summaryrefslogtreecommitdiff
path: root/app/models/concerns/web_hooks/auto_disabling.rb
blob: 2cc17a6f185783a9869395523a0fd81ba8f32ea1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# frozen_string_literal: true

module WebHooks
  module AutoDisabling
    extend ActiveSupport::Concern

    included do
      # A hook is disabled if:
      #
      # - we are no longer in the grace-perod (recent_failures > ?)
      # - and either:
      #   - disabled_until is nil (i.e. this was set by WebHook#fail!)
      #   - or disabled_until is in the future (i.e. this was set by WebHook#backoff!)
      scope :disabled, -> do
        where('recent_failures > ? AND (disabled_until IS NULL OR disabled_until >= ?)',
              WebHook::FAILURE_THRESHOLD, Time.current)
      end

      # A hook is executable if:
      #
      # - we are still in the grace-period (recent_failures <= ?)
      # - OR we have exceeded the grace period and neither of the following is true:
      #   - disabled_until is nil (i.e. this was set by WebHook#fail!)
      #   - disabled_until is in the future (i.e. this was set by WebHook#backoff!)
      scope :executable, -> do
        where('recent_failures <= ? OR (recent_failures > ? AND (disabled_until IS NOT NULL) AND (disabled_until < ?))',
              WebHook::FAILURE_THRESHOLD, WebHook::FAILURE_THRESHOLD, Time.current)
      end
    end

    def executable?
      !temporarily_disabled? && !permanently_disabled?
    end

    def temporarily_disabled?
      return false if recent_failures <= WebHook::FAILURE_THRESHOLD

      disabled_until.present? && disabled_until >= Time.current
    end

    def permanently_disabled?
      return false if disabled_until.present?

      recent_failures > WebHook::FAILURE_THRESHOLD
    end

    def disable!
      return if permanently_disabled?

      super
    end

    def backoff!
      return if permanently_disabled? || (backoff_count >= WebHook::MAX_FAILURES && temporarily_disabled?)

      super
    end

    def alert_status
      if temporarily_disabled?
        :temporarily_disabled
      elsif permanently_disabled?
        :disabled
      else
        :executable
      end
    end
  end
end