在本示例中,我们为电商网站实现 Workflow,每次创建购物车时触发。
Workflow 实例触发后,开始轮询 D1 数据库中的购物车 ID,直到结账完成。购物车结账后,我们通过 fetch POST 与外部提供商处理付款。最后,假设一切顺利,我们尝试使用 Email Workers 向客户发送带有发票的邮件。
如你所见,Workflows 处理各种服务响应和故障;它会重试 D1 直到购物车结账,在支付处理器失败时重试,在无法发送发票邮件时重试。开发者无需关心任何此类逻辑,workflow 可以运行数小时,处理所有可能的情况直到完成。
这是处理购物车的简化示例。在真实场景中,我们假设会有更多步骤和额外逻辑,但此示例让你了解 Workflows 能做什么。
import {
WorkflowEntrypoint,
WorkflowStep,
WorkflowEvent,
} from "cloudflare:workers";
import { EmailMessage } from "cloudflare:email";
import { createMimeMessage } from "mimetext";
// We are using Email Routing to send emails out and D1 for our cart database
type Env = {
CART_WORKFLOW: Workflow;
SEND_EMAIL: any;
DB: any;
};
// Workflow parameters: we expect a cartId
type Params = {
cartId: string;
};
// Adjust this to your Cloudflare zone using Email Routing
const merchantEmail = "[email protected]";
// Uses mimetext npm to generate Email
const genEmail = (email: string, amount: number) => {
const msg = createMimeMessage();
msg.setSender({ name: "Pet shop", addr: merchantEmail });
msg.setRecipient(email);
msg.setSubject("You invoice");
msg.addMessage({
contentType: "text/plain",
data: `Your invoice for ${amount} has been paid. Your products will be shipped shortly.`,
});
return new EmailMessage(merchantEmail, email, msg.asRaw());
};
// Workflow logic
export class cartInvoicesWorkflow extends WorkflowEntrypoint<Env, Params> {
async run(event: WorkflowEvent<Params>, step: WorkflowStep) {
await step.sleep("sleep for a while", "10 seconds");
// Retrieve the cart from the D1 database
// if the cart hasn't been checked out yet retry every 2 minutes, 10 times, otherwise give up
const cart = await step.do(
"retrieve cart",
{
retries: {
limit: 10,
delay: 2000 * 60,
backoff: "constant",
},
timeout: "30 seconds",
},
async () => {
const { results } = await this.env.DB.prepare(
`SELECT * FROM cart WHERE id = ?`,
)
.bind(event.payload.cartId)
.run();
// should return { checkedOut: true, amount: 250 , account: { email: "[email protected]" }};
if (results[0].checkedOut === false) {
throw new Error("cart hasn't been checked out yet");
}
return results[0];
},
);
// Proceed to payment, retry 10 times every minute or give up
const payment = await step.do(
"payment",
{
retries: {
limit: 10,
delay: 1000 * 60,
backoff: "constant",
},
timeout: "30 seconds",
},
async () => {
let resp = await fetch("https://payment-processor.example.com/", {
method: "POST",
headers: {
"Content-Type": "application/json; charset=utf-8",
},
body: JSON.stringify({ amount: cart.amount }),
});
if (!resp.ok) {
throw new Error("payment has failed");
}
return { success: true, amount: cart.amount };
},
);
// Send invoice to the customer, retry 10 times every 5 minutes or give up
// Requires that cart.account.email has previously been validated in Email Routing,
// See https://developers.cloudflare.com/email-service/api/route-emails/email-handler/
await step.do(
"send invoice",
{
retries: {
limit: 10,
delay: 5000 * 60,
backoff: "constant",
},
timeout: "30 seconds",
},
async () => {
const message = genEmail(cart.account.email, payment.amount);
try {
await this.env.SEND_EMAIL.send(message);
} catch (e) {
throw new Error("failed to send invoice");
}
},
);
}
}
// Default page for admin
// Remove in production
export default {
async fetch(req: Request, env: Env): Promise<Response> {
let url = new URL(req.url);
let id = new URL(req.url).searchParams.get("instanceId");
// Get the status of an existing instance, if provided
if (id) {
let instance = await env.CART_WORKFLOW.get(id);
return Response.json({
status: await instance.status(),
});
}
if (url.pathname.startsWith("/new")) {
let instance = await env.CART_WORKFLOW.create({
params: {
cartId: "123",
},
});
return Response.json({
id: instance.id,
details: await instance.status(),
});
}
return new Response(
`<html><body><a href="/new">new instance</a> or add ?instanceId=...</body></html>`,
{
headers: {
"content-type": "text/html;charset=UTF-8",
},
},
);
},
};以下是最小 package.json:
{
"devDependencies": {
"wrangler": "^3.83.0"
},
"dependencies": {
"mimetext": "^3.0.24"
}
}最后是 Wrangler 配置文件:
{
"$schema": "./node_modules/wrangler/config-schema.json",
"name": "cart-invoices",
"main": "src/index.ts",
// Set this to today's date
"compatibility_date": "2026-08-17",
"compatibility_flags": [
"nodejs_compat"
],
"workflows": [
{
"name": "cart-invoices-workflow",
"binding": "CART_WORKFLOW",
"class_name": "cartInvoicesWorkflow"
}
],
"send_email": [
{
"name": "SEND_EMAIL"
}
]
}"$schema" = "./node_modules/wrangler/config-schema.json"
name = "cart-invoices"
main = "src/index.ts"
# Set this to today's date
compatibility_date = "2026-08-17"
compatibility_flags = [ "nodejs_compat" ]
[[workflows]]
name = "cart-invoices-workflow"
binding = "CART_WORKFLOW"
class_name = "cartInvoicesWorkflow"
[[send_email]]
name = "SEND_EMAIL"如果你使用 TypeScript,每当你修改 Wrangler 配置文件时,请运行 wrangler types。这将根据你的绑定生成 env 对象的类型,以及运行时类型。