Keep a waiting process outside memory
Persist a checkpoint and load it in a fresh process. The journal records the stimuli needed to reconstruct the workflow's decisions; durability depends on the host actually storing it.
Processes as data
@schema-reflection/workflow
Experimental prototype · source onlyAn approval can wait longer than your server stays alive. Describe the process separately from the process that happens to be running it.
01 Why it matters
A human approval, a signing flow, or an onboarding sequence spends most of its life waiting. A Promise or timer in memory is tied to one running process. A deploy or restart can discard that waiting state unless the application has a durable representation of what already happened and what should happen next.
The workflow prototype represents steps and decisions as data. Pure start, advance, and resume functions derive the next checkpoint and commands from the definition and recorded history. The host executes commands and persists transitions. Recovery can reconstruct progress without rerunning completed action handlers.
02 What it unlocks
Persist a checkpoint and load it in a fresh process. The journal records the stimuli needed to reconstruct the workflow's decisions; durability depends on the host actually storing it.
A definition can run an action, wait for a correlated event, branch, or complete. The host receives commands rather than having the workflow library directly call a database, queue, or handler.
Inspect the definition, history, pending commands, and status to understand why an instance is waiting and which recorded result or event advances it.
03 How to use it
Evaluate the prototype with a small approval flow and a host you control. Test restart recovery and duplicate command delivery before extending the process. There is no npm installation command for this package yet.
Describe inputs, outputs, action contracts, event correlation, and meaningful step ids. Treat definition versions as part of the process identity, especially when a process may outlive a release.
Call start for a new instance. Persist the proposed checkpoint with outgoing commands, dispatch permitted handlers, and feed their results or ingested events back through advance with host timestamps.
Load the checkpoint and its matching definition in a fresh process, then call resume. Honor stable invocation identities when dispatching pending commands, because a resume can propose the same command again.
The example below describes the experimental source API. This package is not available on npm yet.
The experimental source prototype currently uses Effect 4.0.0-rc.115. Its portable contracts and host protocol may change before a public release.
import { Workflow, Expr } from "@schema-reflection/workflow"
const Review = Workflow.define("Review", { version: 1, input, output },
({ input, steps }) => {
const request = Workflow.run(steps.id("request"), RequestReview, {
candidateId: input.at("candidateId"),
})
const review = Workflow.awaitEvent(steps.id("review"), ReviewSubmitted, {
correlate: request.output.at("requestId"),
timeoutMs: 259_200_000, // three days
})
return Workflow.sequence(request, review,
Workflow.branch(steps.id("decision"),
review.output.at("decision").pipe(Expr.equal("approved")),
Workflow.complete("approved"),
Workflow.complete("rejected")))
})
const { checkpoint, commands } =
Workflow.start(Review, "review-1", { candidateId: "c1" }, Date.now())Interactive simulation loads when this panel comes into view.
The interactive panel is a Foldkit/Foldworks simulation of the behavior, not an execution of this package. The definition above is an API excerpt; supply your application's domain values and contracts.
04 In practice
The process requests a review and waits for a correlated response. A deployment occurs before the reviewer answers. The process should retain the request and the reason it is waiting.
The host runs RequestReview, records its result, and stores the checkpoint that waits on the returned request id.
A fresh host reloads that checkpoint. Resume reconstructs the wait from recorded data instead of requesting another completed review.
The host delivers ReviewSubmitted with its ingestion time. Advance records the event and produces the next branch or completion.
05 How it composes
Each library owns one kind of meaning. Combine the ones your application needs, with an explicit boundary between their jobs.
Logic supplies action behavior; workflow coordinates when an action is requested and how its result affects the process. The host binds exact permitted contracts and controls dispatch.
A portable condition can describe a branch over recorded inputs or results. Generic leaf callbacks need a host adapter; the portable workflow expression language cannot carry arbitrary functions.
Core supplies portable contracts and symbolic expressions for the experimental definition and checkpoint protocol. It helps the loader check shapes and references before accepting a transition.
Use host-defined relation annotations to audit named process and action references in configuration. That graph complements process validation; it does not supply checkpoint storage or event delivery.
A future layout could validate workflow definitions stored as files. Checkpoints are instance history, not merely definitions: their persistence and delivery protocol remain the host's responsibility.
These are application composition patterns, not a promise of automatic adapters. Align Effect peers and artifact formats before combining runtimes; source prototypes can differ from published releases.
See the family's approval scenario →06 Where it stops
This package is source-only. It has one active invocation and no automatic retries. Journals are limited to 10,000 stimuli, and replay cost grows with history. It is not a hosted workflow service.
There is no shipped database adapter, outbox, fencing, or compaction. Dispatch is at least once; handlers must honor invocation identities. The host must persist checkpoints, route events, and make delivery recoverable.
All libraries are pre-1.0. Pin exact versions and plan for changes to APIs and artifact formats.
Continue with the piece next to it