|
1 | 1 | defmodule Sentry.Integrations.Oban.Cron do |
2 | | - @moduledoc false |
| 2 | + @moduledoc """ |
| 3 | + This module provides built-in integration for cron jobs managed by Oban. |
| 4 | + """ |
| 5 | + |
| 6 | + @moduledoc since: "10.9.0" |
| 7 | + |
3 | 8 | alias Sentry.Integrations.CheckInIDMappings |
4 | 9 |
|
| 10 | + @doc """ |
| 11 | + The Oban integration calls this callback (if present) to customize |
| 12 | + the configuration options for the check-in. |
| 13 | +
|
| 14 | + This function must return options compatible with the ones passed to `Sentry.CheckIn.new/1`. |
| 15 | +
|
| 16 | + Options returned by this function overwrite any option inferred by the specific |
| 17 | + integration for the check in. We perform *deep merging* of nested keyword options. |
| 18 | + """ |
| 19 | + @doc since: "10.9.0" |
| 20 | + @callback sentry_check_in_configuration(oban_job :: struct()) :: options_to_merge :: keyword() |
| 21 | + |
5 | 22 | @events [ |
6 | 23 | [:oban, :job, :start], |
7 | 24 | [:oban, :job, :stop], |
8 | 25 | [:oban, :job, :exception] |
9 | 26 | ] |
10 | 27 |
|
| 28 | + @doc false |
11 | 29 | @spec attach_telemetry_handler(keyword()) :: :ok |
12 | 30 | def attach_telemetry_handler(config) when is_list(config) do |
13 | 31 | _ = :telemetry.attach_many(__MODULE__, @events, &__MODULE__.handle_event/4, config) |
14 | 32 | :ok |
15 | 33 | end |
16 | 34 |
|
| 35 | + @doc false |
17 | 36 | @spec handle_event([atom()], term(), term(), keyword()) :: :ok |
18 | 37 | def handle_event(event, measurements, metadata, config) |
19 | 38 |
|
@@ -87,15 +106,56 @@ defmodule Sentry.Integrations.Oban.Cron do |
87 | 106 | monitor_config_opts -> |
88 | 107 | id = CheckInIDMappings.lookup_or_insert_new(job.id) |
89 | 108 |
|
90 | | - [ |
| 109 | + opts = [ |
91 | 110 | check_in_id: id, |
92 | 111 | # This is already a binary. |
93 | 112 | monitor_slug: monitor_slug, |
94 | 113 | monitor_config: monitor_config_opts |
95 | 114 | ] |
| 115 | + |
| 116 | + resolve_custom_opts(opts, job) |
96 | 117 | end |
97 | 118 | end |
98 | 119 |
|
| 120 | + defp resolve_custom_opts(opts, %{worker: worker} = job) |
| 121 | + when is_struct(job, Oban.Job) and is_binary(worker) do |
| 122 | + job.worker |> String.split(".") |> Module.safe_concat() |
| 123 | + rescue |
| 124 | + ArgumentError -> opts |
| 125 | + else |
| 126 | + worker -> |
| 127 | + if Code.ensure_loaded?(worker) do |
| 128 | + resolve_custom_opts(opts, worker, job) |
| 129 | + else |
| 130 | + opts |
| 131 | + end |
| 132 | + end |
| 133 | + |
| 134 | + defp resolve_custom_opts(opts, _job) do |
| 135 | + opts |
| 136 | + end |
| 137 | + |
| 138 | + defp resolve_custom_opts(options, mod, per_integration_term) do |
| 139 | + custom_opts = |
| 140 | + if function_exported?(mod, :sentry_check_in_configuration, 1) do |
| 141 | + mod.sentry_check_in_configuration(per_integration_term) |
| 142 | + else |
| 143 | + [] |
| 144 | + end |
| 145 | + |
| 146 | + deep_merge_keyword(options, custom_opts) |
| 147 | + end |
| 148 | + |
| 149 | + defp deep_merge_keyword(left, right) do |
| 150 | + Keyword.merge(left, right, fn _key, left_val, right_val -> |
| 151 | + if Keyword.keyword?(left_val) and Keyword.keyword?(right_val) do |
| 152 | + deep_merge_keyword(left_val, right_val) |
| 153 | + else |
| 154 | + right_val |
| 155 | + end |
| 156 | + end) |
| 157 | + end |
| 158 | + |
99 | 159 | defp schedule_opts(%{meta: meta} = job) when is_struct(job, Oban.Job) do |
100 | 160 | case meta["cron_expr"] do |
101 | 161 | "@hourly" -> [schedule: [type: :interval, value: 1, unit: :hour]] |
|
0 commit comments