Welcome to mirror list, hosted at ThFree Co, Russian Federation.

log_execution_service.rb « web_hooks « services « app - gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: b1da0c1642f140c8d996b819d3fefa25bce874af (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
70
71
72
73
74
75
76
77
78
79
# frozen_string_literal: true

module WebHooks
  class LogExecutionService
    include ::Gitlab::ExclusiveLeaseHelpers

    LOCK_TTL = 15.seconds.freeze
    LOCK_SLEEP = 0.25.seconds.freeze
    LOCK_RETRY = 65

    attr_reader :hook, :log_data, :response_category

    def initialize(hook:, log_data:, response_category:)
      @hook = hook
      @log_data = log_data.transform_keys(&:to_sym)
      @response_category = response_category
    end

    def execute
      update_hook_failure_state
      log_execution
    end

    private

    def log_execution
      mask_response_headers

      log_data[:request_headers]['X-Gitlab-Token'] = _('[REDACTED]') if hook.token?

      WebHookLog.create!(web_hook: hook, **log_data)
    end

    def mask_response_headers
      return unless hook.url_variables?
      return unless log_data.key?(:response_headers)

      variables_map = hook.url_variables.invert.transform_values { "{#{_1}}" }
      regex = Regexp.union(variables_map.keys)

      log_data[:response_headers].transform_values! do |value|
        regex === value ? value.gsub(regex, variables_map) : value
      end
    end

    # Perform this operation within an `Gitlab::ExclusiveLease` lock to make it
    # safe to be called concurrently from different workers.
    def update_hook_failure_state
      in_lock(lock_name, ttl: LOCK_TTL, sleep_sec: LOCK_SLEEP, retries: LOCK_RETRY) do |retried|
        hook.reset # Reload within the lock so properties are guaranteed to be current.

        case response_category
        when :ok
          hook.enable!
        when :error
          hook.backoff!
        when :failed
          hook.failed!
        end

        hook.update_last_failure
      end
    rescue Gitlab::ExclusiveLeaseHelpers::FailedToObtainLockError
      raise if raise_lock_error?
    end

    def lock_name
      "web_hooks:update_hook_failure_state:#{hook.id}"
    end

    # Allow an error to be raised after failing to obtain a lease only if the hook
    # is not already in the correct failure state.
    def raise_lock_error?
      hook.reset # Reload so properties are guaranteed to be current.

      hook.executable? != (response_category == :ok)
    end
  end
end