Commit Graph

6 Commits

Author SHA1 Message Date
34aa70cbd9 feat(workflows): TaskExecutorWorkflow stub + wire worker — T19/T20
activities.py — persist_task_instance (new):
  Idempotent INSERT ... ON CONFLICT (id) DO NOTHING on task_instances.
  task_id passed in from workflow (derived from workflow_id via uuid5).
  Registered on task-execution-tq.

workflows.py — TaskExecutorWorkflow (T19):
  Derives stable task_id = uuid5(NAMESPACE_URL, workflow_id).
  Calls persist_task_instance → status=done, returns immediately.
  Real execution logic to replace stub in a later workstream.

worker.py — T20:
  Registers persist_task_instance on task-execution-tq Worker.
  Both queues fully wired: orchestrator-tq and task-execution-tq.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 22:30:50 +00:00
da7de6ea3b feat(workflows): implement RunActivityWorkflow — T18
workflows.py — RunActivityWorkflow:
  1. load_activity_definition(activity_id)
  2. resolve_context(context_sources)
  3. evaluate_templates (pure, called in-workflow)
  4. log_run({run_id, ...}) — run_id = uuid5(NAMESPACE_URL, activity_id:trigger_key)
  5. start_child_workflow(TaskExecutorWorkflow, ...) per task spec
     ABANDON parent-close policy (fire-and-forget)
  Returns {"run_id": str, "tasks_spawned": int}

activities.py — log_run updated:
  - now accepts run_id in run_payload (deterministic, passed from workflow)
  - uses pg INSERT ... ON CONFLICT (run_id) DO NOTHING for idempotency

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 22:25:19 +00:00
068780224e feat(activities): implement log_run — T17
Inserts an ActivityRun row via the shared session factory.
Accepts run_payload dict with activity_id, scheduled_for (ISO-8601 or
None), context_snapshot, tasks_spawned, version_used.
Returns run_id as a str UUID.
fired_at is set server-side to now(UTC).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 22:19:12 +00:00
bac3efee89 feat(activities): resolve_context stub + evaluate_templates — T15/T16
activities.py — resolve_context (T15):
  - dispatches on source.type: 'static' returns config["value"]
  - 'http_get' / 'db_query' raise ApplicationError(non_retryable=True)
  - unknown types raise ApplicationError(non_retryable=True)

template_engine.py — evaluate_templates (T16, pure function):
  - evaluates optional condition expressions against context snapshot
    (restricted eval, no builtins)
  - interpolates {context.<name>.<key>} placeholders via str.format_map
  - returns list[{task_type, params}] with falsy-condition rows omitted

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 22:06:09 +00:00
5e4dc6c946 feat(activities): implement load_activity_definition — T14
activities.py:
- init_session_factory(url): module-level async_sessionmaker init,
  called once from worker.py before workers start
- load_activity_definition(activity_id): queries activity_definitions
  by UUID, returns JSON-serialisable dict; raises ApplicationError
  (non_retryable=True) if row not found

worker.py:
- reads ACTCORE_DB_URL at startup, fails fast if missing
- calls init_session_factory() before connecting to Temporal

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 22:02:15 +00:00
21edc313db feat(worker): scaffold activities, workflows, worker entrypoint — T13
src/activity_core/activities.py:
  - load_activity_definition, resolve_context, log_run — @activity.defn
    stubs (raise NotImplementedError, bodies in T14–T17)

src/activity_core/workflows.py:
  - RunActivityWorkflow (orchestrator-tq) — @workflow.defn stub (T18)
  - TaskExecutorWorkflow (task-execution-tq) — @workflow.defn stub (T19)

src/activity_core/worker.py:
  - Connects to Temporal via TEMPORAL_HOST / TEMPORAL_NAMESPACE env vars
  - Spawns two Workers: orchestrator-tq and task-execution-tq
  - Runs until cancelled (python -m activity_core.worker)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 21:57:56 +00:00