activity-core/migrations/versions/0007_create_ops_runs.py
tegwick 15eb3a2066
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 2s
Build and Publish Container Image / build-and-push (push) Successful in 52s
Implement ACTIVITY-WP-0026 ops_run claim queue (T01–T06).
Add durable claimable ops_runs table, emit dual-write on TaskSpec, REST
claim/lease/complete/fail API, ops status visibility, and consumer docs
aligned with ACT-ADR-005. T07 railiance rollout remains deploy-side.
2026-08-03 19:22:50 +02:00

95 lines
3.2 KiB
Python

"""create_ops_runs
Revision ID: 0007
Revises: 0006
Create Date: 2026-08-03
ACTIVITY-WP-0026 / ACT-ADR-005 — claimable ops run queue.
"""
from typing import Sequence, Union
import sqlalchemy as sa
from alembic import op
from sqlalchemy.dialects import postgresql
revision: str = "0007"
down_revision: Union[str, Sequence[str], None] = "0006"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
op.create_table(
"ops_runs",
sa.Column(
"id",
sa.UUID(),
nullable=False,
server_default=sa.text("gen_random_uuid()"),
),
sa.Column("activity_definition_id", sa.UUID(), nullable=False),
sa.Column("idempotency_key", sa.Text(), nullable=False),
sa.Column("target_repo", sa.Text(), nullable=True),
sa.Column("title", sa.Text(), nullable=False),
sa.Column("description", sa.Text(), nullable=False, server_default=""),
sa.Column(
"labels",
postgresql.JSONB(astext_type=sa.Text()),
nullable=False,
server_default=sa.text("'[]'::jsonb"),
),
sa.Column("priority", sa.Text(), nullable=False, server_default="medium"),
sa.Column("state", sa.Text(), nullable=False, server_default="open"),
sa.Column("claim_owner", sa.Text(), nullable=True),
sa.Column("lease_until", sa.DateTime(timezone=True), nullable=True),
sa.Column("attempt", sa.Integer(), nullable=False, server_default="0"),
sa.Column("source_type", sa.Text(), nullable=False),
sa.Column("source_id", sa.Text(), nullable=False),
sa.Column("triggering_event_id", sa.Text(), nullable=False),
sa.Column("approach_hint", sa.Text(), nullable=True),
sa.Column(
"result",
postgresql.JSONB(astext_type=sa.Text()),
nullable=False,
server_default=sa.text("'{}'::jsonb"),
),
sa.Column(
"created_at",
sa.DateTime(timezone=True),
nullable=False,
server_default=sa.text("now()"),
),
sa.Column(
"updated_at",
sa.DateTime(timezone=True),
nullable=False,
server_default=sa.text("now()"),
),
sa.ForeignKeyConstraint(
["activity_definition_id"],
["activity_definitions.id"],
ondelete="RESTRICT",
),
sa.PrimaryKeyConstraint("id"),
sa.UniqueConstraint("idempotency_key", name="uq_ops_runs_idempotency_key"),
)
op.create_index("idx_ops_runs_state", "ops_runs", ["state"])
op.create_index("idx_ops_runs_lease", "ops_runs", ["lease_until"])
op.create_index(
"idx_ops_runs_activity",
"ops_runs",
["activity_definition_id"],
)
op.create_index(
"idx_ops_runs_trigger",
"ops_runs",
["triggering_event_id"],
)
def downgrade() -> None:
op.drop_index("idx_ops_runs_trigger", table_name="ops_runs")
op.drop_index("idx_ops_runs_activity", table_name="ops_runs")
op.drop_index("idx_ops_runs_lease", table_name="ops_runs")
op.drop_index("idx_ops_runs_state", table_name="ops_runs")
op.drop_table("ops_runs")