All-Serverless Durable Coordinator
This spike asks one question: can TPF keep QUEUE_ASYNC semantics without a long-running coordinator process?
The answer is probably yes, but not by making a Lambda, Azure Function, or Cloud Run function "durable" by itself. The coordinator must be decomposed into single-shot actions that can be invoked by APIs, queues, event sources, and schedulers. Durable cloud services own wakeups and storage; TPF still owns execution semantics.
Current FUNCTION support remains serverless invocation/adapter support. This page describes a future design track, not current runtime support.
Recommendation
Use a TPF-native single-shot coordinator action model as the next architecture step.
Provider durable workflow engines can be useful later, but only as backend adapters if they preserve TPF's control-plane invariants:
- execution identity and idempotent submit,
- await unit identity and external completion admission,
- pinned pipeline contract and release version,
- worker identity and release compatibility checks,
- DLQ/re-drive evidence and operator control,
- at-least-once transition execution with stable business idempotency keys.
Do not start Lambda handler implementation until sweep, await item continuation, and polling loops have explicit single-shot actions.
Target Shape
The coordinator no longer has an always-on sweeper thread or local poller loop. Each invocation performs one bounded action and exits.
| Current compute-first role | All-serverless equivalent |
|---|---|
| Hosted control-plane resource | API/function handler for submit, status, result, await completion, admin, and re-drive |
| SQS work poller thread | Queue event-source invocation or explicit processWorkItem action |
| Queue sweeper thread | Scheduled sweepOnce invocation |
| Await completion poller | Provider event-source invocation or explicit completeAwait action |
| Transition worker process | Stateless function that handles one transition envelope |
| Worker lifecycle heartbeat | Explicit heartbeat action or platform-deployment registration action |
Single-Shot Action Sequences
Submit
This action is already close to single-shot. It creates the execution and enqueues work before returning.
Claim And Dispatch
This requires worker selection to be explicit and no accidental local fallback in the coordinator action.
Await Completion
The normal parent-release path is mostly single-shot. Aggregate item continuations are not clean yet because current code can schedule in-process retry attempts.
Sweep And Retry Wakeup
This is the clearest blocker. Current sweepDueExecutions owns a process scheduler and subscribes internally. All-serverless needs an explicit sweepOnce action returning a Uni/result that a scheduled invocation can call.
Re-drive
This is already close to single-shot. It must preserve pinned pipeline, contract, and release identity.
QueueAsyncCoordinator Decomposability Audit
| Area | Current shape | Single-shot readiness | Required change |
|---|---|---|---|
| Submit | executePipelineAsync creates execution and enqueues work | Clean | Keep as action method; ensure no process-local state is required beyond provider selection. |
| Status | getExecutionStatus reads durable record | Clean | No meaningful change. |
| Result | getExecutionResult / payload reads durable record | Clean | No meaningful change. |
| Re-drive | redriveExecution conditionally transitions terminal execution and enqueues work | Clean | Keep as action method; expose explicit result for function/API handlers. |
| Process work item | processExecutionWorkItem admits, claims, invokes worker, commits outcome | Mostly clean | Inject selected worker explicitly; require remote/function worker when running as serverless coordinator. |
| Await completion | completeAwait admits completion and releases parent execution | Partly clean | Keep parent release action; convert aggregate item continuations and retries into explicit queued actions. |
| Sweep | initializeQueueMode starts scheduled executor; sweepDueExecutions subscribes internally | Not clean | Extract sweepOnce(now, limit) returning a result and no internal subscription. |
| Await item continuation | Uses executor scheduling and fire-and-forget retry attempts | Not clean | Represent continuation attempts as durable work items or scheduler wakeups. |
| Work poller | SqsWorkPoller owns process loop | Not clean | Replace loop with queue event-source invocation or single pollOnce handler for local tests. |
| Await completion poller | SqsAwaitCompletionPoller owns process loop | Not clean | Replace loop with queue event-source invocation or single completeAwait handler. |
| SQS transition worker poller | SqsTransitionWorkerPoller owns process loop | Not clean | Use SQS event-source worker function or explicit single request handler. |
The current PipelineControlPlane facade is useful, but it is still process-shaped because initializeQueueMode starts a sweeper and the pollers own loops. The next runtime refactor should separate action logic from process hosting.
Provider Durable Workflow Shortcuts
Provider durable workflow engines may reduce implementation effort, but they are not drop-in replacements for TPF coordinator semantics.
| Backend option | Value | TPF risk |
|---|---|---|
| AWS Lambda durable functions | AWS documents checkpoint/replay, waits, retries, and long-running durable executions in Lambda code. Useful if TPF can compile coordinator logic into durable operations. | AWS owns replay/history semantics; TPF must map await units, release pinning, re-drive, and worker identity without creating a second inconsistent state machine. |
| AWS Step Functions / durable functions comparison | Mature AWS workflow orchestration with explicit state-machine visibility. | TPF pipeline semantics would need to compile into provider workflow definitions; provider history/retry/DLQ semantics may become authoritative. |
| Azure Durable Functions | Azure documents stateful orchestrator/activity/entity functions, managed state, checkpoints, retries, recovery, and Java support. | Strong Azure fit, weaker portability if TPF semantics depend on Durable Functions-specific orchestration constraints. |
| Google Cloud Workflows | Serverless workflow definitions in YAML/JSON, HTTP/service orchestration, retries, callbacks, waits, and monitoring. | Good orchestration substrate, but it is workflow-definition-first rather than TPF Java runtime-first. TPF would likely become a compiler to Workflows for that backend. |
Decision rule: a provider durable workflow backend is acceptable only if TPF can either:
- keep TPF execution/await/release records authoritative and use the provider engine as a wakeup/driver, or
- prove a faithful mapping where provider workflow history becomes authoritative without losing TPF observability and re-drive semantics.
The first implementation path should not assume either mapping. Build the TPF-native single-shot action model first; it is useful for provider event sources, cloud functions, and future durable-workflow adapters.
Implementation Slices After This Spike
- Single-shot coordinator actions. Extract
submit,processWorkItem,completeAwait,redrive, andsweepOnceaction methods without changing compute-first behaviour. - Loop hosting split. Keep current process pollers/sweepers as adapters around the action methods; add tests proving action methods can run without starting loops.
- AWS-shaped local proof. Use LocalStack-style Dynamo/SQS/EventBridge equivalents or scripts to invoke actions without a coordinator process.
- Provider function handlers. Add AWS-first function handlers only after the action model is explicit.
- Durable workflow adapter spike. Evaluate one provider backend using the same action model and document whether it preserves TPF semantics.
Current Decision
Proceed with TPF-native single-shot coordinator action extraction first.
Do not implement Lambda/FUNCTION HA yet. Do not adopt provider durable workflow engines as the primary coordinator runtime until TPF has a clean action model and a mapping test for await units, release identity, and operator re-drive.