pipeline_step_run.py 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. from __future__ import annotations
  2. from datetime import datetime
  3. from typing import Any
  4. from sqlalchemy import (
  5. Boolean,
  6. DateTime,
  7. ForeignKey,
  8. Index,
  9. Integer,
  10. JSON,
  11. String,
  12. Text,
  13. UniqueConstraint,
  14. func,
  15. )
  16. from sqlalchemy.orm import Mapped, mapped_column
  17. from supply_infra.db.base import Base
  18. class PipelineStepRun(Base):
  19. """One durable attempt of a pipeline step."""
  20. __tablename__ = "pipeline_step_run"
  21. __table_args__ = (
  22. UniqueConstraint(
  23. "run_id",
  24. "step_key",
  25. "attempt",
  26. name="uk_pipeline_step_run_attempt",
  27. ),
  28. Index("idx_pipeline_step_claim", "status", "next_retry_at", "step_order"),
  29. Index("idx_pipeline_step_run", "run_id", "step_order", "attempt"),
  30. Index("idx_pipeline_step_lease", "status", "lease_until"),
  31. )
  32. step_run_id: Mapped[str] = mapped_column(String(36), primary_key=True)
  33. run_id: Mapped[str] = mapped_column(
  34. String(36),
  35. ForeignKey("pipeline_run.run_id", ondelete="CASCADE"),
  36. nullable=False,
  37. )
  38. step_key: Mapped[str] = mapped_column(String(64), nullable=False)
  39. step_order: Mapped[int] = mapped_column(Integer, nullable=False)
  40. attempt: Mapped[int] = mapped_column(Integer, nullable=False, default=1)
  41. status: Mapped[str] = mapped_column(String(32), nullable=False, default="pending")
  42. critical: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True)
  43. dependency_snapshot_json: Mapped[list[str]] = mapped_column(
  44. JSON,
  45. nullable=False,
  46. default=list,
  47. )
  48. input_snapshot_json: Mapped[dict[str, Any]] = mapped_column(
  49. JSON,
  50. nullable=False,
  51. default=dict,
  52. )
  53. timeout_seconds: Mapped[int] = mapped_column(Integer, nullable=False)
  54. max_attempts: Mapped[int] = mapped_column(Integer, nullable=False, default=1)
  55. retryable: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
  56. next_retry_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
  57. started_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
  58. finished_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
  59. heartbeat_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
  60. lease_owner: Mapped[str | None] = mapped_column(String(191), nullable=True)
  61. lease_until: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
  62. exit_code: Mapped[int | None] = mapped_column(Integer, nullable=True)
  63. result_summary_json: Mapped[dict[str, Any] | None] = mapped_column(JSON, nullable=True)
  64. error_code: Mapped[str | None] = mapped_column(String(64), nullable=True)
  65. error_message: Mapped[str | None] = mapped_column(Text, nullable=True)
  66. log_uri: Mapped[str | None] = mapped_column(String(1024), nullable=True)
  67. created_at: Mapped[datetime] = mapped_column(
  68. DateTime,
  69. nullable=False,
  70. server_default=func.now(),
  71. )
  72. updated_at: Mapped[datetime] = mapped_column(
  73. DateTime,
  74. nullable=False,
  75. server_default=func.now(),
  76. onupdate=func.now(),
  77. )