失敗から学ぶサーキットブレーカーの仕組み

数日前、予期せぬ問題に直面しました。

強い挫折感を感じました。どうしても解決したかった。そして、好奇心に駆られて、調査を続けました。

再び問題に向き合い、解決策を見つけました。それは「サーキットブレーカー(Circuit Breaker)」と呼ばれるものです。

ソフトウェアにおけるサーキットブレーカーは、単一の障害がシステム全体をクラッシュさせるのを防ぎます。これは、家庭にあるブレーカーと同じ仕組みです。

サーキットブレーカーには3つの状態があります:

  • CLOSED: すべてが正常に動作しています。すべてのリクエストが通過します。システムは失敗を追跡します。失敗が制限に達すると、回路が開きます。
  • OPEN: システムは即座にすべてのリクエストを停止します。これにより、障害が発生しているサービスが回復するための時間が確保されます。
  • HALF_OPEN: システムは少数のテストリクエストを許可します。それらが成功すれば回路は閉じ、失敗すれば再び回路が開きます。

以下は、コードによる簡単な実装例です:

export class CircuitBreaker {
    constructor(failureThreshold, cooldownMs) {
        this.failureThreshold = failureThreshold
        this.cooldownMs = cooldownMs
        this.state = "CLOSED"
        this.failureCount = 0
        this.lastFailureTime = null
    }

    openCircuit() {
        this.state = "OPEN"
        this.lastFailureTime = Date.now()
    }

    closeCircuit() {
        this.state = "CLOSED"
        this.failureCount = 0
        this.lastFailureTime = null
    }

    halfOpenCircuit() {
        this.state = "HALF_OPEN"
    }

    async execute(fn) {
        if (this.state === "OPEN") {
            const cooldownExpired = Date.now() - this.lastFailureTime >= this.cooldownMs
            if (!cooldownExpired) {
                throw new Error("Circuit is open.")
            }
            this.halfOpenCircuit();
        }

        try {
            const result = await fn()
            if (this.state === "HALF_OPEN") {
                this.closeCircuit()
            }
            return result;
        } catch (error) {
            if (this.state === "HALF_OPEN") {
                this.openCircuit()
                throw error;
            }
            this.failureCount++
            if (this.failureCount >= this.failureThreshold) {
                this.openCircuit()
            }
            throw error
        }
    }
}

この仕組みによって、最近の問題は解決しました。エラーの氾濫によってアプリケーションが停止してしまうのを防いでくれます。

ぜひコメント欄で感想を聞かせてください。私はまだ勉強中です。

出典: https://dev.to/neel-vekariya/circuit-breaker-explained-through-real-failure-experience-3aeg