Distributed Deadlock Detection: The Chandy-Misra-Haas Algorithm in Microservices

In complex microservice architectures executing multi-resource transactions (e.g. reserving inventory across sharded SQL databases, acquiring Redis Redlock leases, and reserving payment holds), circular dependencies can create catastrophic distributed deadlocks. The Chandy-Misra-Haas (CMH) edge-chasing algorithm provides decentralized, asynchronous deadlock detection by propagating lightweight probe messages along the edges of the distributed Wait-For-Graph (WFG) without requiring a centralized lock coordinator.

The Architecture of Edge-Chasing Probe Propagation

How probe messages detect circular dependencies without global synchronization:

⚡ The Probe Reflection Invariant

When process $P_i$ is blocked waiting for resource $R$ held by process $P_j$, $P_i$ initiates a probe $(i, j, k)$ where $i$ is the initiator, $j$ is the sender, and $k$ is the recipient. If $P_k$ is transitively blocked on $P_m$, it forwards probe $(i, k, m)$. If process $P_i$ ever receives a probe carrying its own initiator ID $(i, *, i)$, a circular dependency is mathematically proven, prompting $P_i$ to abort and release its held locks.

Deadlock Resolution Strategies Compared

Resolution Strategy Architecture Model Message Overhead False Deadlock Rate
Lock Lease TTL TimeoutsOptimistic timeout expirationZero network probe overheadHigh (Aborts valid slow transactions)
Centralized WFG CoordinatorGlobal lock manager serviceHigh ($O(N)$ lock state reporting)Moderate (State lag during failovers)
Chandy-Misra-Haas Edge ChasingDecentralized Asynchronous ProbingLow (Probes sent only when blocked)Zero Phantom Deadlocks

Chandy-Misra-Haas Probe Handler in TypeScript

Asynchronously forwarding edge-chasing probes in distributed microservices:

export interface CMHProbe {
  initiatorId: string;
  senderId: string;
  recipientId: string;
}

export class DistributedLockAgent {
  private holdingProcessId: string;
  private waitingOnProcessIds: Set<string> = new Set();

  constructor(holdingProcessId: string) {
    this.holdingProcessId = holdingProcessId;
  }

  public handleIncomingProbe(probe: CMHProbe): { isDeadlocked: boolean; forwardedProbes: CMHProbe[] } {
    // Check if probe returned to initiator
    if (probe.initiatorId === this.holdingProcessId) {
      return { isDeadlocked: true, forwardedProbes: [] };
    }

    // Forward probe along all outgoing Wait-For-Graph edges
    const forwardedProbes: CMHProbe[] = [];
    for (const targetProcessId of this.waitingOnProcessIds) {
      forwardedProbes.push({
        initiatorId: probe.initiatorId,
        senderId: this.holdingProcessId,
        recipientId: targetProcessId
      });
    }

    return { isDeadlocked: false, forwardedProbes };
  }
}

Explore Advanced Distributed Engineering & Architecture

Build resilient distributed systems with provable concurrency guarantees. Read our guide on Deterministic Time-Travel Debugging & Record-and-Replay, explore cross-currency swap modeling on FinanceQuickly XCCY Collateral, review telematics spoliation on CarInjuryAttorney HOS Forensics, or consult with our distributed systems architects.