A long-running Temporal workflow in poimen-workflows that receives cluster events via signals and evaluates them against operational goals.
Why
The api-gateway handles commodity routing (Gotify push, SQS queue). Intelligent observation — "is this PR stale?", "did deploys degrade after this merge?", "are error rates spiking?" — needs durable state and goal tracking. Temporal gives us that for free.
ObserverWorkflow starts with WorkflowID: observer-main and stays running
Receives events via workflow.GetSignalChannel("event") — send signal, workflow processes it
After processing 1000 events, calls continue-as-new with carried state
Goal state (counters, timestamps, active violations) survives continue-as-new: verify by sending events before and after CAN, goal evaluation is consistent
Workflow recoverable after worker crash: kill worker pod, restart, workflow resumes from last checkpoint
Goal Evaluation
Goal pr_review_sla: pr.created event starts a timer; if no pr.review within 2h for same subject → triggers notification action
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
What
A long-running Temporal workflow in
poimen-workflowsthat receives cluster events via signals and evaluates them against operational goals.Why
The api-gateway handles commodity routing (Gotify push, SQS queue). Intelligent observation — "is this PR stale?", "did deploys degrade after this merge?", "are error rates spiking?" — needs durable state and goal tracking. Temporal gives us that for free.
Architecture
Files (poimen-workflows repo)
statemachine/observer.go— ObserverWorkflowstatemachine/goals.go— Goal types + built-in goalsaction/observer_eval.go— evaluate event against goalsaction/observer_notify.go— dispatch notificationstests/observer_workflow_test.go— unit testsAcceptance
Workflow Lifecycle
ObserverWorkflowstarts withWorkflowID: observer-mainand stays runningworkflow.GetSignalChannel("event")— send signal, workflow processes itcontinue-as-newwith carried statecontinue-as-new: verify by sending events before and after CAN, goal evaluation is consistentGoal Evaluation
pr_review_sla:pr.createdevent starts a timer; if nopr.reviewwithin 2h for same subject → triggers notification actiondeploy_health:sync.failedevent → immediately triggers alert (priority 10)build_success_rate: tracksbuild.success/build.failureratio over sliding window; drops below 95% → triggers alertAction Dispatch
notify→ calls Gotify activity with correct prioritystart_workflow→ starts child workflow with event as inputsignal_orchestrator→ signals running orchestrator workflow (e.g., inject lesson)Tests
go test ./tests/observer_workflow_test.go— receives 3 events via signal, evaluates goals, dispatches actions (mocked activities)go test ./tests/observer_workflow_test.go— continue-as-new after N events, state carriedgo test ./tests/observer_workflow_test.go— goal cooldown: duplicate violation suppressedgo test ./tests/observer_workflow_test.go— no goals registered: events accepted, no actions dispatchedgo test ./tests/observer_workflow_test.go— action failure: logged, workflow continues