mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-08-18 10:48:53 +00:00
Port the #4504 retention semantics (#4452 duplicate-execution fix) into the hexagonal dispatch path. Once launch() returns -- or raises without being able to say whether a run started -- a live run may exist, so bookkeeping failures must not release the task's single active slot: - The two post-launch writes are best-effort: failures are logged and surfaced on DispatchResult.error while the outcome stays LAUNCHED. - New LaunchIndeterminateError expresses main's launch_succeeded-before- unpack semantics at the port boundary: the adapter raises it when the side effect may have happened but the identity is unknown, and the service retains the slot with run_id=None. - LaunchFailedError is narrowed to "the adapter is CERTAIN no run started", since that path releases the slot. Regression tests ported from tests/test_scheduled_task_service.py. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
86 lines
3.0 KiB
Python
86 lines
3.0 KiB
Python
"""The known errors of the schedule context.
|
|
|
|
One family under one base class, so the primary adapter can map the whole
|
|
family onto protocol codes in a single table. Class names keep the PEP 8
|
|
``Error`` suffix; the module is named ``exceptions`` after the AWS
|
|
hexagonal guidance's domain folder of the same name.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
class ScheduleError(Exception):
|
|
"""Base error for the schedule domain."""
|
|
|
|
|
|
class InvalidScheduleError(ScheduleError):
|
|
"""Timezone, cron expression, or run_at is not usable."""
|
|
|
|
|
|
class InvalidContextModeError(ScheduleError):
|
|
"""context_mode is unknown, or reuse_thread is missing its thread_id."""
|
|
|
|
|
|
class TaskNotFoundError(ScheduleError):
|
|
"""The task does not exist or does not belong to the user."""
|
|
|
|
|
|
class TaskNotMutableError(ScheduleError):
|
|
"""The task is currently running and cannot be edited."""
|
|
|
|
|
|
class ThreadNotFoundError(ScheduleError):
|
|
"""reuse_thread points at a thread the user cannot access."""
|
|
|
|
|
|
class CorruptStoredScheduleError(ScheduleError):
|
|
"""A stored task row can no longer be rebuilt into a valid aggregate.
|
|
|
|
Raised by the persistence adapter, never by the aggregate: it means the
|
|
*storage* is damaged, not that a client submitted something invalid --
|
|
which is why it is deliberately absent from the router's status table and
|
|
falls through to the unclassified-500 branch instead of riding
|
|
``InvalidScheduleError``'s 422.
|
|
"""
|
|
|
|
|
|
class ActiveRunConflictError(ScheduleError):
|
|
"""The task already holds its single active run slot.
|
|
|
|
Raised by the run repository when the partial unique index
|
|
``uq_scheduled_task_run_active`` rejects a second active row. Moved here
|
|
from ``persistence/scheduled_task_runs/sql.py`` (was
|
|
``ActiveScheduledRunConflict``) so the domain owns its own vocabulary.
|
|
"""
|
|
|
|
|
|
class ThreadBusyError(ScheduleError):
|
|
"""The execution thread already has an in-flight run.
|
|
|
|
Translated by the RunLauncher adapter from ConflictError / HTTP 409.
|
|
This is what removes `from fastapi import HTTPException` from the
|
|
orchestration layer.
|
|
"""
|
|
|
|
|
|
class LaunchFailedError(ScheduleError):
|
|
"""The launch definitely did not start a run.
|
|
|
|
The adapter may raise this only when it is CERTAIN no run exists -- the
|
|
service releases the task's active slot on this path, so raising it after
|
|
the launch side effect may have happened reopens the #4452 duplicate
|
|
execution. When in doubt, raise LaunchIndeterminateError instead.
|
|
"""
|
|
|
|
|
|
class LaunchIndeterminateError(ScheduleError):
|
|
"""The launch side effect may have happened, but its identity is unknown.
|
|
|
|
Raised by the RunLauncher adapter when the launch call did not fail
|
|
cleanly -- the response could not be decoded, the connection dropped after
|
|
the request was sent, and so on. The service treats this as launched with
|
|
an unknown run id: the execution record stays active so the task's single
|
|
active slot remains held (#4452 / #4504), and reconciliation later settles
|
|
what actually happened.
|
|
"""
|