dag.py 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. from __future__ import annotations
  2. from dataclasses import dataclass
  3. @dataclass(frozen=True)
  4. class StepDefinition:
  5. key: str
  6. order: int
  7. dependencies: tuple[str, ...]
  8. timeout_seconds: int
  9. max_attempts: int = 1
  10. retryable: bool = False
  11. critical: bool = True
  12. _RAW_STEPS: tuple[tuple[str, int, bool], ...] = (
  13. ("global_tree_sync", 3600, True),
  14. ("demand_pool_source_sync", 3600, True),
  15. ("demand_classify", 21600, False),
  16. ("demand_belong_rel_sync", 3600, True),
  17. ("real_metrics_sync", 3600, True),
  18. ("popularity_stats", 3600, True),
  19. ("category_tree_weight", 3600, True),
  20. ("source_video_sync", 7200, True),
  21. ("demand_grade", 21600, False),
  22. ("demand_expand", 21600, False),
  23. ("video_discovery", 21600, False),
  24. ("aigc_write_record", 1800, True),
  25. )
  26. def _build_steps() -> tuple[StepDefinition, ...]:
  27. result: list[StepDefinition] = []
  28. previous: str | None = None
  29. for order, (key, timeout_seconds, retryable) in enumerate(_RAW_STEPS, start=1):
  30. result.append(
  31. StepDefinition(
  32. key=key,
  33. order=order,
  34. dependencies=(previous,) if previous else (),
  35. timeout_seconds=timeout_seconds,
  36. max_attempts=2 if retryable else 1,
  37. retryable=retryable,
  38. )
  39. )
  40. previous = key
  41. return tuple(result)
  42. PIPELINE_STEPS = _build_steps()
  43. STEP_BY_KEY = {step.key: step for step in PIPELINE_STEPS}
  44. def validate_dag() -> None:
  45. seen: set[str] = set()
  46. for step in PIPELINE_STEPS:
  47. if step.key in seen:
  48. raise ValueError(f"Duplicate step key: {step.key}")
  49. missing = set(step.dependencies) - seen
  50. if missing:
  51. raise ValueError(f"Step {step.key} has unresolved dependencies: {sorted(missing)}")
  52. seen.add(step.key)
  53. validate_dag()