Durable Execution: Temporal & Inngest
Relevant source files
The following files were used as context for generating this wiki page:
Durable Execution in Forze provides a framework for building long-running, reliable processes using distributed orchestrators like Temporal and Inngest. The system abstracts complex distributed systems logic—such as state persistence, retries, and timers—into logical specifications and ports that integrate seamlessly with the Forze application layer.
The architecture separates logical definitions (specs) from physical execution (adapters). Temporal is used for complex stateful workflows, signals, and queries, while Inngest is utilized for event-driven durable functions and memoized steps.
Sources: skills/forze-temporal-workflows/SKILL.md, skills/forze-inngest-durable-functions/SKILL.md
Workflow Architecture and Specifications
Workflows are defined using DurableWorkflowSpec, which describes the main entry point, signals, queries, and updates. This spec acts as the contract between the application logic and the Temporal backend.
Component Relationship
The diagram below illustrates how logical workflow specifications are mapped to the Temporal client and task queues through the dependency registry.
Key Workflow Entities
| Entity | Description |
|---|---|
DurableWorkflowInvokeSpec | Defines the args_type and return_type for a workflow or action. |
DurableWorkflowSignalSpec | Specification for asynchronous signals sent to a running workflow. |
DurableWorkflowQuerySpec | Specification for synchronous queries to retrieve state from a workflow. |
DurableWorkflowHandle | A unique identifier containing workflow_id and optional run_id. |
Sources: src/forze/application/contracts/durable/workflow/specs.py:19-55
Temporal Execution Engine
The TemporalClient serves as the low-level bridge to the Temporal SDK. It manages the lifecycle of the connection to the Temporal cluster and provides methods for starting, signaling, and querying workflows.
Workflow Lifecycle Flow
The following sequence diagram shows the interaction when a handler triggers a workflow execution through the Forze ports.
Temporal Client Operations
The TemporalClient handles the following core responsibilities:
- Workflow Management: Starting (
start_workflow), canceling (cancel_workflow), and terminating (terminate_workflow) executions. - State Interaction: Sending signals (
signal_workflow) and executing queries (query_workflow) or updates (update_workflow). - Result Retrieval: Blocking or polling for workflow completion via
get_workflow_result.
Sources: src/forze_temporal/kernel/client/client.py:141-213
Durable Workflow Schedules
Forze supports the Temporal Schedules API, allowing workflows to be triggered based on time intervals or cron expressions.
Schedule Timing Configuration
The DurableWorkflowScheduleTiming class provides a provider-agnostic way to define when a workflow should fire. It supports:
- Cron Expressions: Multiple cron strings for complex scheduling.
- Intervals: Fixed
timedeltabetween runs. - Jitter: Random delays to prevent "thundering herd" issues.
Sources: src/forze/application/contracts/durable/workflow/specs.py:165-197
Schedule Management Flow
Inngest Durable Functions
Forze integrates with Inngest to provide event-driven durable execution. Unlike Temporal workflows, Inngest functions are triggered by events or crons and use memoized "steps" to ensure durability.
Comparison with Temporal
| Feature | Temporal (Workflows) | Inngest (Functions) |
|---|---|---|
| Trigger | Explicit Start / Signal | Event-driven / Cron |
| State | Stateful Orchestration | Memoized Steps |
| Communication | gRPC to Server | HTTP Webhooks (FastAPI) |
| Key Spec | DurableWorkflowSpec | DurableFunctionSpec |
Sources: skills/forze-inngest-durable-functions/SKILL.md
Durable Function Steps
Inside an Inngest function, developers use DurableFunctionStepDepKey to execute code that must be checkpointed.
step = ctx.deps.provide(DurableFunctionStepDepKey)
await step.run("process-payment", lambda: payment_provider.charge(...))
Sources: skills/forze-inngest-durable-functions/SKILL.md
Implementation Patterns
Context and Tenancy
In multi-tenant environments, Durable Execution requires careful context propagation. Forze uses ExecutionContextInterceptor to ensure that TenantIdentity and AuthnIdentity cross the client/worker boundary. This allows generated workflow_id values to include tenant scopes automatically when tenant_aware=True is configured in the TemporalDepsModule.
Sources: skills/forze-temporal-workflows/SKILL.md, tests/unit/test_forze_temporal/test_adapters_schedule.py:61-78
Registry Configuration
Durable execution components must be registered in the DepsRegistry to be accessible to handlers.
temporal_module = TemporalDepsModule(
client=temporal_client,
workflows={
"onboarding": {
"queue": "onboarding-tasks",
"tenant_aware": True,
}
},
)
deps = DepsRegistry.from_modules(temporal_module)
Sources: skills/forze-temporal-workflows/SKILL.md
Summary
The Durable Execution system in Forze enables developers to build resilient, long-running processes by abstracting Temporal and Inngest. By using DurableWorkflowSpec and DurableFunctionSpec, the application remains decoupled from the specific underlying infrastructure. Temporal provides robust stateful orchestration with support for schedules and signals, while Inngest offers a lightweight event-driven alternative using HTTP-based durable steps.