Support snoozing / cancel job
Is your feature request related to a problem? Please describe. When hitting rate limited api it's useful to be able to snooze the job
Describe the solution you'd like Maybe we could use the changeset context to achieve this ?
Describe alternatives you've considered Plain oban job. cron
Express the feature either with a change to resource syntax, or with a change to the resource interface
@zachdaniel do you have ideas how this should be implemented?
I most likely still don't fully understand Ash nuances, but same action can be called both directly and from job, so those error messages, probably should make sense if action is called directly.
for snooze, it could be some generic error, like rate limit exceeded, that can be handled from job and also show reasonable feedback if triggered directly.
for cancel it seems more odd. ok job will handle it, but directly triggering action will return canceled?
and how to technically implement this?
it could be done probably both through Ash.Changeset.add_error/3 and Ash.Changeset.put_context/3
I think the trick will be to add some kind of "handler" that can return :snooze/:cancel statuses. For instance we have an on_error action that can currently handle errors, so we could add an option that is something like
error_router: fn error ->
:retry | :snooze | :cancel | :fail
end)
Then you can react to any error and use that to :snooze the job.
:cancel makes a little bit less sense because of the way triggers work, the idea is that the scheduler would just eventually pick it up again and try again, so that one might need a bit more thought applied to it. We could maybe start w/ just :retry | :snooze | :fail.
There is case for cancel as well. For me i dont use scheduled triggers and trigger them manually when necesary. If i have job with max_attemts x and somewhere in the middle i get some error that i can know for sure that this will not be success, but i dont have any need to retry again.
now we have on_error that is if final execution has failed.
we need another that is triggered on all error attempts (like your suggested error_router, but i much rather would have on_error for every failed attempt and on_final_error when all attempts have been failed, but backwards compatibility...)
Regardless of naming this callback only needs to map action error response to oban worker accepted ones https://hexdocs.pm/oban/Oban.Worker.html#t:result/0.
My confusion is what should be input for this callback? I either Ash.Changeset.t() -> Oban.Worker.result() or error -> Oban.Worker.result(). Probably second one.
👋 Just my two cents, since I looked into how to implement it.
https://github.com/ash-project/ash_oban/blob/2d03c464168d86be921d14c79eb1722bf4ac9ca7/lib/transformers/define_action_workers.ex#L106C22-L106C32
That’s the macro that defines the Oban worker.
My idea was to add a specific Oban context and avoid using the bang version of the action. This way, you could check whether the action returns a specific Oban-compatible structure, allowing you to return :ok and other values supported by Oban workers.
As Zach suggested, this should be doable by hooking into the error handler though I’m not sure if that feature existed the last time I used Ash. Still, it seems feasible to intercept the error and return the appropriate Oban value to the worker if the macro that define the worker is adapted for it.
I have investigated handle_error function that currently handles case if it is last attempt failed do on_error action, I think there we can add functionality for rest of attempts that just map response for oban appropriate format, to support snooze, cancel, discard.