File size: 2,303 Bytes
3e21b19
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
defmodule ObanErrorReporter do
  use Plausible
  require Logger

  def handle_event(name, measurements, metadata, _) do
    # handling telemetry event in a try/catch block
    # to avoid handler detachment in the case of an error
    # see https://hexdocs.pm/telemetry/telemetry.html#attach/4
    try do
      handle_event(name, measurements, metadata)
    catch
      kind, reason ->
        message = Exception.format(kind, reason, __STACKTRACE__)
        Logger.error(message)
    end
  end

  defp handle_event([:oban, :job, :exception], measure, %{job: job} = meta) do
    extra =
      job
      |> Map.take([:id, :args, :meta, :queue, :worker])
      |> Map.merge(measure)

    on_job_exception(job)
    capture_error(meta, extra)
  end

  defp handle_event([:oban, :notifier, :exception], _timing, meta) do
    extra = Map.take(meta, ~w(channel payload)a)
    capture_error(meta, extra)
  end

  defp handle_event([:oban, :plugin, :exception], _timing, meta) do
    extra = Map.take(meta, ~w(plugin)a)
    capture_error(meta, extra)
  end

  defp on_job_exception(%Oban.Job{
         queue: "analytics_imports",
         args: %{"import_id" => import_id},
         state: "executing",
         attempt: attempt,
         max_attempts: max_attempts
       })
       when attempt >= max_attempts do
    site_import = Plausible.Repo.get(Plausible.Imported.SiteImport, import_id)

    if site_import do
      Plausible.Workers.ImportAnalytics.import_fail(site_import, [])
    end
  end

  defp on_job_exception(%Oban.Job{
         queue: "analytics_imports",
         args: %{"import_id" => import_id},
         state: "executing"
       }) do
    site_import = Plausible.Repo.get(Plausible.Imported.SiteImport, import_id)

    if site_import do
      Plausible.Workers.ImportAnalytics.import_fail_transient(site_import)
    end
  end

  defp on_job_exception(_job), do: :ignore

  # Logs the error and sends it to Sentry
  defp capture_error(meta, extra) do
    Logger.error(
      # this message is ignored by Sentry
      "Background job (#{inspect(extra)}) failed:\n\n  " <>
        Exception.format(:error, meta.reason, meta.stacktrace),
      # Sentry report is built entirely from crash_reason
      crash_reason: {meta.reason, meta.stacktrace},
      sentry: %{extra: extra}
    )
  end
end