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: 0ee7c41469fe40459b0d527c180efaeedd097c23 (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
80
81
82
83
84
85
86
87
# 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
      @prev_state = hook.active_state(ignore_flag: true)
    end

    def execute
      update_hook_failure_state
      log_execution
    end

    private

    def log_execution
      WebHookLog.create!(web_hook: hook, **log_data)
    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

        log_state_change
      end
    rescue Gitlab::ExclusiveLeaseHelpers::FailedToObtainLockError
      raise if raise_lock_error?
    end

    def log_state_change
      new_state = hook.active_state(ignore_flag: true)

      return if @prev_state == new_state

      Gitlab::AuthLogger.info(
        message: 'WebHook change active_state',
        # identification
        hook_id: hook.id,
        hook_type: hook.type,
        project_id: hook.project_id,
        group_id: hook.group_id,
        # relevant data
        prev_state: @prev_state,
        new_state: new_state,
        duration: log_data[:execution_duration],
        response_status: log_data[:response_status],
        recent_hook_failures: hook.recent_failures,
        # context
        **Gitlab::ApplicationContext.current
      )
    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