mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-08-01 19:06:01 +00:00
refactor(schedule): promote the domain errors to exceptions.py
Move model/errors.py up one level to domain/schedule/exceptions.py, a sibling of the model, matching the AWS domain layout the spec mandates (exceptions/ is its own member of the domain folder, not part of the model) and the feedback reference implementation. Class names keep the PEP 8 Error suffix. Pure move -- the nine classes are AST-identical to the originals; imports across the domain, adapters, router, and tests now take errors from deerflow.domain.schedule.exceptions.
This commit is contained in:
parent
a7c1a34b28
commit
f88c8e61bc
@ -25,7 +25,7 @@ from typing import Any
|
||||
|
||||
from fastapi import HTTPException
|
||||
|
||||
from deerflow.domain.schedule.model import LaunchFailedError, ThreadBusyError
|
||||
from deerflow.domain.schedule.exceptions import LaunchFailedError, ThreadBusyError
|
||||
from deerflow.domain.schedule.ports import LaunchedRun, RunLauncher
|
||||
from deerflow.runtime import ConflictError
|
||||
|
||||
|
||||
@ -19,14 +19,8 @@ from sqlalchemy import func, select
|
||||
from sqlalchemy.exc import IntegrityError
|
||||
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker
|
||||
|
||||
from deerflow.domain.schedule.model import (
|
||||
ACTIVE_RUN_STATUSES,
|
||||
TERMINAL_RUN_STATUSES,
|
||||
ActiveRunConflictError,
|
||||
RunStatus,
|
||||
ScheduledRun,
|
||||
TriggerKind,
|
||||
)
|
||||
from deerflow.domain.schedule.exceptions import ActiveRunConflictError
|
||||
from deerflow.domain.schedule.model import ACTIVE_RUN_STATUSES, TERMINAL_RUN_STATUSES, RunStatus, ScheduledRun, TriggerKind
|
||||
from deerflow.domain.schedule.ports import ScheduledRunRepository
|
||||
|
||||
# Transitional: the ORM row stays in the harness until engine, models, and
|
||||
|
||||
@ -26,15 +26,8 @@ from datetime import UTC, datetime, timedelta
|
||||
from sqlalchemy import and_, or_, select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker
|
||||
|
||||
from deerflow.domain.schedule.model import (
|
||||
TERMINAL_TASK_STATUSES,
|
||||
ContextMode,
|
||||
InvalidScheduleError,
|
||||
ScheduledTask,
|
||||
ScheduleSpec,
|
||||
ScheduleType,
|
||||
TaskStatus,
|
||||
)
|
||||
from deerflow.domain.schedule.exceptions import InvalidScheduleError
|
||||
from deerflow.domain.schedule.model import TERMINAL_TASK_STATUSES, ContextMode, ScheduledTask, ScheduleSpec, ScheduleType, TaskStatus
|
||||
from deerflow.domain.schedule.ports import ScheduledTaskRepository
|
||||
|
||||
# Transitional: the ORM row stays in the harness until engine, models, and
|
||||
|
||||
@ -30,8 +30,7 @@ from app.gateway.routers.schedule.models import (
|
||||
ScheduledTaskUpdateRequest,
|
||||
TriggerResponse,
|
||||
)
|
||||
from deerflow.domain.schedule.model import (
|
||||
DispatchOutcome,
|
||||
from deerflow.domain.schedule.exceptions import (
|
||||
InvalidContextModeError,
|
||||
InvalidScheduleError,
|
||||
ScheduleError,
|
||||
@ -39,6 +38,7 @@ from deerflow.domain.schedule.model import (
|
||||
TaskNotMutableError,
|
||||
ThreadNotFoundError,
|
||||
)
|
||||
from deerflow.domain.schedule.model import DispatchOutcome
|
||||
from deerflow.domain.schedule.service import ContextChange
|
||||
|
||||
router = APIRouter(prefix="/api", tags=["scheduled-tasks"])
|
||||
|
||||
@ -7,28 +7,30 @@ tests, not everyday call-site symbols.
|
||||
`ScheduleService` is not exported yet: the application service has not landed.
|
||||
"""
|
||||
|
||||
from deerflow.domain.schedule.exceptions import (
|
||||
ActiveRunConflictError,
|
||||
InvalidContextModeError,
|
||||
InvalidScheduleError,
|
||||
LaunchFailedError,
|
||||
ScheduleError,
|
||||
TaskNotFoundError,
|
||||
TaskNotMutableError,
|
||||
ThreadBusyError,
|
||||
ThreadNotFoundError,
|
||||
)
|
||||
from deerflow.domain.schedule.model import (
|
||||
ACTIVE_RUN_STATUSES,
|
||||
TERMINAL_RUN_STATUSES,
|
||||
TERMINAL_TASK_STATUSES,
|
||||
ActiveRunConflictError,
|
||||
ContextMode,
|
||||
DispatchOutcome,
|
||||
InvalidContextModeError,
|
||||
InvalidScheduleError,
|
||||
LaunchFailedError,
|
||||
RunStatus,
|
||||
ScheduledRun,
|
||||
ScheduledTask,
|
||||
ScheduleError,
|
||||
SchedulePolicy,
|
||||
ScheduleSpec,
|
||||
ScheduleType,
|
||||
TaskNotFoundError,
|
||||
TaskNotMutableError,
|
||||
TaskStatus,
|
||||
ThreadBusyError,
|
||||
ThreadNotFoundError,
|
||||
TriggerKind,
|
||||
)
|
||||
|
||||
|
||||
@ -1,3 +1,11 @@
|
||||
"""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
|
||||
|
||||
|
||||
@ -8,8 +8,11 @@ what a single `model.py` would have.
|
||||
|
||||
The re-exports below are ordered alphabetically because ruff's isort rule
|
||||
owns that block; alphabetical happens to satisfy the real dependency order
|
||||
too (enums and errors depend on nothing, run depends on enums, spec depends
|
||||
on enums and errors, task depends on all three), so it needs no override.
|
||||
too (enums depend on nothing, run depends on enums, spec depends on enums,
|
||||
task depends on both), so it needs no override. The domain errors are not
|
||||
re-exported here: they live one level up in
|
||||
`deerflow.domain.schedule.exceptions`, a sibling of the model per the AWS
|
||||
domain layout, and are imported from there.
|
||||
|
||||
What actually keeps the package acyclic is a rule isort cannot express:
|
||||
**a submodule imports its siblings directly, never this package.** Reaching
|
||||
@ -27,17 +30,6 @@ from deerflow.domain.schedule.model.enums import (
|
||||
TaskStatus,
|
||||
TriggerKind,
|
||||
)
|
||||
from deerflow.domain.schedule.model.errors import (
|
||||
ActiveRunConflictError,
|
||||
InvalidContextModeError,
|
||||
InvalidScheduleError,
|
||||
LaunchFailedError,
|
||||
ScheduleError,
|
||||
TaskNotFoundError,
|
||||
TaskNotMutableError,
|
||||
ThreadBusyError,
|
||||
ThreadNotFoundError,
|
||||
)
|
||||
from deerflow.domain.schedule.model.run import ACTIVE_RUN_STATUSES, TERMINAL_RUN_STATUSES, ScheduledRun
|
||||
from deerflow.domain.schedule.model.spec import SchedulePolicy, ScheduleSpec
|
||||
from deerflow.domain.schedule.model.task import TERMINAL_TASK_STATUSES, ScheduledTask
|
||||
@ -46,23 +38,14 @@ __all__ = [
|
||||
"ACTIVE_RUN_STATUSES",
|
||||
"TERMINAL_RUN_STATUSES",
|
||||
"TERMINAL_TASK_STATUSES",
|
||||
"ActiveRunConflictError",
|
||||
"ContextMode",
|
||||
"DispatchOutcome",
|
||||
"InvalidContextModeError",
|
||||
"InvalidScheduleError",
|
||||
"LaunchFailedError",
|
||||
"RunStatus",
|
||||
"ScheduleError",
|
||||
"SchedulePolicy",
|
||||
"ScheduleSpec",
|
||||
"ScheduleType",
|
||||
"ScheduledRun",
|
||||
"ScheduledTask",
|
||||
"TaskNotFoundError",
|
||||
"TaskNotMutableError",
|
||||
"TaskStatus",
|
||||
"ThreadBusyError",
|
||||
"ThreadNotFoundError",
|
||||
"TriggerKind",
|
||||
]
|
||||
|
||||
@ -6,8 +6,8 @@ from zoneinfo import ZoneInfo, ZoneInfoNotFoundError
|
||||
|
||||
from croniter import croniter
|
||||
|
||||
from deerflow.domain.schedule.exceptions import InvalidScheduleError
|
||||
from deerflow.domain.schedule.model.enums import ScheduleType
|
||||
from deerflow.domain.schedule.model.errors import InvalidScheduleError
|
||||
|
||||
CRON_FIELD_COUNT = 5
|
||||
|
||||
|
||||
@ -4,8 +4,8 @@ import uuid
|
||||
from dataclasses import dataclass, field, replace
|
||||
from datetime import UTC, datetime
|
||||
|
||||
from deerflow.domain.schedule.exceptions import InvalidContextModeError, TaskNotMutableError
|
||||
from deerflow.domain.schedule.model.enums import ContextMode, RunStatus, ScheduleType, TaskStatus, TriggerKind
|
||||
from deerflow.domain.schedule.model.errors import InvalidContextModeError, TaskNotMutableError
|
||||
from deerflow.domain.schedule.model.spec import SchedulePolicy, ScheduleSpec
|
||||
|
||||
TERMINAL_TASK_STATUSES = frozenset({TaskStatus.COMPLETED, TaskStatus.FAILED, TaskStatus.CANCELLED})
|
||||
|
||||
@ -17,20 +17,22 @@ from __future__ import annotations
|
||||
from dataclasses import dataclass, replace
|
||||
from datetime import datetime
|
||||
|
||||
from deerflow.domain.schedule.model import (
|
||||
from deerflow.domain.schedule.exceptions import (
|
||||
ActiveRunConflictError,
|
||||
LaunchFailedError,
|
||||
TaskNotFoundError,
|
||||
ThreadBusyError,
|
||||
ThreadNotFoundError,
|
||||
)
|
||||
from deerflow.domain.schedule.model import (
|
||||
ContextMode,
|
||||
DispatchOutcome,
|
||||
LaunchFailedError,
|
||||
RunStatus,
|
||||
ScheduledRun,
|
||||
ScheduledTask,
|
||||
SchedulePolicy,
|
||||
ScheduleSpec,
|
||||
ScheduleType,
|
||||
TaskNotFoundError,
|
||||
ThreadBusyError,
|
||||
ThreadNotFoundError,
|
||||
TriggerKind,
|
||||
)
|
||||
from deerflow.domain.schedule.ports import (
|
||||
|
||||
@ -17,11 +17,11 @@ from __future__ import annotations
|
||||
from dataclasses import dataclass, field, replace
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from deerflow.domain.schedule.exceptions import ActiveRunConflictError
|
||||
from deerflow.domain.schedule.model import (
|
||||
ACTIVE_RUN_STATUSES,
|
||||
TERMINAL_RUN_STATUSES,
|
||||
TERMINAL_TASK_STATUSES,
|
||||
ActiveRunConflictError,
|
||||
RunStatus,
|
||||
ScheduledRun,
|
||||
ScheduledTask,
|
||||
|
||||
@ -19,17 +19,15 @@ from datetime import UTC, datetime, timedelta
|
||||
|
||||
import pytest
|
||||
|
||||
from deerflow.domain.schedule.exceptions import InvalidContextModeError, InvalidScheduleError, TaskNotMutableError
|
||||
from deerflow.domain.schedule.model import (
|
||||
ContextMode,
|
||||
InvalidContextModeError,
|
||||
InvalidScheduleError,
|
||||
RunStatus,
|
||||
ScheduledRun,
|
||||
ScheduledTask,
|
||||
SchedulePolicy,
|
||||
ScheduleSpec,
|
||||
ScheduleType,
|
||||
TaskNotMutableError,
|
||||
TaskStatus,
|
||||
TriggerKind,
|
||||
)
|
||||
|
||||
@ -31,16 +31,8 @@ from schedule_fakes import (
|
||||
from app.adapters.schedule.scheduled_run_repository import SqlScheduledRunRepository
|
||||
from app.adapters.schedule.scheduled_task_repository import SqlScheduledTaskRepository
|
||||
from deerflow.config.database_config import DatabaseConfig
|
||||
from deerflow.domain.schedule.model import (
|
||||
ActiveRunConflictError,
|
||||
ContextMode,
|
||||
RunStatus,
|
||||
ScheduledRun,
|
||||
ScheduledTask,
|
||||
ScheduleSpec,
|
||||
TaskStatus,
|
||||
TriggerKind,
|
||||
)
|
||||
from deerflow.domain.schedule.exceptions import ActiveRunConflictError
|
||||
from deerflow.domain.schedule.model import ContextMode, RunStatus, ScheduledRun, ScheduledTask, ScheduleSpec, TaskStatus, TriggerKind
|
||||
from deerflow.domain.schedule.ports import ScheduledRunRepository, ScheduledTaskRepository
|
||||
from deerflow.persistence.engine import close_engine, get_session_factory, init_engine_from_config
|
||||
|
||||
|
||||
@ -17,15 +17,7 @@ from datetime import UTC, datetime, timedelta, timezone
|
||||
import pytest
|
||||
|
||||
from app.gateway.routers.schedule.models import ScheduledRunResponse, ScheduledTaskResponse
|
||||
from deerflow.domain.schedule.model import (
|
||||
ContextMode,
|
||||
RunStatus,
|
||||
ScheduledRun,
|
||||
ScheduledTask,
|
||||
ScheduleSpec,
|
||||
TaskStatus,
|
||||
TriggerKind,
|
||||
)
|
||||
from deerflow.domain.schedule.model import ContextMode, RunStatus, ScheduledRun, ScheduledTask, ScheduleSpec, TaskStatus, TriggerKind
|
||||
|
||||
# Exactly the frontend's `ScheduledTask` type (frontend/src/core/scheduled-tasks/types.ts).
|
||||
FRONTEND_TASK_FIELDS = {
|
||||
|
||||
@ -30,15 +30,8 @@ from schedule_fakes import (
|
||||
)
|
||||
|
||||
from app.gateway.routers.schedule import router as router_module
|
||||
from deerflow.domain.schedule.model import (
|
||||
LaunchFailedError,
|
||||
RunStatus,
|
||||
ScheduledRun,
|
||||
SchedulePolicy,
|
||||
TaskStatus,
|
||||
ThreadBusyError,
|
||||
TriggerKind,
|
||||
)
|
||||
from deerflow.domain.schedule.exceptions import LaunchFailedError, ThreadBusyError
|
||||
from deerflow.domain.schedule.model import RunStatus, ScheduledRun, SchedulePolicy, TaskStatus, TriggerKind
|
||||
from deerflow.domain.schedule.service import ScheduleService
|
||||
|
||||
USER = "user-1"
|
||||
@ -528,7 +521,7 @@ class TestRunHistory:
|
||||
|
||||
class TestErrorMapping:
|
||||
def test_every_mapped_error_is_a_schedule_error(self):
|
||||
from deerflow.domain.schedule.model import ScheduleError
|
||||
from deerflow.domain.schedule.exceptions import ScheduleError
|
||||
|
||||
assert all(issubclass(error, ScheduleError) for error in router_module._STATUS_BY_ERROR)
|
||||
|
||||
@ -537,7 +530,7 @@ class TestErrorMapping:
|
||||
"""A new domain error is a new protocol decision. Letting it through
|
||||
surfaces as a 500 that has to be classified, rather than shipping as
|
||||
whatever 4xx happened to be nearest."""
|
||||
from deerflow.domain.schedule.model import ScheduleError
|
||||
from deerflow.domain.schedule.exceptions import ScheduleError
|
||||
|
||||
class NewDomainError(ScheduleError):
|
||||
pass
|
||||
@ -551,7 +544,7 @@ class TestErrorMapping:
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_a_mapped_error_keeps_its_message_as_the_detail(self):
|
||||
from deerflow.domain.schedule.model import TaskNotFoundError
|
||||
from deerflow.domain.schedule.exceptions import TaskNotFoundError
|
||||
|
||||
@router_module._map_domain_errors
|
||||
async def handler():
|
||||
|
||||
@ -26,7 +26,7 @@ import pytest
|
||||
from fastapi import HTTPException
|
||||
|
||||
from app.adapters.schedule.run_launcher import GatewayRunLauncher
|
||||
from deerflow.domain.schedule.model import LaunchFailedError, ThreadBusyError
|
||||
from deerflow.domain.schedule.exceptions import LaunchFailedError, ThreadBusyError
|
||||
from deerflow.domain.schedule.ports import LaunchedRun
|
||||
from deerflow.runtime import ConflictError
|
||||
|
||||
|
||||
@ -23,19 +23,21 @@ from schedule_fakes import (
|
||||
InMemoryScheduledTaskRepository,
|
||||
)
|
||||
|
||||
from deerflow.domain.schedule.exceptions import (
|
||||
InvalidScheduleError,
|
||||
LaunchFailedError,
|
||||
TaskNotFoundError,
|
||||
TaskNotMutableError,
|
||||
ThreadBusyError,
|
||||
ThreadNotFoundError,
|
||||
)
|
||||
from deerflow.domain.schedule.model import (
|
||||
ContextMode,
|
||||
DispatchOutcome,
|
||||
InvalidScheduleError,
|
||||
LaunchFailedError,
|
||||
RunStatus,
|
||||
SchedulePolicy,
|
||||
ScheduleSpec,
|
||||
TaskNotFoundError,
|
||||
TaskNotMutableError,
|
||||
TaskStatus,
|
||||
ThreadBusyError,
|
||||
ThreadNotFoundError,
|
||||
TriggerKind,
|
||||
)
|
||||
from deerflow.domain.schedule.ports import RunOutcome
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user