Cohesive Systems logoCOHESIVE SYSTEMS

Search Cohesive Systems

Ready

Search Cohesive Systems

Find product pages, building blocks, technical articles, and graph definitions.

Cohesive.Processes Internals

From Async C# to Durable Execution

How authored Processes become restorable definitions, advance through immutable continuations, and retain enough evidence for safe replay and recovery.

Why These Internals Exist

The Cohesive.Processes overview presents the application model: author a workflow in familiar C#, invoke semantic operations, wait for external progress, and return a typed outcome.

Durable execution must preserve that workflow after the authoring process exits, the host restarts, definitions change, and external operations complete more than once. It must decide which continuation can advance, which inputs are acceptable, and which completed work can be replayed from evidence.

C# Is the Authoring Surface

A human-authored Process begins with a partial type marked by GenerateProcessDefinition. Its Run method returns ProcessTask<T> and receives a ProcessContext. Semantic operations use await; pure locals and expressions become inputs to the nearest operation, branch, or terminal result.

Cohesive.Analyzers reads the method's syntax and generates a Define factory. The annotated method is never invoked, and no CLR async state machine becomes durable authority. The generated factory produces the canonical execution-definition document used by compilation and runtime interpretation.

The frontend supports a restricted source language that can lower completely into the finite Process model:

await process.Query / Read

Canonical meaning
Evaluation of one exact Relation or Query with typed input and a result continuation.

await process.Transition

Canonical meaning
Invocation of one exact entity Transition for an explicitly computed subject.

await process.Effect

Canonical meaning
A durable typed request obligation and its selected outcome continuation.

if, switch, Choice, Match

Canonical meaning
Finite branch structure with explicit coverage and deterministic selection.

return, Succeed, Terminate

Canonical meaning
A typed terminal Process result and status.

Arbitrary CLR services, I/O, ordinary tasks, reflection, mutable loops, recursion, captured delegates, and host-language suspension cannot enter the generated model. Unsupported syntax produces a source diagnostic instead of creating behavior that might fail during replay.

Direct builder authoring remains available for generators, importers, and tests. It is an advanced lowering surface rather than the normal application API.

One Semantic Lifecycle

Canonical Process lifecycle

Syntax-only asynchronous C#, then Canonical Process document, then Linked compiled plan, then Immutable continuation decision, then Durable checkpoint and evidence

A Process resumes from its definition and durable evidence, not from a suspended C# method.

Source is a replaceable producer. The canonical document retains Process semantics. A compiled plan is one replaceable interpretation of an exact definition, while runtime evidence records what happened under that definition and its fingerprint.

The Canonical Process Model

The closed Process node union covers exact semantic operations and finite control flow:

Transitions and Relations
requests, events, signals, and waits
choice, match, fork, and join
children, partition work, and recurrence
durable coordination through time

Read is an authoring alias for Relation or Query evaluation; it does not create another entity-read model. Effect lowers to a durable typed request rather than an arbitrary CLR callback. Every referenced Process, Transition, Relation, Query, or interaction uses exact definition identity, revision, and fingerprint evidence.

Static compilation validates graph integrity, binding visibility, portable expression types, finite activation, linked contracts, and structural policies. It also derives the requirements a runtime must satisfy without selecting a workflow engine or storage backend.

Durable Interactions and Waits

A request creates an explicit obligation with contract-owned terminal outcomes. Events continue without a response obligation. Signals target an exact Process occurrence. Replies close a retained request identity.

AwaitMatch models a durable race between typed interaction inputs and absolute deadlines. Its semantic policy includes:

  • deterministic priority and clause-identity arbitration
  • portable guards over typed input
  • late, stale, and duplicate input dispositions
  • missing-target behavior
  • a retention horizon

The result-binding C# form uses a closed source-only case family followed immediately by an exhaustive switch. Generation fuses each switch arm into its clause continuation. No union wrapper, discriminator, callback, or CLR pattern object is persisted.

