Back to KB
Difficulty
Intermediate
Read Time
8 min

Building reliable distributed workflows in TypeScript with HazelJS Sagas

By Codcompass Team··8 min read

Current Situation Analysis

Modern backend architectures rarely confine a single business operation to one database. A checkout flow touches a payment gateway, an inventory system, and a notification provider. A SaaS onboarding sequence provisions a tenant, allocates cloud resources, and configures access controls. These systems operate independently, expose REST or gRPC endpoints, and maintain their own transaction logs. They do not share a global lock.

Developers frequently approach these distributed pipelines with a monolithic mindset. They wrap the sequence in nested try/catch blocks, sprinkle manual cleanup logic, and hope that error paths remain synchronized. This approach fractures under production load. When a payment processor times out after inventory is reserved, the system either leaks resources (orphaned holds) or double-charges customers on retry. The core misunderstanding is treating distributed workflows as if they require strict ACID guarantees. In reality, cross-boundary operations demand eventual consistency paired with explicit failure recovery.

Two-phase commit (2PC) theoretically solves this, but it requires every participant to support a distributed transaction coordinator. Third-party vendors, legacy PMS systems, and cloud APIs rarely expose this capability. The industry standard for bridging this gap is the Saga pattern. Instead of a single atomic commit, a saga decomposes the workflow into discrete local steps. Each step that modifies external state is paired with a compensating action. If the pipeline fails mid-execution, the orchestrator triggers compensators in reverse order, restoring business consistency without requiring vendor-level transaction support.

WOW Moment: Key Findings

The trade-off between traditional transactional models and saga orchestration becomes stark when measured against real-world operational metrics. The following comparison illustrates why sagas dominate cross-service workflows:

ApproachConsistency ModelRollback ComplexityCross-Vendor CompatibilityDebugging Overhead
Local ACID TransactionStrong (all-or-nothing)Low (database handles it)None (single system boundary)Minimal
Ad-Hoc Error HandlingNone (manual cleanup)High (fragile, divergent paths)HighVery High
Saga OrchestrationEventual (compensating actions)Medium (explicit by design)HighLow (centralized flow)

This finding matters because it shifts the engineering focus from preventing failure to designing recovery. Sagas acknowledge that network partitions, API rate limits, and third-party outages are inevitable. By encoding compensators as first-class citizens alongside forward steps, teams gain predictable rollback behavior, simplified incident response, and a single source of truth for workflow state. This enables reliable checkout, provisioning, and booking flows without demanding architectural concessions from external vendors.

Core Solution

Implementing a saga requires three components: a state container, a decorated workflow class, and an orchestrator that manages execution and compensation. We will build a SaaS tenant provisioning pipeline using @hazeljs/saga. The flow creates a tenant record, provisions a dedicated database instance, and sends a welcome notification. If provisioning fails, the tenant record is archived and the database allocation is revoked.

🎉 Mid-Year Sale — Unlock Full Article

Base plan from just $4.99/mo or $49/yr

Sign in to read the full article and unlock all 635+ tutorials.

Sign In / Register — Start Free Trial

7-day free trial · Cancel anytime · 30-day money-back