gabriel / musehub public
musehub_jobs_models.py python
67 lines 2.8 KB
Raw
sha256:1ccb8409daa5aabe577bd26d11b56ed12f3376d64011d0e75a247e81211a66ee docs(mwp4/phase5): tick Phase 5 checkboxes, close musehub#109 Sonnet 4.6 20 days ago
1 """ORM models for the background job queue.
2
3 Tables:
4 - musehub_background_jobs: Durable job queue — web process enqueues, worker process executes
5 """
6
7 from __future__ import annotations
8
9 from datetime import datetime, timezone
10
11 from sqlalchemy import DateTime, ForeignKey, Index, Integer, String, Text
12 from sqlalchemy.orm import Mapped, mapped_column
13 from sqlalchemy.dialects.postgresql import JSONB
14
15 from musehub.db.database import Base
16 from musehub.types.json_types import JSONObject, JSONValue # JSONValue needed for ForwardRef resolution in Mapped[]
17
18
19 def _utc_now() -> datetime:
20 return datetime.now(tz=timezone.utc)
21
22
23 class MusehubBackgroundJob(Base):
24 """A durable background job enqueued by the web process and processed by the worker.
25
26 The web process (uvicorn) never executes job logic directly — it only
27 inserts a row here. A separate worker process polls this table, claims
28 rows with ``FOR UPDATE SKIP LOCKED``, and runs the work outside the web
29 server's memory space so a crash in the worker cannot affect request handling.
30
31 Supported job_type values:
32 ``intel.code`` — rebuild code intelligence for a repo.
33 payload: {"head": "<commit_id>"}
34 ``intel.structural`` — compute cross-domain structural intelligence.
35 payload: {"head": "<commit_id>"}
36 ``gc`` — prune commits and snapshots unreachable from any branch.
37 payload: {}
38
39 Status lifecycle:
40 pending → running → done
41 → failed (attempt < max_attempts)
42 └→ pending (retried by worker after transient failure)
43 """
44
45 __tablename__ = "musehub_background_jobs"
46 __table_args__ = (
47 Index("ix_musehub_background_jobs_status_created", "status", "created_at"),
48 )
49
50 job_id: Mapped[str] = mapped_column(String(128), primary_key=True)
51 repo_id: Mapped[str] = mapped_column(
52 String(128),
53 ForeignKey("musehub_repos.repo_id", ondelete="CASCADE"),
54 nullable=False,
55 index=True,
56 )
57 job_type: Mapped[str] = mapped_column(String(64), nullable=False)
58 payload: Mapped[JSONObject] = mapped_column(JSONB, nullable=False, default=dict)
59 status: Mapped[str] = mapped_column(String(16), nullable=False, default="pending", server_default="pending", index=True)
60 created_at: Mapped[datetime] = mapped_column(
61 DateTime(timezone=True), nullable=False, default=_utc_now
62 )
63 claimed_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
64 done_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
65 attempt: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
66 error: Mapped[str | None] = mapped_column(Text, nullable=True)
67 quarantine_reason: Mapped[str | None] = mapped_column(Text, nullable=True)
File History 2 commits
sha256:1ccb8409daa5aabe577bd26d11b56ed12f3376d64011d0e75a247e81211a66ee docs(mwp4/phase5): tick Phase 5 checkboxes, close musehub#109 Sonnet 4.6 20 days ago
sha256:2c523da45351334b5c4dbefed4dc3dd553b3faa8737a4e6caf301e5dc82141be test(mwp4): Phase 0 RED reproduction tests for RC-4 ordering race Sonnet 4.6 20 days ago