Build workflows that don’t break. GenSX gives you first-class primitives for pause/resume, retries, and human input—without losing state or writing scaffolding code.
Durable execution is built in. State is preserved automatically, workflows resume after failure, and you can checkpoint anywhere in the flow to rewind with new input or retry logic.
GenSX automatically snapshots all workflow state between component steps. If the process crashes or restarts, it picks up right where it left off:
const StatefulWorkflow = gensx.Component(
"StatefulWorkflow",
async ({ userId }: { userId: string }) => {
const userData = await fetchUserData(userId);
const processedData = await processUserData(userData);
const approval = await requestInput<{ approved: boolean }>(
async (callbackUrl) => {
await sendApprovalRequest(callbackUrl, processedData);
}
);
if (approval.approved) {
// If the program crashes during the finalizeUserData component, it can recover and resume without needing to re-fetch human approval.
return await finalizeUserData(processedData);
}
return "User data processing cancelled";
}
);
Need to wait for someone to click a button, review a doc, or approve a change? GenSX makes it easy to pause execution until human input arrives—with zero polling or timers.
const LongRunningApproval = gensx.Component(
"LongRunningApproval",
async ({ requestId }: { requestId: string }) => {
const approval = await requestInput<{ approved: boolean; notes: string }>(
async (callbackUrl) => {
await scheduleApprovalRequest(callbackUrl, requestId);
}
);
if (approval.approved) {
return await processApprovedRequest(requestId, approval.notes);
}
return "Request denied";
}
);
Execution can wait hours, days, or weeks—no resource usage, no expiration.
Handle failures the same way you’d write robust async code—try/catch
still works, but now it’s durable:
const RobustWorkflow = gensx.Component(
"RobustWorkflow",
async ({ items }: { items: any[] }) => {
const results = [];
const errors = [];
for (const item of items) {
try {
const result = await ProcessItem({ item });
results.push(result);
} catch (error) {
errors.push({ item, error: error.message });
}
}
return { results, errors };
}
);
Failures are isolated and recoverable across runs. No work is lost unless you want it to be.
For replay to work, everything outside a component must be deterministic. That means:
Date.now()
or Math.random()
outside components// ❌ Breaks replay
const BadWorkflow = gensx.Component("Bad", async () => {
return await ProcessData({
timestamp: Date.now(),
randomId: Math.random()
});
});
// ✅ Safe for replay
const GoodWorkflow = gensx.Component(
"Good",
async ({ timestamp, randomId }) => {
return await ProcessData({ timestamp, randomId });
}
);
Non-determinism is allowed inside components. That’s where GenSX captures and preserves execution.
const SafeComponent = gensx.Component(
"SafeComponent",
async ({ userId }: { userId: string }) => {
const now = Date.now(); // ✅ Safe here
const requestId = Math.random().toString(36);
const response = await fetch(`/api/users/${userId}`, {
headers: { 'X-Request-ID': requestId }
});
return await response.json();
}
);
Sometimes you need to go back and do something over—with feedback. Checkpoints let you do exactly that:
createCheckpoint()
to snapshot the current pointrestore(feedback)
const CheckpointWorkflow = gensx.Component(
"CheckpointWorkflow",
async ({ data }) => {
const { restore, feedback } = createCheckpoint();
if (feedback) {
return await processDataWithFeedback(data, feedback);
}
const result = await processData(data);
if (result.needsReview) {
await restore({ message: "Needs review", result });
}
return result;
}
);
The line after restore()
is never reached.
You can prevent infinite retries with maxRestores
:
const LimitedCheckpoint = gensx.Component("Retry", async () => {
const { restore, feedback } = createCheckpoint(
{ label: "retry" },
{ maxRestores: 3 }
);
if (feedback?.attempt >= 3) {
throw new Error("Maximum retries exceeded");
}
const result = await processWithRetry();
if (!result.success) {
await restore({
attempt: (feedback?.attempt || 0) + 1,
error: result.error
});
}
return result;
});
Checkpoint restoration is a powerful escape hatch for:
const HumanReviewWorkflow = gensx.Component(
"HumanReview",
async ({ document }) => {
const { restore, feedback } = createCheckpoint({ label: "review" });
if (feedback) {
return feedback.approved
? await finalizeDocument(document, feedback.changes)
: await reviseDocument(document, feedback.changes);
}
const draft = await generateDocument(document);
const review = await requestInput<{ approved: boolean; changes: any }>(
async (callbackUrl) => {
await sendForReview(draft, callbackUrl);
}
);
await restore(review);
}
);
Every execution is tracked in the GenSX console: