Skip to content
All essays
CraftApril 5, 202410 min

Building High-Availability Systems

Learn strategies for building systems that stay available even during failures

Ü
Ümit Uz
Mobile & Full Stack Developer

High availability means your system remains operational even when components fail. Let's explore the key patterns.

Redundancy

Remove single points of failure:

typescript
class RedundantService {
  private instances: Service[] = [];

  async call(): Promise<Response> {
    // Try primary
    try {
      return await this.instances[0].execute();
    } catch (error) {
      // Fallback to backup
      return await this.instances[1].execute();
    }
  }
}

Health Checks

Monitor service health:

typescript
class HealthChecker {
  async checkService(service: Service): Promise<boolean> {
    try {
      const response = await fetch(service.healthEndpoint);
      return response.ok;
    } catch {
      return false;
    }
  }

  async checkAll(): Promise<HealthStatus> {
    const results = await Promise.all(
      this.services.map(async s => ({
        service: s.name,
        healthy: await this.checkService(s)
      }))
    );
    return { services: results };
  }
}

Circuit Breakers

Prevent cascading failures:

typescript
class CircuitBreaker {
  private failures = 0;
  private lastFailureTime = 0;
  private state: 'closed' | 'open' | 'half-open' = 'closed';

  async execute(fn: () => Promise<any>): Promise<any> {
    if (this.state === 'open') {
      if (Date.now() - this.lastFailureTime > 60000) {
        this.state = 'half-open';
      } else {
        throw new Error('Circuit breaker is open');
      }
    }

    try {
      const result = await fn();
      this.onSuccess();
      return result;
    } catch (error) {
      this.onFailure();
      throw error;
    }
  }

  private onSuccess() {
    this.failures = 0;
    if (this.state === 'half-open') {
      this.state = 'closed';
    }
  }

  private onFailure() {
    this.failures++;
    this.lastFailureTime = Date.now();
    if (this.failures >= 5) {
      this.state = 'open';
    }
  }
}

Conclusion

High availability requires redundancy, monitoring, and automatic failover.

Related essays

Next essay
Horizontal Scaling: Strategies for Growing Systems