Skip to content

Instantly share code, notes, and snippets.

@igalshilman
Created October 24, 2024 15:35
Show Gist options
  • Save igalshilman/6d807620048ca7aeb3c87f07e76f2297 to your computer and use it in GitHub Desktop.
Save igalshilman/6d807620048ca7aeb3c87f07e76f2297 to your computer and use it in GitHub Desktop.
/*
* Copyright (c) 2023-2024 - Restate Software, Inc., Restate GmbH
*
* This file is part of the Restate SDK for Node.js/TypeScript,
* which is released under the MIT license.
*
* You can find a copy of the license in file LICENSE in the root
* directory of this repository or package, or at
* https://github.com/restatedev/sdk-typescript/blob/main/LICENSE
*/
/* eslint-disable @typescript-eslint/no-unused-vars */
import * as restate from "@restatedev/restate-sdk";
import { CombineablePromise } from "@restatedev/restate-sdk";
interface PaymentRequest {
amount: number;
account: string;
}
interface PaymentSuccess {
account: string;
}
const payment = restate.workflow({
name: "payment",
handlers: {
// these are the steps of the workflow, broken down to individual handlers
// instead of a single monolithic function.
makePayment: async (
ctx: restate.WorkflowSharedContext,
payment: PaymentRequest
) => {
//
// For example use the stripe client to make the payment.
// <!> Restate will store the result of this block durably, and
// will make sure that it will not be executed again, once durably committed by restate.
},
notifyUser: async (
ctx: restate.WorkflowSharedContext,
payment: PaymentRequest
) => {
//
// use an email delivery service here to notify the user that their payment is being processed
//
},
emitEvent: async (
ctx: restate.WorkflowSharedContext,
payment: PaymentRequest
) => {
//
// publish an event to an external system
//
},
/**
* Run is the entry point for the workflow.
*
* @param ctx the restate context allows interacting with the restate APIs.
* @param payment the argument
* @returns
*/
run: async (ctx: restate.WorkflowContext, request: PaymentRequest) => {
//
// let's start by validating the workflow input.
// The input might come directly from restate's ingress or via
// a typed workflow client (see workflow_client.ts example)
//
if (request.amount < 0) {
// this will stop the workflow
throw new restate.TerminalError("Amount must be positive");
}
const isCanceled = ctx.promise("canceled").get();
// step 1
const makePayment = ctx
.workflowClient(payment, ctx.key)
.makePayment(request);
await CombineablePromise.race([isCanceled, makePayment]);
// step 2
const notifyUser = ctx
.workflowClient(payment, ctx.key)
.notifyUser(request);
await CombineablePromise.race([isCanceled, notifyUser]);
// step 3
const emitEvent = ctx.workflowClient(payment, ctx.key).emitEvent(request);
await CombineablePromise.race([isCanceled, emitEvent]);
return "success";
},
/**
* PaymentWebhook handler - is triggered directly as a Webhook by our imaginary payment provider.
*/
cancel: async (ctx: restate.WorkflowSharedContext) => {
await ctx.promise("canceled").reject("cancelled");
},
},
});
export type PaymentWorkflow = typeof payment;
restate.endpoint().bind(payment).listen();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment