Skip to content

Commit c97d407

Browse files
committed
Add "Run Now" button to cron details page
Missed crons can be ran manually through the UI now with the "Run Now" button. Options are preserved and the job is properly marked as being part of that cron lineage.
1 parent ebe32fc commit c97d407

File tree

2 files changed

+57
-0
lines changed

2 files changed

+57
-0
lines changed

lib/oban/web/live/crons/detail_component.ex

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,16 @@ defmodule Oban.Web.Crons.DetailComponent do
3131
</.link>
3232
3333
<div class="flex space-x-3">
34+
<button
35+
:if={can?(:insert_jobs, @access)}
36+
type="button"
37+
class="flex items-center text-sm text-gray-600 dark:text-gray-400 bg-white dark:bg-gray-800 px-4 py-2 border border-gray-300 dark:border-gray-700 rounded-md focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-blue-500 focus-visible:border-blue-500 hover:text-blue-500 hover:border-blue-600 cursor-pointer"
38+
phx-click="run-now"
39+
phx-target={@myself}
40+
>
41+
<Icons.play_circle class="mr-2 h-5 w-5" /> Run Now
42+
</button>
43+
3444
<button
3545
:if={@cron.dynamic? and can?(:pause_queues, @access)}
3646
type="button"
@@ -330,6 +340,34 @@ defmodule Oban.Web.Crons.DetailComponent do
330340
# Handlers
331341

332342
@impl Phoenix.LiveComponent
343+
def handle_event("run-now", _params, socket) do
344+
enforce_access!(:insert_jobs, socket.assigns.access)
345+
346+
%{cron: cron, conf: conf} = socket.assigns
347+
348+
worker = Module.safe_concat([cron.worker])
349+
args = Map.get(cron.opts, "args", %{})
350+
351+
opts =
352+
cron.opts
353+
|> Map.take(~w(max_attempts priority queue tags))
354+
|> Keyword.new(fn {key, val} -> {String.to_existing_atom(key), val} end)
355+
|> Keyword.put(:meta, %{cron: true, cron_expr: cron.expression, cron_name: cron.name})
356+
357+
changeset = worker.new(args, opts)
358+
359+
case Oban.insert(conf.name, changeset) do
360+
{:ok, _job} ->
361+
send(self(), :refresh)
362+
send(self(), {:flash, :info, "Job inserted for #{cron.worker}"})
363+
364+
{:error, _reason} ->
365+
send(self(), {:flash, :error, "Failed to insert job"})
366+
end
367+
368+
{:noreply, socket}
369+
end
370+
333371
def handle_event("toggle-pause", _params, socket) do
334372
enforce_access!(:pause_queues, socket.assigns.access)
335373

test/oban/web/pages/crons/detail_test.exs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,25 @@ defmodule Oban.Web.Pages.Crons.DetailTest do
150150
refute has_element?(live, "fieldset[disabled]")
151151
assert has_element?(live, "button:not([disabled])", "Save Changes")
152152
end
153+
154+
test "run now button inserts a job for the cron" do
155+
DynamicCron.insert([{"0 * * * *", DetailCronWorker, name: "run-now-test"}])
156+
157+
{:ok, live, _html} = live(build_conn(), "/oban/crons/run-now-test")
158+
159+
refresh(live)
160+
161+
assert has_element?(live, "button", "Run Now")
162+
163+
live
164+
|> element("button", "Run Now")
165+
|> render_click()
166+
167+
assert [job] = Repo.all(Job)
168+
169+
assert "Oban.Workers.DetailCronWorker" == job.worker
170+
assert %{"cron_expr" => "0 * * * *", "cron_name" => "run-now-test"} = job.meta
171+
end
153172
end
154173

155174
defp refresh(live) do

0 commit comments

Comments
 (0)