Packages
ash_oban
0.8.0-rc.1
0.8.10
0.8.9
0.8.8
0.8.7
0.8.6
0.8.5
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0-rc.1
0.8.0-rc.0
0.7.2
0.7.1
0.7.0
0.6.0
0.5.1
0.5.0
0.4.12
0.4.11
0.4.10
0.4.9
0.4.8
0.4.7
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
0.2.6
0.2.5
0.2.4
0.2.3
0.2.3-rc.1
0.2.3-rc.0
0.2.2
0.2.1
0.2.0
0.1.14
0.1.13
0.1.12
0.1.11
0.1.9
0.1.8
0.1.7
0.1.6
0.1.5
0.1.4
0.1.3
0.1.2
0.1.1
The extension for integrating Ash resources with Oban.
Current section
59 Versions
Jump to
Current section
59 Versions
Compare versions
13
files changed
+644
additions
-87
deletions
| @@ -38,6 +38,7 @@ spark_locals_without_parens = [ | |
| 38 38 | state: 1, |
| 39 39 | stream_batch_size: 1, |
| 40 40 | stream_with: 1, |
| 41 | + tags: 1, |
| 41 42 | timeout: 1, |
| 42 43 | trigger: 1, |
| 43 44 | trigger: 2, |
| @@ -11,6 +11,23 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline | |
| 11 11 | |
| 12 12 | <!-- changelog --> |
| 13 13 | |
| 14 | + ## [v0.8.0-rc.1](https://github.com/ash-project/ash_oban/compare/v0.8.0-rc.0...v0.8.0-rc.1) (2026-02-23) |
| 15 | + |
| 16 | + |
| 17 | + |
| 18 | + |
| 19 | + ### Improvements: |
| 20 | + |
| 21 | + * add new test helpers for triggers & schedulers by Zach Daniel |
| 22 | + |
| 23 | + * add support for snoozing and cancelling Oban jobs from actions by Zach Daniel |
| 24 | + |
| 25 | + * validate that `on_error` action exists by Zach Daniel |
| 26 | + |
| 27 | + * support setting tags in DSL by Zach Daniel |
| 28 | + |
| 29 | + * set job into context to allow for better logging and error handling by Zach Daniel |
| 30 | + |
| 14 31 | ## [v0.8.0-rc.0](https://github.com/ash-project/ash_oban/compare/v0.7.2...v0.8.0-rc.0) (2026-02-22) |
| @@ -150,6 +150,7 @@ end | |
| 150 150 | | [`on_error_fails_job?`](#oban-triggers-trigger-on_error_fails_job?){: #oban-triggers-trigger-on_error_fails_job? } | `boolean` | `false` | Determines if the oban job will be failed on the last attempt when there is an on_error handler that is called. If there is no on_error, then the action is always marked as failed on the last attempt. | |
| 151 151 | | [`shared_context?`](#oban-triggers-trigger-shared_context?){: #oban-triggers-trigger-shared_context? } | `boolean` | | If set to `true`, the `ash_oban?: true` flag will be placed in shared context instead of regular context. Shared context propagates to related actions called via `manage_relationship` and can be passed to other action invocations using the context as scope, making it easier to detect AshOban execution in nested actions. If not specified, inherits the global `shared_context?` setting from the `oban` section. | |
| 152 152 | | [`use_tenant_from_record?`](#oban-triggers-trigger-use_tenant_from_record?){: #oban-triggers-trigger-use_tenant_from_record? } | `boolean` | `false` | If set to `true`, the tenant will be extracted from each record's tenant attribute and used when the worker processes that record. This allows the scheduler to use a multitenancy `:allow_global` read action to find records across all tenants, while the worker action still runs with the correct tenant context for each individual record. If not specified, inherits the global `use_tenant_from_record?` setting from the `oban` section. | |
| 153 | + | [`tags`](#oban-triggers-trigger-tags){: #oban-triggers-trigger-tags } | `list(String.t)` | `[]` | A list of tags to add to the Oban job. Tags are merged with any tags set in `worker_opts`. | |
| 153 154 | | [`worker_opts`](#oban-triggers-trigger-worker_opts){: #oban-triggers-trigger-worker_opts } | `keyword` | `[]` | Options to set on the worker. ATTENTION: this may overwrite options set by ash_oban, make sure you know what you are doing. See [Oban.Worker](https://hexdocs.pm/oban/Oban.Worker.html#module-defining-workers) for options and [Oban.Pro.Worker](https://oban.pro/docs/pro/Oban.Pro.Worker.html) for oban pro | |
| 154 155 | | [`backoff`](#oban-triggers-trigger-backoff){: #oban-triggers-trigger-backoff } | `pos_integer \| (any -> any) \| :exponential` | `:exponential` | Configure after how much time job should (in seconds) be retried in case of error if more retries available. Can be a number of seconds or a function that takes the job and returns a number of seconds. Will not be executed if default max_attempts value of 1 will be used. See [Oban.Worker](https://hexdocs.pm/oban/Oban.Worker.html#module-customizing-backoff) for more about backoff. backoff 10 backoff fn _job -> 10 end backoff fn %Oban.Job{attempt: attempt} -> 10 * attempt end backoff fn %Oban.Job{attempt: attempt, unsaved_error: unsaved_error} -> %{kind: _, reason: reason, stacktrace: _} = unsaved_error case reason do %MyApp.ApiError{status: 429} -> 300 _ -> trunc(:math.pow(attempt, 4)) end end | |
| 155 156 | | [`timeout`](#oban-triggers-trigger-timeout){: #oban-triggers-trigger-timeout } | `pos_integer \| (any -> any) \| :infinity` | `:infinity` | Configure timeout for the job in milliseconds. See [Oban.Worker timeout](https://hexdocs.pm/oban/Oban.Worker.html#module-customizing-timeout) for more about timeout. timeout 30_000 timeout fn _job -> :timer.seconds(30) end | |
| @@ -269,6 +270,7 @@ schedule name, cron | |
| 269 270 | | [`state`](#oban-scheduled_actions-schedule-state){: #oban-scheduled_actions-schedule-state } | `:active \| :paused \| :deleted` | `:active` | Describes the state of the cron job. See the getting started guide for more information. The most important thing is that you *do not remove a scheduled action from a resource if you are using oban pro*. | |
| 270 271 | | [`max_attempts`](#oban-scheduled_actions-schedule-max_attempts){: #oban-scheduled_actions-schedule-max_attempts } | `pos_integer` | `1` | How many times to attempt the job. The action will receive a `last_oban_attempt?` argument on the last attempt, and you should handle errors accordingly. | |
| 271 272 | | [`priority`](#oban-scheduled_actions-schedule-priority){: #oban-scheduled_actions-schedule-priority } | `non_neg_integer` | `3` | A number from 0 to 3, where 0 is the highest priority and 3 is the lowest. | |
| 273 | + | [`tags`](#oban-scheduled_actions-schedule-tags){: #oban-scheduled_actions-schedule-tags } | `list(String.t)` | `[]` | A list of tags to add to the Oban job. | |
| 272 274 | | [`debug?`](#oban-scheduled_actions-schedule-debug?){: #oban-scheduled_actions-schedule-debug? } | `boolean` | `false` | If set to `true`, detailed debug logging will be enabled for this trigger. You can also set `config :ash_oban, debug_all_triggers?: true` to enable debug logging for all triggers. | |
| 273 275 | | [`shared_context?`](#oban-scheduled_actions-schedule-shared_context?){: #oban-scheduled_actions-schedule-shared_context? } | `boolean` | | If set to `true`, the `ash_oban?: true` flag will be placed in shared context instead of regular context. Shared context propagates to related actions called via `manage_relationship` and can be passed to other action invocations using the context as scope, making it easier to detect AshOban execution in nested actions. If not specified, inherits the global `shared_context?` setting from the `oban` section. | |
| @@ -149,6 +149,124 @@ A chunk counts as **one** job execution against Oban's queue concurrency and rat | |
| 149 149 | - Only works with `update` and `destroy` actions (not generic or create actions). |
| 150 150 | - Atomic actions are recommended for efficient bulk execution, though non-atomic actions are supported via the `:stream` strategy. |
| 151 151 | |
| 152 | + ### Tagging Jobs |
| 153 | + |
| 154 | + You can attach tags to jobs for filtering and grouping in telemetry, notifications, and the Oban dashboard: |
| 155 | + |
| 156 | + ```elixir |
| 157 | + trigger :process do |
| 158 | + action :process |
| 159 | + where expr(processed != true) |
| 160 | + tags ["processing", "intense"] |
| 161 | + end |
| 162 | + |
| 163 | + schedule :import_from_github, "0 */6 * * *" do |
| 164 | + action :import_from_github |
| 165 | + tags ["import", "external"] |
| 166 | + end |
| 167 | + ``` |
| 168 | + |
| 169 | + Tags set via `tags` are merged with any tags you also set in `worker_opts`, so both lists are combined. |
| 170 | + |
| 171 | + ### Accessing the Oban Job |
| 172 | + |
| 173 | + The underlying `%Oban.Job{}` struct is available in the context of any action run by a trigger or scheduled action. Access it via `context.ash_oban.job`: |
| 174 | + |
| 175 | + ```elixir |
| 176 | + # In a change module |
| 177 | + def change(changeset, _opts, context) do |
| 178 | + job = context.ash_oban.job |
| 179 | + Ash.Changeset.put_context(changeset, :oban_tags, job.tags) |
| 180 | + end |
| 181 | + |
| 182 | + # In a generic action implementation |
| 183 | + def run(input, _opts, context) do |
| 184 | + job = context.ash_oban.job |
| 185 | + Logger.info("Attempt #{job.attempt} of #{job.max_attempts}") |
| 186 | + :ok |
| 187 | + end |
| 188 | + ``` |
| 189 | + |
| 190 | + > ### Chunk processing {: .info} |
| 191 | + > The `oban_job` is not available in chunk worker contexts, since those process a batch of jobs rather than a single one. |
| 192 | + |
| 193 | + ### Controlling Job Behavior (Snooze and Cancel) |
| 194 | + |
| 195 | + From within any action run by a trigger or scheduled action, you can snooze or cancel the Oban job by raising (or returning as an error) `AshOban.Errors.SnoozeJob` or `AshOban.Errors.CancelJob`. These work from both the main action and the `on_error` action. |
| 196 | + |
| 197 | + #### Snoozing a job |
| 198 | + |
| 199 | + Snoozing re-schedules the job to run again after a delay without consuming an attempt. Use this for transient conditions like rate limits or temporary unavailability: |
| 200 | + |
| 201 | + ```elixir |
| 202 | + update :sync_with_external_api do |
| 203 | + change fn changeset, _context -> |
| 204 | + case ExternalAPI.rate_limit_remaining() do |
| 205 | + 0 -> |
| 206 | + Ash.Changeset.add_error( |
| 207 | + changeset, |
| 208 | + AshOban.Errors.SnoozeJob.exception(snooze_for: 60) |
| 209 | + ) |
| 210 | + _ -> |
| 211 | + do_sync(changeset) |
| 212 | + end |
| 213 | + end |
| 214 | + end |
| 215 | + ``` |
| 216 | + |
| 217 | + Or via `raise`: |
| 218 | + |
| 219 | + ```elixir |
| 220 | + raise AshOban.Errors.SnoozeJob, snooze_for: 60 |
| 221 | + ``` |
| 222 | + |
| 223 | + The `snooze_for` field is an integer number of seconds. |
| 224 | + |
| 225 | + #### Cancelling a job |
| 226 | + |
| 227 | + Cancelling stops all retries and marks the job as cancelled. Use this when you determine that further processing is permanently invalid: |
| 228 | + |
| 229 | + ```elixir |
| 230 | + update :process do |
| 231 | + change fn changeset, _context -> |
| 232 | + record = changeset.data |
| 233 | + |
| 234 | + if record.deleted_at do |
| 235 | + Ash.Changeset.add_error( |
| 236 | + changeset, |
| 237 | + AshOban.Errors.CancelJob.exception(reason: :record_deleted) |
| 238 | + ) |
| 239 | + else |
| 240 | + do_process(changeset) |
| 241 | + end |
| 242 | + end |
| 243 | + end |
| 244 | + ``` |
| 245 | + |
| 246 | + Or via `raise`: |
| 247 | + |
| 248 | + ```elixir |
| 249 | + raise AshOban.Errors.CancelJob, reason: :permanently_invalid |
| 250 | + ``` |
| 251 | + |
| 252 | + The `reason` field accepts any term. |
| 253 | + |
| 254 | + #### From the on_error action |
| 255 | + |
| 256 | + Both errors also work from the `on_error` action. For example, to cancel the job from your error handler rather than failing it: |
| 257 | + |
| 258 | + ```elixir |
| 259 | + update :handle_failure do |
| 260 | + change fn changeset, _context -> |
| 261 | + # Log the failure, then cancel the job instead of failing it |
| 262 | + Ash.Changeset.add_error( |
| 263 | + changeset, |
| 264 | + AshOban.Errors.CancelJob.exception(reason: :handled) |
| 265 | + ) |
| 266 | + end |
| 267 | + end |
| 268 | + ``` |
| 269 | + |
| 152 270 | ### Scheduled Actions |
| 153 271 | |
| 154 272 | Scheduled actions are a much simpler concept than triggers. They are used to perform a generic action on a specified schedule. For example, lets say |
| @@ -18,7 +18,7 @@ about what `AshOban` provides. | |
| 18 18 | ## Bring in the `ash_oban` dependency |
| 19 19 | |
| 20 20 | ```elixir |
| 21 | - {:ash_oban, "~> 0.8.0-rc.0"} |
| 21 | + {:ash_oban, "~> 0.8.0-rc.1"} |
| 22 22 | ``` |
| 23 23 | |
| 24 24 | ## Setup |
Loading more files…