looper: lifecycle-own workflow state and make resume semantics real
#2,471 opened on Jul 12, 2026
Repository metrics
- Stars
- (4,293 stars)
- PR merge metrics
- (PR metrics pending)
Description
Summary
Make workflow state a bounded runtime-generation service shared across requests with consistent resume, take, expiry, and close behavior. Owner surfaces: src/semantic-router/pkg/looper/workflows.go, src/semantic-router/pkg/looper/workflows_state_store.go, and src/semantic-router/pkg/extproc/req_filter_looper.go.
Current behavior
Workflow loopers create state stores per request. Redis clients are not lifecycle-owned, memory state cannot resume across independent HTTP turns, file expiry depends on later writes, and payload size is not independently bounded.
Expected behavior
One state service is owned per runtime generation, all advertised backends support stable pause and resume semantics, and connection, cardinality, byte, TTL, take, and shutdown behavior are bounded and testable.
Acceptance
- Share one state service per runtime generation and close or drain it during retirement.
- Make two independent requests pause and resume with memory, file, and Redis backends.
- Keep Redis connection counts stable and enforce backend TTL.
- Bound memory state by TTL, cardinality, and bytes; expire file state without requiring a later write.
- Make concurrent take exactly once and cap stored payload size.
Validation
- Add two-request pause/resume conformance tests for every backend.
- Add sustained-request Redis pool, idle-expiry, payload-limit, concurrent-take, reload, and shutdown tests under
-race. - Run
cd src/semantic-router && go test -race ./pkg/looper ./pkg/extproc. - Run the affected Looper workflow E2E profiles selected by the harness.
Related
- Parent audit: #2375
- Looper hardening: #2336
- Router Memory: #2339
- Durable architecture: TD044