---
title: "Why Dex?"
description: "Dex is a Durable Execution(D-Ex) platform."
canonical_url: "https://docs.superdurable.io/intro/what-is-dex/"
source: "docs/content/intro/what-is-dex.mdx"
locale: "en"
---

# Why Dex?

Dex is a Durable Execution(D-Ex) platform.

Dex is structural programming with only a few concepts as [primitives](https://docs.superdurable.io/primitives.md). You use Dex to write a Flow filled with ordinary code: durable Steps, Attributes, RPCs, and durable conditions using Channels and Timers. Then you run Workers hosting your Flow. The Client calls Dex Server to start and interact with Flow instances. Dex Server dispatches Step and RPC invocation tasks to your Workers.

An Application contains a Client, which starts and interacts with Flow instances, and a Worker, which hosts the Flow; both use the Dex SDK. The Application calls Dex Server with startFlow and invokeRPC, and Dex Server invokes Steps and RPCs on the Worker. Dex Server persists Flow instances and their execution.

A **Step** can optionally **WaitFor** some condition (**Channel**, **Timer**, or both) durably. When the condition is met, **Execute** is invoked. If there is no WaitFor, Execute is invoked directly.

**Execute** returns a decision for the next Steps or for completing the Flow. Within the Steps and RPCs, user code can read or write **Attributes**, and/or publish durable **Channel** messages as communication from external events or within threads of a Flow.

## Order processing as an example

If you have not read [What is Durable Execution?](https://docs.superdurable.io/intro/what-is-durable-execution.md), the example below is the order-processing flow from that page.

The flow will charge the buyer, then wait for seller approval (with reminders), then ship the item, and refund if ship API call retries exhaust.

**Flow: OrderProcessingFlow**

Start Step: `Charge`

**Steps**

- `Charge`
- `Refund`
  - `gracefulComplete`
- `Ship`
  - WaitFor `anyOf`: channel `seller-ok.for 1`, timer `24 hours timer`
  - `gracefulComplete` when `not (context.has_timer_fired())`

**Edges**

- `goTo` (decision; Charge) → `Ship` (step): go_to
- `goTo` (decision; Ship; when `context.has_timer_fired()`) → `Ship` (step): go_to
- `order-status` (attribute) → `describe` (rpc): get
- `seller-ok` (channel) → `anyOf` (wait; Ship): seller-ok.for 1
- `approve` (rpc) → `seller-ok` (channel): publish
- `Charge` (step) → `order-status` (attribute): set
- `Refund` (step) → `order-status` (attribute): set
- `Ship` (step) → `order-status` (attribute): set
- `Ship` (step) → `Refund` (step): Execute failure

Example: [examples/python/dex_examples/products/order-processing/order_processing_flow.py](https://github.com/superdurable/dex/tree/main/examples/python/dex_examples/products/order-processing/order_processing_flow.py)

- **ChargeStep** calls the payment API with Step-level retry. On success, move to ShipStep atomically.
- **ShipStep** waits for a seller **Channel** or a **Timer**. Timer first: send a reminder and keep waiting. Approval: ship. Exhausted ship retries: **RefundStep**.
- **RPC approve** publishes the seller Channel.
- The storefront **start** handler waits for ChargeStep with the Client **wait-for-Step-completion** API — not a homemade status poll.
- **Attribute order-status** is indexed so support can search stuck orders.

**Python**

```python
order_status = Attribute(
    "order-status",
    str,
    AttributeIndex(IndexType.KEYWORD, "keyword1"),
)
seller_ok = Channel[str]("seller-ok", str)


class ChargeStep(Step[OrderRequest]):
    def __init__(self, service: MyDependencyService, ship: ShipStep) -> None:
        self.service = service
        self.ship = ship

    def get_step_options(self) -> StepOptions:
        return StepOptions(
            execute_retry=RetryPolicy(
                total_duration=timedelta(hours=1),
            )
        )

    def execute(self, context: Context, input: OrderRequest) -> StepDecision:
        self.service.charge_user(input.email, input.customer_id, input.amount)
        order_status.set(context, "charged")
        return go_to(ShipStep, input)


class ShipStep(Step[OrderRequest]):
    def __init__(self, service: MyDependencyService, refund: RefundStep) -> None:
        self.service = service
        self.refund = refund

    def get_step_options(self) -> StepOptions:
        return StepOptions(
            execute_retry=RetryPolicy(
                total_duration=timedelta(hours=1),
            )
        ).on_execute_failure_proceed_to(
            RefundStep,
            StepOptions(
                execute_retry=RetryPolicy(
                    total_duration=timedelta(hours=1),
                )
            ),
        )

    def wait_for(self, context: Context, input: OrderRequest) -> Wait:
        return Wait.any_of(
            seller_ok.for_one(),
            Timer.by_duration(timedelta(hours=24)),
        )

    def execute(self, context: Context, input: OrderRequest) -> StepDecision:
        if context.has_timer_fired():
            self.service.send_email(
                input.email,
                "Reminder: approve shipment",
                "Please approve or provide a tracking number.",
            )
            return go_to(ShipStep, input)
        self.service.ship_item(input.order_id)
        order_status.set(context, "shipped")
        return graceful_complete(f"shipped:{input.order_id}")


class RefundStep(Step[OrderRequest]):
    def __init__(self, service: MyDependencyService) -> None:
        self.service = service

    def execute(self, context: Context, input: OrderRequest) -> StepDecision:
        self.service.update_external_system(f"refund {input.order_id}")
        order_status.set(context, "refunded")
        return graceful_complete(f"refunded:{input.order_id}")


class OrderProcessingFlow(Flow[OrderRequest]):
    def __init__(self, service: MyDependencyService) -> None:
        self.service = service
        self.refund = RefundStep(service)
        self.ship = ShipStep(service, self.refund)
        self.charge = ChargeStep(service, self.ship)

    def get_steps(self) -> StepList[OrderRequest]:
        return StepList.start_step(self.charge).other_steps(self.ship, self.refund)

    def get_persistence_schema(self) -> PersistenceSchema:
        return PersistenceSchema.of(order_status, seller_ok)

    @rpc
    def approve(self, context: Context, _note: str) -> RPCResult[str]:
        seller_ok.publish(context, "approved")
        return RPCResult("ok")

    @rpc
    def describe(self, context: Context) -> RPCResult[str]:
        return RPCResult(order_status.get(context))
```

Example: [examples/python/dex_examples/products/order-processing](https://github.com/superdurable/dex/tree/main/examples/python/dex_examples/products/order-processing)

**Go**

```go
func (chargeStep) GetStepOptions() *dex.StepOptions {
	return &dex.StepOptions{
		ExecuteRetry: &dex.RetryPolicy{
			TotalDuration: time.Hour,
		},
	}
}

func (step chargeStep) Execute(
	ctx dex.Context,
	order OrderRequest,
) (*dex.StepDecision, error) {
	step.service.ChargeUser(order.Email, order.CustomerID, order.Amount)
	if err := OrderStatus.Set(ctx, "charged"); err != nil {
		return nil, err
	}
	return dex.GoTo(shipStep{}, order), nil
}

func (step shipStep) GetStepOptions() *dex.StepOptions {
	return &dex.StepOptions{
		ExecuteRetry: &dex.RetryPolicy{
			TotalDuration: time.Hour,
		},
		ExecuteFailure: dex.ProceedToOnExecuteFailure(
			refundStep{},
			&dex.StepOptions{
				ExecuteRetry: &dex.RetryPolicy{
					TotalDuration: time.Hour,
				},
			},
		),
	}
}

func (shipStep) WaitFor(
	dex.Context,
	OrderRequest,
) (*dex.Wait, error) {
	return dex.AnyOf(
		SellerOK.ForOne(),
		dex.Timer(24 * time.Hour),
	), nil
}

func (step shipStep) Execute(
	ctx dex.Context,
	order OrderRequest,
) (*dex.StepDecision, error) {
	if ctx.HasTimerFired() {
		step.service.SendEmail(
			order.Email,
			"Reminder: approve shipment",
			"Please approve or provide a tracking number.",
		)
		return dex.GoTo(shipStep{}, order), nil
	}
	if err := step.service.ShipItem(order.OrderID); err != nil {
		return nil, err
	}
	if err := OrderStatus.Set(ctx, "shipped"); err != nil {
		return nil, err
	}
	return dex.GracefulComplete("shipped:" + order.OrderID), nil
}

func (step refundStep) Execute(
	ctx dex.Context,
	order OrderRequest,
) (*dex.StepDecision, error) {
	step.service.UpdateExternalSystem("refund " + order.OrderID)
	if err := OrderStatus.Set(ctx, "refunded"); err != nil {
		return nil, err
	}
	return dex.GracefulComplete("refunded:" + order.OrderID), nil
}

type OrderProcessingFlow struct {
	dex.FlowDefaults
	service service.MyService
}

func NewOrderProcessingFlow(applicationService service.MyService) *OrderProcessingFlow {
	return &OrderProcessingFlow{service: applicationService}
}

func (flow *OrderProcessingFlow) GetSteps() []dex.StepDef {
	return []dex.StepDef{
		dex.DefineStartStep(chargeStep{service: flow.service}),
		dex.DefineStep(shipStep{service: flow.service}),
		dex.DefineStep(refundStep{service: flow.service}),
	}
}

func (flow *OrderProcessingFlow) GetRPCs() []dex.RPCDef {
	return []dex.RPCDef{
		dex.DefineRPC(flow.Approve, nil),
		dex.DefineRPC(flow.Describe, nil),
	}
}

func (*OrderProcessingFlow) GetPersistenceSchema() dex.PersistenceSchema {
	return dex.PersistenceSchema{
		Attributes: []dex.AttributeDef{OrderStatus},
		Channels:   []dex.ChannelDef{SellerOK},
	}
}

func (*OrderProcessingFlow) Approve(
	ctx dex.Context,
	_ string,
) (*dex.RPCResult[string], error) {
	if err := SellerOK.Publish(ctx, "approved"); err != nil {
		return nil, err
	}
	return &dex.RPCResult[string]{Output: "ok"}, nil
}

func (*OrderProcessingFlow) Describe(
	ctx dex.Context,
	_ dex.None,
) (*dex.RPCResult[string], error) {
	status, err := OrderStatus.Get(ctx)
	if err != nil {
		return nil, err
	}
	return &dex.RPCResult[string]{Output: status}, nil
}
```

Example: [examples/go/products/order-processing](https://github.com/superdurable/dex/tree/main/examples/go/products/order-processing)

**Java**

```java
public class OrderProcessingFlow implements Flow<OrderRequest> {
    public static final Attribute<String> orderStatus = Attribute.define(
            "order-status",
            String.class,
            new AttributeIndex(AttributeIndex.Type.KEYWORD, "keyword1"));
    public static final Channel<String> sellerOk = Channel.define("seller-ok", String.class);

    private final MyDependencyService service;
    private final ChargeStep charge;
    private final ShipStep ship;
    private final RefundStep refund;

    public OrderProcessingFlow(final MyDependencyService service) {
        this.service = service;
        this.refund = new RefundStep(service);
        this.ship = new ShipStep(service, this.refund);
        this.charge = new ChargeStep(service, this.ship);
    }

    @Override
    public StepList<OrderRequest> getSteps() {
        return StepList.startStep(charge).otherSteps(ship, refund);
    }

    @Override
    public PersistenceSchema getPersistenceSchema() {
        return PersistenceSchema.of(orderStatus, sellerOk);
    }

    @RPC
    public RPCResult<String> approve(final Context context, final String note) {
        sellerOk.publish(context, "approved");
        return RPCResult.of("ok");
    }

    @RPC
    public RPCResult<String> describe(final Context context) {
        return RPCResult.of(orderStatus.get(context));
    }

    static final class ChargeStep implements Step<OrderRequest> {
        private final MyDependencyService service;
        private final ShipStep ship;

        ChargeStep(final MyDependencyService service, final ShipStep ship) {
            this.service = service;
            this.ship = ship;
        }

        @Override
        public String getStepType() {
            return "ChargeStep";
        }

        @Override
        public Class<OrderRequest> getInputType() {
            return OrderRequest.class;
        }

        @Override
        public StepOptions getStepOptions() {
            return StepOptions.newBuilder()
                    .executeRetry(RetryPolicy.newBuilder()
                            .totalDuration(Duration.ofHours(1))
                            .build())
                    .build();
        }

        @Override
        public StepDecision execute(final Context context, final OrderRequest order) {
            service.chargeUser(order.email, order.customerId, order.amount);
            orderStatus.set(context, "charged");
            return StepDecision.goTo(ShipStep.class, order);
        }
    }

    static final class ShipStep implements Step<OrderRequest> {
        private final MyDependencyService service;
        private final RefundStep refund;

        ShipStep(final MyDependencyService service, final RefundStep refund) {
            this.service = service;
            this.refund = refund;
        }

        @Override
        public String getStepType() {
            return "ShipStep";
        }

        @Override
        public Class<OrderRequest> getInputType() {
            return OrderRequest.class;
        }

        @Override
        public StepOptions getStepOptions() {
            return StepOptions.newBuilder()
                    .executeRetry(RetryPolicy.newBuilder()
                            .totalDuration(Duration.ofHours(1))
                            .build())
                    .onExecuteFailureProceedTo(
                            RefundStep.class,
                            StepOptions.newBuilder()
                                    .executeRetry(RetryPolicy.newBuilder()
                                            .totalDuration(Duration.ofHours(1))
                                            .build())
                                    .build())
                    .build();
        }

        @Override
        public Wait waitFor(final Context context, final OrderRequest order) {
            return Wait.anyOf(
                    sellerOk.forOne(),
                    Timer.byDuration(Duration.ofHours(24)));
        }

        @Override
        public StepDecision execute(final Context context, final OrderRequest order) {
            if (context.hasTimerFired()) {
                service.sendEmail(
                        order.email,
                        "Reminder: approve shipment",
                        "Please approve or provide a tracking number.");
                return StepDecision.goTo(ShipStep.class, order);
            }
            service.shipItem(order.orderId);
            orderStatus.set(context, "shipped");
            return StepDecision.gracefulComplete("shipped:" + order.orderId);
        }
    }

    static final class RefundStep implements Step<OrderRequest> {
        private final MyDependencyService service;

        RefundStep(final MyDependencyService service) {
            this.service = service;
        }

        @Override
        public String getStepType() {
            return "RefundStep";
        }

        @Override
        public Class<OrderRequest> getInputType() {
            return OrderRequest.class;
        }

        @Override
        public StepDecision execute(final Context context, final OrderRequest order) {
            service.updateExternalSystem("refund " + order.orderId);
            orderStatus.set(context, "refunded");
            return StepDecision.gracefulComplete("refunded:" + order.orderId);
        }
    }
}
```

Example: [examples/java/src/main/java/io/superdurable/dex/products/orderprocessing](https://github.com/superdurable/dex/tree/main/examples/java/src/main/java/io/superdurable/dex/products/orderprocessing)

**TypeScript**

```typescript
const orderStatus = new Attribute("order-status", stringCodec, {
  type: IndexType.KEYWORD,
  indexKey: "keyword1",
});
const sellerOk = new Channel("seller-ok", stringCodec);

export class OrderProcessingFlow implements Flow<OrderRequest> {
  public readonly charge: ChargeStep;
  public readonly ship: ShipStep;
  public readonly refund: RefundStep;

  public constructor(public readonly service: MyDependencyService) {
    this.refund = new RefundStep(service);
    this.ship = new ShipStep(service, this.refund);
    this.charge = new ChargeStep(service, this.ship);
  }

  public getFlowType(): string {
    return "OrderProcessingFlow";
  }

  public getSteps() {
    return StepList.startStep(this.charge).otherSteps(this.ship, this.refund);
  }

  public getPersistenceSchema(): PersistenceSchema {
    return {
      attributes: [orderStatus],
      channels: [sellerOk],
    };
  }

  @rpc({ inputCodec: stringCodec, outputCodec: stringCodec })
  public approve(context: Context, _note: string): RPCResult<string> {
    sellerOk.publish(context, "approved");
    return { output: "ok" };
  }

  @rpc({ outputCodec: stringCodec })
  public describe(context: Context): RPCResult<string> {
    return { output: orderStatus.get(context) };
  }
}

class ChargeStep implements Step<OrderRequest> {
  public readonly inputCodec = orderRequestCodec;

  public constructor(
    private readonly service: MyDependencyService,
    private readonly ship: ShipStep,
  ) {}

  public getStepType(): string {
    return "ChargeStep";
  }

  public getStepOptions() {
    return {
      executeRetry: {
        totalDurationMs: 60 * 60 * 1000,
      },
    };
  }

  public execute(context: Context, input: OrderRequest): StepDecision {
    this.service.chargeUser(input.email, input.customerId, input.amount);
    orderStatus.set(context, "charged");
    return goTo(ShipStep, input);
  }
}

class ShipStep implements Step<OrderRequest> {
  public readonly inputCodec = orderRequestCodec;

  public constructor(
    private readonly service: MyDependencyService,
    private readonly refund: RefundStep,
  ) {}

  public getStepType(): string {
    return "ShipStep";
  }

  public getStepOptions() {
    return {
      executeRetry: {
        totalDurationMs: 60 * 60 * 1000,
      },
      executeFailure: ExecuteFailure.proceedTo(RefundStep, {
        executeRetry: {
          totalDurationMs: 60 * 60 * 1000,
        },
      }),
    };
  }

  public waitFor(_context: Context, _input: OrderRequest): Wait {
    return Wait.anyOf(sellerOk.forOne(), Timer.byDuration(DAY_MS));
  }

  public execute(context: Context, input: OrderRequest): StepDecision {
    if (context.hasTimerFired()) {
      this.service.sendEmail(
        input.email,
        "Reminder: approve shipment",
        "Please approve or provide a tracking number.",
      );
      return goTo(ShipStep, input);
    }
    this.service.shipItem(input.orderId);
    orderStatus.set(context, "shipped");
    return gracefulComplete(`shipped:${input.orderId}`);
  }
}

class RefundStep implements Step<OrderRequest> {
  public readonly inputCodec = orderRequestCodec;

  public constructor(private readonly service: MyDependencyService) {}

  public getStepType(): string {
    return "RefundStep";
  }

  public execute(context: Context, input: OrderRequest): StepDecision {
    this.service.updateExternalSystem(`refund ${input.orderId}`);
    orderStatus.set(context, "refunded");
    return gracefulComplete(`refunded:${input.orderId}`);
  }
}
```

Example: [examples/typescript/src/products/order-processing](https://github.com/superdurable/dex/tree/main/examples/typescript/src/products/order-processing)

**Rust**

```rust
#[derive(Clone)]
pub struct OrderProcessingFlow {
    charge: Charge,
    ship: Ship,
    refund: Refund,
}

impl OrderProcessingFlow {
    pub fn new(service: MyDependencyService) -> Self {
        Self {
            charge: Charge {
                service: service.clone(),
            },
            ship: Ship {
                service: service.clone(),
            },
            refund: Refund { service },
        }
    }

    fn approve(&self, context: &mut Context, _note: String) -> HandlerResult<RpcResult<String>> {
        SELLER_OK.publish(context, "approved".to_string())?;
        Ok(RpcResult::new("ok".to_string()))
    }

    fn describe(&self, context: &mut Context) -> HandlerResult<RpcResult<String>> {
        Ok(RpcResult::new(ORDER_STATUS.get_required(context)?))
    }
}

impl Default for OrderProcessingFlow {
    fn default() -> Self {
        Self::new(MyDependencyService)
    }
}

impl Flow for OrderProcessingFlow {
    type StartInput = OrderRequest;

    fn flow_type(&self) -> &'static str {
        "OrderProcessingFlow"
    }

    fn steps(&self) -> StepList<'_, Self::StartInput> {
        StepList::start(&self.charge)
            .and(&self.ship)
            .and(&self.refund)
    }

    fn persistence(&self) -> PersistenceSchema {
        PersistenceSchema::new()
            .attribute(&ORDER_STATUS)
            .channel(&SELLER_OK)
    }

    fn rpcs(&self) -> RpcList<Self> {
        RpcList::new()
            .function(APPROVE_ORDER, Self::approve)
            .function_without_input(DESCRIBE_ORDER, Self::describe)
    }
}

#[derive(Clone, Default)]
pub struct Charge {
    service: MyDependencyService,
}

impl Step for Charge {
    type Input = OrderRequest;

    fn step_type(&self) -> &'static str {
        "ChargeStep"
    }

    fn options(&self) -> StepOptions<Self::Input> {
        StepOptions::new().execute_retry(
            RetryPolicy::new().total_duration(Duration::from_secs(60 * 60)),
        )
    }

    fn execute(&self, context: &mut Context, input: Self::Input) -> HandlerResult<StepDecision> {
        self.service
            .charge_user(&input.email, &input.customer_id, input.amount);
        context.record_event("charge", input.order_id.clone())?;
        ORDER_STATUS.set(context, "charged".to_string())?;
        Ok(StepDecision::go_to(&Ship::default(), input))
    }
}

#[derive(Clone, Default)]
pub struct Ship {
    service: MyDependencyService,
}

impl Step for Ship {
    type Input = OrderRequest;

    fn step_type(&self) -> &'static str {
        "ShipStep"
    }

    fn options(&self) -> StepOptions<Self::Input> {
        StepOptions::new()
            .execute_retry(
                RetryPolicy::new().total_duration(Duration::from_secs(60 * 60)),
            )
            .on_execute_failure_proceed_to(&Refund::default())
    }

    fn wait_for(&self, _context: &mut Context, _input: Self::Input) -> HandlerResult<Wait> {
        Ok(Wait::any_of([
            SELLER_OK.for_one(),
            Timer::by_duration(Duration::from_secs(24 * 60 * 60)),
        ]))
    }

    fn execute(&self, context: &mut Context, input: Self::Input) -> HandlerResult<StepDecision> {
        if context.has_any_timer_fired() {
            self.service.send_email(
                &input.email,
                "Reminder: approve shipment",
                "Please approve or provide a tracking number.",
            );
            context.record_event("shipment-reminder", input.order_id.clone())?;
            return Ok(StepDecision::go_to(&Ship::default(), input));
        }
        self.service.ship_item(&input.order_id)?;
        context.record_event("ship", input.order_id.clone())?;
        ORDER_STATUS.set(context, "shipped".to_string())?;
        Ok(StepDecision::graceful_complete(format!(
            "shipped:{}",
            input.order_id
        )))
    }
}

#[derive(Clone, Default)]
pub struct Refund {
    service: MyDependencyService,
}

impl Step for Refund {
    type Input = OrderRequest;

    fn step_type(&self) -> &'static str {
        "RefundStep"
    }

    fn options(&self) -> StepOptions<Self::Input> {
        StepOptions::new().execute_retry(
            RetryPolicy::new().total_duration(Duration::from_secs(60 * 60)),
        )
    }

    fn execute(&self, context: &mut Context, input: Self::Input) -> HandlerResult<StepDecision> {
        self.service
            .update_external_system(&format!("refund {}", input.order_id));
        context.record_event("refund", input.order_id.clone())?;
        ORDER_STATUS.set(context, "refunded".to_string())?;
        Ok(StepDecision::graceful_complete(format!(
            "refunded:{}",
            input.order_id
        )))
    }
}

static ORDER_STATUS: LazyLock<Attribute<String>> = LazyLock::new(|| {
    Attribute::new("order-status").indexed(AttributeIndex::keyword().with_key("keyword1"))
});

static SELLER_OK: LazyLock<Channel<String>> = LazyLock::new(|| Channel::new("seller-ok"));
```

Example: [examples/rust/src/products/order_processing](https://github.com/superdurable/dex/tree/main/examples/rust/src/products/order_processing)

Frontend wait for “payment received”. **GET /products/order-processing/start** starts the Flow, then waits for ChargeStep before it returns:

**Python**

```python
        run_id = await app_state.client.start_flow(
            app_state.order_processing,
            flow_id,
            request,
            start_options(),
        )
        await app_state.client.wait_for_step_completion(
            flow_id,
            CHARGE_STEP,
            CHARGE_WAIT_TIMEOUT,
        )
        return started_flow(flow_id, run_id)
```

Example: [examples/python/dex_examples/products/order-processing](https://github.com/superdurable/dex/tree/main/examples/python/dex_examples/products/order-processing)

**Go**

```go
	runID, err := controller.client.StartFlow(
		request.Request.Context(),
		controller.flow,
		flowID,
		input,
		sdk.StartFlowOptions{},
	)
	if err != nil {
		httputil.Respond(request, nil, err)
		return
	}
	err = controller.client.WaitForStepCompletion(
		request.Request.Context(),
		flowID,
		sdk.StepExecutionID{StepType: ChargeStepType},
		sdk.WaitOptions{Timeout: 5 * time.Minute},
	)
	httputil.Respond(request, gin.H{"flowID": flowID, "runID": runID}, err)
```

Example: [examples/go/products/order-processing](https://github.com/superdurable/dex/tree/main/examples/go/products/order-processing)

**Java**

```java
        final String runId = client.startFlow(flow, flowId, request, ExampleFlows.startOptions());
        client.waitForStepCompletion(
                flowId,
                StepExecutionId.of("ChargeStep"),
                Duration.ofMinutes(5));
        final Map<String, String> response = new LinkedHashMap<String, String>();
        response.put("flowID", flowId);
        response.put("runID", runId);
        return ResponseEntity.ok(response);
```

Example: [examples/java/src/main/java/io/superdurable/dex/products/orderprocessing](https://github.com/superdurable/dex/tree/main/examples/java/src/main/java/io/superdurable/dex/products/orderprocessing)

**TypeScript**

```typescript
    const runId = await client.startFlow(flow, flowId, input, startOptions());
    await client.waitForStepCompletion(
      flowId,
      StepExecutionId.of("ChargeStep"),
      5 * 60 * 1000,
    );
    response.json({ flowID: flowId, runID: runId });
```

Example: [examples/typescript/src/products/order-processing](https://github.com/superdurable/dex/tree/main/examples/typescript/src/products/order-processing)

**Rust**

```rust
        let run_id = client.start_flow(&flow, &flow_id, input)?;
        client.wait_for_step_completion(
            &flow_id,
            StepExecutionId::of(&Charge::default()),
            Duration::from_secs(300),
        )?;
        Ok(StartResponse { flow_id, run_id })
```

Example: [examples/rust/src/products/order_processing](https://github.com/superdurable/dex/tree/main/examples/rust/src/products/order_processing)

Step transitions are atomic. Timers and Channel waits survive Worker restarts. Retries and compensation are declared on the Step.

## How this differs from traditional Durable Execution

Traditional Durable Execution runs workflow functions by **replaying** event history. Side effects go in **activities**. You must split business logic into **workflow code** and **activity code**. Those two are completely different paradigms. The workflow code must stay **deterministic**: no extra clocks, random, or IO in the replayed function. Event history has a **size constraint**. That history is also a poor store for application data: large payloads are expensive and slow.

Replay-based Durable Execution must expose a large set of APIs to simulate a programming model. Those APIs introduce many implicit contracts and interfaces. They are hard to understand and maintain.

Dex does not ask you to write a replayable workflow function. You declare Steps and movements. Worker handlers are ordinary code. Waits, RPC, and locking are part of the Flow model, not something you reconstruct from history primitives. **Attribute** data lives in a **blob store**, not in event history. You can sync it to a database you already run.

## Next steps

- [Primitives](https://docs.superdurable.io/primitives.md) — Step, Attribute, Channel, Timer, RPC, Client APIs
- [Design Patterns](https://docs.superdurable.io/design-patterns.md) — reusable Flow shapes
- [Product Examples](https://docs.superdurable.io/use-cases.md) — fuller product examples
