summaryrefslogtreecommitdiff
path: root/app/workers/error_tracking_issue_link_worker.rb
blob: 37a3a1e7bcbf7f6c9e0ff3eab39c81150c35f993 (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
88
89
90
91
# frozen_string_literal: true

# Creates a link in Sentry between a Sentry issue and a GitLab issue.
# If the link already exists, no changes will occur.
# If a link to a different GitLab issue exists, a new link
#   will still be created, but will not be visible in Sentry
#   until the prior link is deleted.
class ErrorTrackingIssueLinkWorker # rubocop:disable Scalability/IdempotentWorker
  include ApplicationWorker

  data_consistency :always

  sidekiq_options retry: 3
  include ExclusiveLeaseGuard
  include Gitlab::Utils::StrongMemoize

  feature_category :error_tracking
  worker_has_external_dependencies!

  LEASE_TIMEOUT = 15.minutes

  attr_reader :issue

  def perform(issue_id)
    @issue = Issue.find_by_id(issue_id)

    return unless valid?

    try_obtain_lease do
      logger.info("Linking Sentry issue #{sentry_issue_id} to GitLab issue #{issue.id}")

      sentry_client.create_issue_link(integration_id, sentry_issue_id, issue)
    rescue ErrorTracking::SentryClient::Error => e
      logger.info("Failed to link Sentry issue #{sentry_issue_id} to GitLab issue #{issue.id} with error: #{e.message}")
    end
  end

  private

  def valid?
    issue && error_tracking && sentry_issue_id
  end

  def error_tracking
    strong_memoize(:error_tracking) do
      issue.project.error_tracking_setting
    end
  end

  def sentry_issue_id
    strong_memoize(:sentry_issue_id) do
      issue.sentry_issue.sentry_issue_identifier
    end
  end

  def sentry_client
    error_tracking.sentry_client
  end

  def integration_id
    strong_memoize(:integration_id) do
      repo&.integration_id
    end
  end

  def repo
    sentry_client
      .repos(organization_slug)
      .find { |repo| repo.project_id == issue.project_id && repo.status == 'active' }
  rescue ErrorTracking::SentryClient::Error => e
    logger.info("Unable to retrieve Sentry repo for organization #{organization_slug}, id #{sentry_issue_id}, with error: #{e.message}")

    nil
  end

  def organization_slug
    error_tracking.organization_slug
  end

  def project_url
    ::Gitlab::Routing.url_helpers.project_url(issue.project)
  end

  def lease_key
    "link_sentry_issue_#{sentry_issue_id}_gitlab_#{issue.id}"
  end

  def lease_timeout
    LEASE_TIMEOUT
  end
end