Accepted interaction inputs become durable inbox evidence. Outgoing requests, replies, signals, and events become canonical outbox envelopes. Their logical identities let delivery and recovery distinguish a repeated attempt from new work.

Parallel and Higher-Order Work

Fork and Join carry more meaning than “run these tasks together.” Canonical policy states how many branches must complete, how failure affects the threshold, what happens to remaining branches, whether completion order is observable, and how simultaneous eligibility is resolved.

Typed source helpers cover all-branch tuples, the first eligible winner, and required-count winners. Hard limits bound items, starts per activation, total parallelism, and optional capacity domains. A runtime may narrow admission within those bounds; it cannot silently exceed or weaken them.

A child invocation records its exact Process and request protocol, terminal-status mapping, purpose, and parent-cancellation behavior. Purpose distinguishes ordinary work from compensation and reconciliation.

ForEachPartition admits dynamically discovered items under explicit finite limits and failure policy. RepeatAcrossActivation models durable recurrence with a maximum occurrence count and a bound on unchanged progress. These policies make liveness assumptions available to validation and operational tooling.

Identity and Compatibility

The source generator derives deterministic identities for local structure. Unrelated source insertions do not globally renumber semantic roles. Explicit identities remain necessary when a continuation, checkpoint, migration, external target, operational command, or cross-revision contract names a construct directly.

Changing an explicitly durable identity or fingerprint-bearing topology is a compatibility decision. Restore validates the schema, definition identity, revision, fingerprint, continuation tokens, and linked semantic evidence before execution resumes.

Durable Runtime and Replay

ProcessReferenceInterpreter provides the reference in-memory interpretation of a compiled canonical plan. Durable execution composes that plan with Cohesive.Storage.Processes.ProcessDurableRuntime and IProcessDurableStore.

The durable checkpoint is one coherent aggregate containing:

Continuation tokens

What it preserves
The exact canonical nodes and typed bindings from which execution can continue.

Attempt and activation receipts

What it preserves
Which Process attempt accepted which finite activation under which definition.

Inbox dispositions

What it preserves
How targeted, late, stale, duplicate, and unresolved inputs were handled.

Operation receipts

What it preserves
Which Relation, Transition, or host operation has already completed and which result can be reused.

Outbox envelopes

What it preserves
Interactions committed for later publication with stable logical emission identity.

Control state

What it preserves
Pause, continue, restart, cancel, and terminate evidence with attempt and fencing semantics.

One storage mutation commits a legal successor. Replay returns retained operation evidence instead of repeating logical work. This is the Process-side basis for reconstitution after a restart. An operation adapter may still perform physical idempotency and delivery work required by its external system; the Process ledger preserves whether this Process occurrence has already accepted the result.

Control and Observation

Operational surfaces project common execution artifacts instead of inventing workflow-specific status models:

  • bounded current ExecutionStatus
  • payload-safe normalized trace
  • layered explain artifacts with definition, compilation, realization, and runtime evidence
  • low-cardinality telemetry
  • canonical lifecycle control commands

Pause, continue, restart, cancel, and terminate retain attempt identity, fencing, idempotency, and safe-point behavior. API, CLI, monitoring, and presentation surfaces may format or redact this evidence without becoming execution authority.

Current Runtime Boundaries

ProcessReferenceInterpreter

Current responsibility
Advance an immutable compiled continuation and produce operations, waits, interactions, or a terminal result.

ProcessDurableRuntime

Current responsibility
Coordinate finite activations with the durable store and commit coherent checkpoint successors.

Operation adapters

Current responsibility
Execute exact Relations, entity Transitions, and host operations, then return typed evidence to the Process.

Interaction adapters

Current responsibility
Publish outbox envelopes and deliver accepted replies, events, signals, and request outcomes.

DurableTask adapter

Current responsibility
Provide authority-neutral task-hub status projections; it is not the canonical Process executor.

Any future engine adapter must consume compiled canonical definitions and preserve the durable-store boundary or return a precise capability diagnostic.

Continue

Return to the Cohesive.Processes overview →

Build the first asynchronous Process →

See how entity Transitions make local decisions →