Объяснение паттерна Circuit Breaker на примере сбоя

Несколько дней назад я столкнулся с неожиданной проблемой.

Я был крайне раздосадован. Мне хотелось это исправить. Любопытство заставляло меня двигаться дальше.

Я снова сел за решение проблемы. И нашел решение. Оно называется circuit breaker.

В программном обеспечении circuit breaker предотвращает падение всей системы из-за одной ошибки. Он работает так же, как автоматический выключатель у вас дома.

У circuit breaker есть три состояния:

  • CLOSED: Все работает. Все запросы проходят. Система отслеживает ошибки. Если количество ошибок достигает лимита, цепь размыкается.
  • OPEN: Система немедленно прекращает все запросы. Это дает сбойному сервису время на восстановление.
  • HALF_OPEN: Система пропускает несколько тестовых запросов. Если они проходят успешно, цепь замыкается. Если нет — цепь снова размыкается.

Here is a simple implementation in code:

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