Skip to content

Distributed Workflows

When your application grows, you need to ensure your workflows are safe across multiple instances and can handle high concurrency.

Cross-Instance Safety

By default, Orchestrix runs workflows in-process. To ensure that two different instances of your app don't process the same request at the same time, you must use Distributed Idempotency.

Redis Adapter

The Redis adapter uses atomic operations to "lock" an idempotency key before execution.

ts
import { createRedisIdempotencyStore } from "@eddiecbrl/orchestrix/adapters/redis";

const store = createRedisIdempotencyStore(redisClient);
const flow = create("my-flow", { idempotency: store });

Handling Concurrency

If a second request with the same idempotency key arrives while the first one is still running:

  1. Default: Orchestrix returns a running status and does not re-execute.
  2. throwIfRunning: You can configure it to throw an error so your API can return a 409 Conflict.
ts
await flow.run(input, {
  key: "abc",
  throwIfRunning: true
});

Resilience vs. Throughput

  • More Retries: Improves resilience but increases the "hold time" of resources and can decrease overall throughput.
  • Short Timeouts: Improves throughput and fail-fast behavior but can lead to more frequent compensations if your downstream services are just slightly slow.

The Role of Message Queues

Orchestrix is often used inside a consumer of a message queue (like RabbitMQ or SQS).

  1. Message Arrives: Queue delivers message to Worker instance.
  2. Orchestrix Runs: The worker uses Orchestrix to execute the multi-step business logic.
  3. Ack/Nack: Based on the FlowResult, the worker acknowledges the message or returns it to the queue for a full retry.

Using Orchestrix's internal retries before returning the message to the queue is usually more efficient for transient network issues.

Released under the MIT License.