generated from coulomb/repo-seed
feat(WP-0002): complete Triggers & Ops workstream
Delivers all 12 tasks (T22–T33): Temporal Schedule manager + startup sync, NATS JetStream event router, FastAPI CRUD + manual trigger, Prometheus metrics wiring, custom search-attribute tagging, and operational runbook. Marks workplan status as done. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -15,7 +15,7 @@ import uuid
|
||||
from datetime import timedelta
|
||||
|
||||
from temporalio import workflow
|
||||
from temporalio.common import RetryPolicy
|
||||
from temporalio.common import RetryPolicy, SearchAttributeKey, TypedSearchAttributes, SearchAttributePair
|
||||
|
||||
with workflow.unsafe.imports_passed_through():
|
||||
from activity_core.activities import (
|
||||
@@ -25,6 +25,12 @@ with workflow.unsafe.imports_passed_through():
|
||||
resolve_context,
|
||||
)
|
||||
from activity_core.template_engine import evaluate_templates
|
||||
from activity_core.schedule_manager import SCHEDULED_TRIGGER_KEY
|
||||
|
||||
# T32: Custom search attributes for Temporal visibility (must be registered in Temporal first).
|
||||
# Registration: temporal operator search-attribute create --name ActivityId --type Keyword
|
||||
_ACTIVITY_ID_KEY = SearchAttributeKey.for_keyword("ActivityId")
|
||||
_ACTIVITY_NAME_KEY = SearchAttributeKey.for_keyword("ActivityName")
|
||||
|
||||
_RETRY_POLICY = RetryPolicy(
|
||||
initial_interval=timedelta(seconds=1),
|
||||
@@ -74,6 +80,16 @@ class RunActivityWorkflow:
|
||||
retry_policy=_RETRY_POLICY,
|
||||
)
|
||||
|
||||
# T32: Tag this workflow execution with activity metadata so runs are
|
||||
# filterable in the Temporal UI (requires ActivityId + ActivityName to be
|
||||
# registered as custom search attributes — see docs/runbook.md).
|
||||
workflow.upsert_search_attributes(
|
||||
TypedSearchAttributes([
|
||||
SearchAttributePair(_ACTIVITY_ID_KEY, activity_id),
|
||||
SearchAttributePair(_ACTIVITY_NAME_KEY, defn.get("name", "")),
|
||||
])
|
||||
)
|
||||
|
||||
# ── 2. Resolve context ────────────────────────────────────────────────
|
||||
context_snapshot: dict = await workflow.execute_activity(
|
||||
resolve_context,
|
||||
@@ -89,9 +105,14 @@ class RunActivityWorkflow:
|
||||
|
||||
# ── 4. Log the run ────────────────────────────────────────────────────
|
||||
# run_id is derived deterministically so log_run retries are idempotent.
|
||||
run_id = str(
|
||||
uuid.uuid5(uuid.NAMESPACE_URL, f"{activity_id}:{trigger_key}")
|
||||
)
|
||||
# For schedule-fired runs the trigger_key is the sentinel "scheduled";
|
||||
# each fire has a unique workflow_id (embeds ${firstScheduledTime}), so
|
||||
# we use the workflow_id as the dedup key instead.
|
||||
if trigger_key == SCHEDULED_TRIGGER_KEY:
|
||||
dedup_source = workflow.info().workflow_id
|
||||
else:
|
||||
dedup_source = f"{activity_id}:{trigger_key}"
|
||||
run_id = str(uuid.uuid5(uuid.NAMESPACE_URL, dedup_source))
|
||||
await workflow.execute_activity(
|
||||
log_run,
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user