DEV Community

Alex Spinov
Alex Spinov

Posted on

Temporal Has Free Durable Workflow Execution — Here's Why Microservices Teams Need It

What happens when your microservice crashes mid-workflow? With Temporal, it picks up exactly where it left off.

What is Temporal?

Temporal is an open-source durable execution platform. Write workflows as code — if the process crashes, Temporal replays the workflow from the last checkpoint. No data loss, no manual recovery.

Why You Need Durable Execution

Imagine an order processing workflow:

  1. Charge payment
  2. Reserve inventory
  3. Send confirmation email
  4. Schedule shipping

What if the server crashes after step 2? Without Temporal: manual intervention. With Temporal: automatic retry from step 3.

Quick Start

# Start Temporal server
temporal server start-dev

# Create project
mkdir temporal-app && cd temporal-app
bun init && bun add @temporalio/client @temporalio/worker @temporalio/workflow @temporalio/activity
Enter fullscreen mode Exit fullscreen mode

Define Activities

// src/activities.ts
export async function chargePayment(orderId: string, amount: number): Promise<string> {
  const response = await fetch('https://payments.api/charge', {
    method: 'POST',
    body: JSON.stringify({ orderId, amount }),
  });
  const data = await response.json();
  return data.transactionId;
}

export async function reserveInventory(orderId: string, items: string[]): Promise<boolean> {
  // Call inventory service
  return true;
}

export async function sendConfirmationEmail(email: string, orderId: string): Promise<void> {
  await fetch('https://email.api/send', {
    method: 'POST',
    body: JSON.stringify({ to: email, template: 'order-confirmed', data: { orderId } }),
  });
}
Enter fullscreen mode Exit fullscreen mode

Define Workflow

// src/workflows.ts
import { proxyActivities, sleep } from '@temporalio/workflow';
import type * as activities from './activities';

const { chargePayment, reserveInventory, sendConfirmationEmail } = proxyActivities<typeof activities>({
  startToCloseTimeout: '30 seconds',
  retry: { maximumAttempts: 3 },
});

export async function orderWorkflow(order: { id: string; email: string; amount: number; items: string[] }): Promise<string> {
  // Step 1: Charge payment
  const txId = await chargePayment(order.id, order.amount);

  // Step 2: Reserve inventory
  const reserved = await reserveInventory(order.id, order.items);
  if (!reserved) throw new Error('Inventory unavailable');

  // Step 3: Send confirmation
  await sendConfirmationEmail(order.email, order.id);

  // Step 4: Wait 30 days, then send review request
  await sleep('30 days');
  // This sleep survives server restarts!

  return txId;
}
Enter fullscreen mode Exit fullscreen mode

Start Workflow

// src/client.ts
import { Client } from '@temporalio/client';
import { orderWorkflow } from './workflows';

const client = new Client();

const handle = await client.workflow.start(orderWorkflow, {
  taskQueue: 'orders',
  workflowId: `order-${orderId}`,
  args: [{ id: orderId, email: 'alice@example.com', amount: 99.99, items: ['item-1'] }],
});

const result = await handle.result();
Enter fullscreen mode Exit fullscreen mode

Key Features

  • Automatic retries with configurable policies
  • Long-running workflows — sleep for days/months without keeping a process alive
  • Signals — send data to running workflows
  • Queries — check workflow state without affecting execution
  • Child workflows — compose complex workflows from simpler ones
  • Cron schedules — run workflows on a schedule

Temporal vs Alternatives

Feature Temporal Inngest Bull/BullMQ
Durable Execution Yes Yes No
Language Support TS, Go, Java, Python, PHP TS only TS only
Self-hosted Yes Yes Yes
Long Sleeps Days/months Hours No
Workflow as Code Yes Yes No
Visual UI Temporal UI Dashboard Bull Board

Need durable data pipelines? Check out my Apify actors — reliable scraping that never loses data. For custom solutions, email spinov001@gmail.com.

Top comments (0)