StaticdisconnectingActivates a deployed version across the entire mesh. The quorum coordinates a synchronized switch-over:
nocache mode — all engines consult Postgres for the
active version on every request.cache mode — engines resume caching.The optional delay adds a pause (in ms) for the quorum to reach
consensus under heavy traffic. Combine with throttle() for
zero-downtime version switches.
Optionaldelay: numberAdds a transition message to the workstream, resuming Leg 2 of a
paused reentrant activity (e.g., await, worker, hook). This
is typically called by the engine internally but is exposed for
advanced use cases like custom activity implementations.
Deploys a YAML workflow graph to Postgres. Accepts a file path or
an inline YAML string. Referenced $ref files are resolved and
merged. The deployed version is inactive until activate() is
called.
// Deploy from an inline YAML string
await hotMesh.deploy(`
app:
id: myapp
version: '2'
graphs:
- subscribes: order.placed
activities:
t1:
type: trigger
process:
type: worker
topic: order.process
transitions:
t1:
- to: process
`);
// Deploy from a file path (resolves $ref references)
await hotMesh.deploy('./workflows/order.yaml');
Returns specific searchable fields from a job's HASH record.
Pass field names to retrieve; use ":" to read the reserved
status field.
Returns all raw key-value pairs for a job's HASH record. This is
the lowest-level read — it returns internal engine fields alongside
user data. Prefer getState() for structured output.
Interrupts (terminates) an active workflow job. The job's status is set to an error code indicating abnormal termination, and any pending activities or timers are cancelled.
Subscribes to workflow emissions matching a wildcard pattern. Useful for monitoring an entire domain of workflows at once.
Publishes a message to a workflow topic, starting a new job.
Returns the job ID immediately (fire-and-forget). Use pubsub
to block until the workflow completes.
Optionalcontext: JobStateOptionalextended: ExtensionTypePublishes a message to every mesh member via the quorum channel
(Postgres LISTEN/NOTIFY). Any QuorumMessage type can be sent,
but the user type is the most common for application-level
messaging.
// Broadcast a custom event to all mesh members
await hotMesh.pubQuorum({
type: 'user',
topic: 'deploy.notify',
message: { version: '2.1.0', deployer: 'ci-pipeline' },
});
// Broadcast a config-reload signal
await hotMesh.pubQuorum({
type: 'user',
topic: 'config.reload',
message: { features: { darkMode: true } },
});
Publishes a message to a workflow topic and blocks until the workflow
completes, returning the final job output. Internally subscribes to
the workflow's publishes topic before publishing, then unsubscribes
after receiving the result.
Broadcasts a roll call across the mesh and collects responses from
every connected engine and worker. Each member replies with its
QuorumProfile — including GUID, worker topic, stream depth,
throttle rate, and system health (CPU, memory, network).
Use this for service discovery, health checks, and capacity planning.
Optionaldelay: numberSends a signal to a paused workflow, resuming its execution.
The topic must match a hook rule defined in the YAML graph's
hooks section. The engine locates the exact activity and
dimension for reentry based on the hook rule's match conditions.
Use this to deliver external data (approval decisions, webhook
payloads, partner responses) into a workflow that is sleeping
on a hook activity or awaiting a waitFor() signal.
Optionalstatus: StreamStatusOptionalcode: numberSubscribes to all output and interim emissions from a specific workflow topic. The callback fires each time a job on that topic completes or emits an interim result.
Subscribes to the quorum channel, receiving every message broadcast across the mesh in real time. This is the primary observability hook into the service mesh — use it to monitor version activations, throttle commands, roll call responses, workflow completions, and custom user events.
Messages arrive as typed QuorumMessage unions. Switch on
message.type to handle each:
| Type | When it fires |
|---|---|
pong |
A mesh member responds to a roll call |
throttle |
A throttle command was broadcast |
activate |
A version activation is in progress |
job |
A workflow completed and published its result |
user |
A custom user message (via pubQuorum) |
ping |
A roll call was initiated |
work |
A work distribution event |
cron |
A cron/scheduled event |
// Build a real-time mesh dashboard
await hotMesh.subQuorum((topic, message) => {
switch (message.type) {
case 'pong':
dashboard.updateMember(message.guid, {
topic: message.profile?.worker_topic,
throttle: message.profile?.throttle,
depth: message.profile?.stream_depth,
cpu: message.profile?.system?.CPULoad,
});
break;
case 'throttle':
dashboard.logThrottle(
message.throttle,
message.topic,
message.guid,
);
break;
case 'job':
dashboard.logCompletion(message.topic, message.job);
break;
case 'user':
dashboard.logUserEvent(message.topic, message.message);
break;
}
});
Broadcasts a throttle command to the mesh via the quorum channel. Targeted members insert a delay (in milliseconds) before processing their next stream message, providing instant backpressure control across any combination of engines and workers.
Throttling is stateless — no data is lost. Messages accumulate in Postgres streams and are processed once the throttle is lifted.
| Option | Effect |
|---|---|
| (none) | Throttle the entire mesh (all engines + all workers) |
topic |
Throttle all workers subscribed to this topic |
guid |
Throttle a single engine or worker instance |
topic + guid |
Throttle a specific topic on a specific instance |
| Value | Effect |
|---|---|
0 |
Resume normal processing (remove throttle) |
-1 |
Pause indefinitely (emergency stop) |
500 |
500ms delay between messages |
// Emergency stop: pause the entire mesh
await hotMesh.throttle({ throttle: -1 });
// Resume the entire mesh
await hotMesh.throttle({ throttle: 0 });
// Slow a specific worker topic to 1 msg per second
await hotMesh.throttle({ throttle: 1000, topic: 'order.process' });
// Throttle a single instance by GUID
await hotMesh.throttle({ throttle: 2000, guid: 'abc-123' });
// Throttle a specific topic on a specific instance
await hotMesh.throttle({
throttle: 500,
guid: 'abc-123',
topic: 'payment.charge',
});
Unsubscribes a callback previously registered with subQuorum().
StaticguidStaticinitInstance initializer. Workers are configured similarly to the engine, but as an array with multiple worker objects.
HotMesh supports retry policies with exponential backoff. Retry behavior
can be configured independently on both the engine and individual
workers. They are not inherited; each operates at its own level.
retryPolicy: Stamps messages the engine publishes with
retry metadata (stored as Postgres columns). Workers that consume
these messages will use the embedded config when handling failures.retryPolicy: Used as the fallback when the consumed
message does not carry explicit retry metadata.const hotMesh = await HotMesh.init({
appId: 'myapp',
engine: {
connection: {
class: Postgres,
options: {
connectionString: 'postgresql://usr:pwd@localhost:5432/db',
}
}
},
workers: [...]
});
const hotMesh = await HotMesh.init({
appId: 'myapp',
engine: {
connection: {
class: Postgres,
options: { connectionString: 'postgresql://...' }
},
retryPolicy: {
maximumAttempts: 5,
backoffCoefficient: 2,
maximumInterval: '300s'
}
}
});
const hotMesh = await HotMesh.init({
appId: 'myapp',
engine: { connection },
workers: [{
topic: 'order.process',
connection,
retryPolicy: {
maximumAttempts: 5,
backoffCoefficient: 2,
maximumInterval: '30s',
},
callback: async (data: StreamData) => {
const result = await doWork(data.data);
return {
code: 200,
status: StreamStatus.SUCCESS,
metadata: { ...data.metadata },
data: { result },
} as StreamDataResponse;
}
}]
});
Retry Policy Options:
maximumAttempts - Maximum retry attempts before failure (default: 3)backoffCoefficient - Base for exponential backoff calculation (default: 10)maximumInterval - Maximum delay between retries in seconds or duration string (default: '120s')Retry Delays: For backoffCoefficient: 2, delays are: 2s, 4s, 8s, 16s, 32s...
capped at maximumInterval.
Note: Retry policies are stored in PostgreSQL columns for efficient querying and observability. Each retry creates a new message, preserving message immutability.
Staticstop
A distributed service mesh that turns Postgres into a durable workflow orchestration engine. Every
HotMesh.init()call creates a point of presence — an engine, a quorum member, and zero or more workers — that collaborates with its peers through Postgres LISTEN/NOTIFY to form a self-coordinating mesh with no external dependencies.Service Mesh Architecture
Each HotMesh instance joins a quorum — a real-time pub/sub channel backed by Postgres LISTEN/NOTIFY. The quorum is the mesh's nervous system: version activations, throttle commands, roll calls, and custom user messages all propagate instantly to every connected engine and worker across all processes and servers.
Quick Start
Quorum: The Mesh Control Plane
The quorum channel is a broadcast bus available to every mesh member. Use it for operational control, observability, and custom messaging.
Throttling: Backpressure Across the Mesh
Throttle commands propagate instantly to every targeted member via the quorum channel, providing fine-grained flow control.
Lifecycle
init— Create an engine + workers; join the quorum.deploy— Upload a YAML graph to Postgres (inactive).activate— Coordinate the quorum to switch to the new version.pub/pubsub— Trigger workflow execution.stop— Leave the quorum and release connections.Higher-Level Modules
For most use cases, prefer the higher-level wrappers:
See
https://hotmeshio.github.io/sdk-typescript/ - API reference