Circuit Breaker erklärt anhand eines Fehlers

Vor ein paar Tagen bin ich auf ein unerwartetes Problem gestoßen.

Frustration packte mich hart. Ich wollte es beheben. Die Neugier trieb mich dazu, weiterzumachen.

Ich setzte mich erneut mit dem Problem auseinander. Ich fand die Lösung. Sie heißt Circuit Breaker.

In der Softwareentwicklung verhindert ein Circuit Breaker, dass ein einzelner Fehler das gesamte System zum Absturz bringt. Er funktioniert wie der Sicherungsautomat in deinem Zuhause.

Ein Circuit Breaker hat drei Zustände:

  • CLOSED: Alles funktioniert. Alle Anfragen werden durchgelassen. Das System protokolliert Fehler. Wenn die Fehler ein Limit erreichen, öffnet sich der Schaltkreis.
  • OPEN: Das System stoppt sofort alle Anfragen. Dies gibt dem fehlerhaften Dienst Zeit, sich zu erholen.
  • HALF_OPEN: Das System lässt einige Testanfragen zu. Wenn diese erfolgreich sind, schließt sich der Schaltkreis. Wenn sie fehlschlagen, öffnet er sich wieder.

Hier ist eine einfache Implementierung in Code:

    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
        }