feat(workflow): orchestrate resumable dataflow handoffs

This commit is contained in:
2026-07-30 03:11:56 +02:00
parent a1654e70cf
commit a6e0e89829
18 changed files with 3938 additions and 27 deletions
+241
View File
@@ -140,6 +140,11 @@ class WorkflowDefinition(Base, TimestampMixin):
cascade="all, delete-orphan",
order_by="WorkflowDefinitionRevision.revision",
)
instances: Mapped[list["WorkflowInstance"]] = relationship(
back_populates="definition",
cascade="all, delete-orphan",
order_by="WorkflowInstance.created_at",
)
class WorkflowDefinitionRevision(Base, TimestampMixin):
@@ -188,8 +193,244 @@ class WorkflowDefinitionRevision(Base, TimestampMixin):
definition: Mapped[WorkflowDefinition] = relationship(back_populates="revisions")
class WorkflowInstance(Base, TimestampMixin):
__tablename__ = "workflow_instances"
__table_args__ = (
UniqueConstraint(
"tenant_id",
"definition_id",
"idempotency_key",
name="uq_workflow_instance_idempotency",
),
Index(
"ix_workflow_instances_tenant_status",
"tenant_id",
"status",
),
Index(
"ix_workflow_instances_reconcile",
"status",
"updated_at",
),
)
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_uuid)
tenant_id: Mapped[str] = mapped_column(String(36), nullable=False, index=True)
definition_id: Mapped[str] = mapped_column(
ForeignKey("workflow_definitions.id", ondelete="CASCADE"),
nullable=False,
index=True,
)
definition_revision_id: Mapped[str] = mapped_column(
ForeignKey("workflow_definition_revisions.id", ondelete="RESTRICT"),
nullable=False,
index=True,
)
status: Mapped[str] = mapped_column(
String(30),
default="running",
nullable=False,
index=True,
)
idempotency_key: Mapped[str] = mapped_column(
String(255),
nullable=False,
index=True,
)
correlation_id: Mapped[str | None] = mapped_column(
String(128),
nullable=True,
index=True,
)
current_step_id: Mapped[str | None] = mapped_column(
String(36),
nullable=True,
index=True,
)
input_: Mapped[dict[str, Any]] = mapped_column(
"input",
JSON,
default=dict,
nullable=False,
)
context_: Mapped[dict[str, Any]] = mapped_column(
"context",
JSON,
default=dict,
nullable=False,
)
output_: Mapped[dict[str, Any]] = mapped_column(
"output",
JSON,
default=dict,
nullable=False,
)
authorization_: Mapped[dict[str, Any]] = mapped_column(
"authorization",
JSON,
default=dict,
nullable=False,
)
started_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True),
nullable=False,
)
finished_at: Mapped[datetime | None] = mapped_column(
DateTime(timezone=True),
nullable=True,
)
cancellation_requested_at: Mapped[datetime | None] = mapped_column(
DateTime(timezone=True),
nullable=True,
)
error: Mapped[str | None] = mapped_column(Text, nullable=True)
created_by: Mapped[str | None] = mapped_column(
String(255),
nullable=True,
index=True,
)
definition: Mapped[WorkflowDefinition] = relationship(
back_populates="instances"
)
steps: Mapped[list["WorkflowInstanceStep"]] = relationship(
back_populates="instance",
cascade="all, delete-orphan",
order_by="WorkflowInstanceStep.sequence",
)
events: Mapped[list["WorkflowInstanceEvent"]] = relationship(
back_populates="instance",
cascade="all, delete-orphan",
order_by="WorkflowInstanceEvent.sequence",
)
class WorkflowInstanceStep(Base, TimestampMixin):
__tablename__ = "workflow_instance_steps"
__table_args__ = (
UniqueConstraint(
"instance_id",
"sequence",
name="uq_workflow_instance_step_sequence",
),
Index(
"ix_workflow_instance_steps_tenant_status",
"tenant_id",
"status",
),
)
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_uuid)
tenant_id: Mapped[str] = mapped_column(String(36), nullable=False, index=True)
instance_id: Mapped[str] = mapped_column(
ForeignKey("workflow_instances.id", ondelete="CASCADE"),
nullable=False,
index=True,
)
sequence: Mapped[int] = mapped_column(Integer, nullable=False)
node_id: Mapped[str] = mapped_column(String(120), nullable=False, index=True)
node_type: Mapped[str] = mapped_column(String(120), nullable=False, index=True)
status: Mapped[str] = mapped_column(
String(30),
nullable=False,
index=True,
)
attempt: Mapped[int] = mapped_column(Integer, default=1, nullable=False)
idempotency_key: Mapped[str] = mapped_column(
String(255),
nullable=False,
)
input_: Mapped[dict[str, Any]] = mapped_column(
"input",
JSON,
default=dict,
nullable=False,
)
output_: Mapped[dict[str, Any]] = mapped_column(
"output",
JSON,
default=dict,
nullable=False,
)
handoff: Mapped[dict[str, Any]] = mapped_column(
JSON,
default=dict,
nullable=False,
)
external_ref: Mapped[str | None] = mapped_column(
String(500),
nullable=True,
index=True,
)
started_at: Mapped[datetime | None] = mapped_column(
DateTime(timezone=True),
nullable=True,
)
finished_at: Mapped[datetime | None] = mapped_column(
DateTime(timezone=True),
nullable=True,
)
error: Mapped[str | None] = mapped_column(Text, nullable=True)
completed_by: Mapped[str | None] = mapped_column(
String(255),
nullable=True,
)
instance: Mapped[WorkflowInstance] = relationship(back_populates="steps")
class WorkflowInstanceEvent(Base):
__tablename__ = "workflow_instance_events"
__table_args__ = (
UniqueConstraint(
"instance_id",
"sequence",
name="uq_workflow_instance_event_sequence",
),
Index(
"ix_workflow_instance_events_tenant_created",
"tenant_id",
"created_at",
),
)
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_uuid)
tenant_id: Mapped[str] = mapped_column(String(36), nullable=False, index=True)
instance_id: Mapped[str] = mapped_column(
ForeignKey("workflow_instances.id", ondelete="CASCADE"),
nullable=False,
index=True,
)
step_id: Mapped[str | None] = mapped_column(
String(36),
nullable=True,
index=True,
)
sequence: Mapped[int] = mapped_column(Integer, nullable=False)
kind: Mapped[str] = mapped_column(String(120), nullable=False, index=True)
actor_id: Mapped[str | None] = mapped_column(
String(255),
nullable=True,
index=True,
)
payload: Mapped[dict[str, Any]] = mapped_column(
JSON,
default=dict,
nullable=False,
)
created_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True),
nullable=False,
)
instance: Mapped[WorkflowInstance] = relationship(back_populates="events")
__all__ = [
"WorkflowDefinition",
"WorkflowDefinitionRevision",
"WorkflowInstance",
"WorkflowInstanceEvent",
"WorkflowInstanceStep",
"new_uuid",
]