From 0cd4cb0a7c817ae680f34e30a71053f62fd40c43 Mon Sep 17 00:00:00 2001 From: Rosa Gutierrez Date: Sun, 10 Nov 2024 21:23:56 +0100 Subject: [PATCH] Don't try to enqueue recurring tasks that are undefined For example, if running Mission Control from another app than the one where the recurring task classes are defined. Fixes #200 --- .../jobs/recurring_tasks_controller.rb | 9 ++++++- .../mission_control/jobs/recurring_task.rb | 4 +++ .../jobs/recurring_tasks/_actions.html.erb | 4 ++- .../solid_queue_ext/recurring_tasks.rb | 6 +++++ .../recurring_tasks_controller_test.rb | 27 +++++++++++++++++++ 5 files changed, 48 insertions(+), 2 deletions(-) diff --git a/app/controllers/mission_control/jobs/recurring_tasks_controller.rb b/app/controllers/mission_control/jobs/recurring_tasks_controller.rb index 3456378e..c555b567 100644 --- a/app/controllers/mission_control/jobs/recurring_tasks_controller.rb +++ b/app/controllers/mission_control/jobs/recurring_tasks_controller.rb @@ -1,6 +1,7 @@ class MissionControl::Jobs::RecurringTasksController < MissionControl::Jobs::ApplicationController before_action :ensure_supported_recurring_tasks before_action :set_recurring_task, only: [ :show, :update ] + before_action :ensure_recurring_task_can_be_enqueued, only: :update def index @recurring_tasks = MissionControl::Jobs::Current.server.recurring_tasks @@ -14,7 +15,7 @@ def update if (job = @recurring_task.enqueue) && job.successfully_enqueued? redirect_to application_job_path(@application, job.job_id), notice: "Enqueued recurring task #{@recurring_task.id}" else - redirect_to application_recurring_task_path(@application, @recurring_task), alert: "Something went wrong enqueuing this recurring task" + redirect_to application_recurring_task_path(@application, @recurring_task.id), alert: "Something went wrong enqueuing this recurring task" end end @@ -28,4 +29,10 @@ def ensure_supported_recurring_tasks def set_recurring_task @recurring_task = MissionControl::Jobs::Current.server.find_recurring_task(params[:id]) end + + def ensure_recurring_task_can_be_enqueued + unless @recurring_task.runnable? + redirect_to application_recurring_task_path(@application, @recurring_task.id), alert: "This task can't be enqueued" + end + end end diff --git a/app/models/mission_control/jobs/recurring_task.rb b/app/models/mission_control/jobs/recurring_task.rb index 9bec8811..5110a9df 100644 --- a/app/models/mission_control/jobs/recurring_task.rb +++ b/app/models/mission_control/jobs/recurring_task.rb @@ -16,6 +16,10 @@ def enqueue queue_adapter.enqueue_recurring_task(id) end + def runnable? + queue_adapter.can_enqueue_recurring_task?(id) + end + private attr_reader :queue_adapter end diff --git a/app/views/mission_control/jobs/recurring_tasks/_actions.html.erb b/app/views/mission_control/jobs/recurring_tasks/_actions.html.erb index 553ed230..bef70a82 100644 --- a/app/views/mission_control/jobs/recurring_tasks/_actions.html.erb +++ b/app/views/mission_control/jobs/recurring_tasks/_actions.html.erb @@ -1,3 +1,5 @@
- <%= button_to "Run now", application_recurring_task_path(@application, recurring_task.id), class: "button is-warning is-light mr-0", method: :put %> + <% if recurring_task.runnable? %> + <%= button_to "Run now", application_recurring_task_path(@application, recurring_task.id), class: "button is-warning is-light mr-0", method: :put %> + <% end %>
diff --git a/lib/active_job/queue_adapters/solid_queue_ext/recurring_tasks.rb b/lib/active_job/queue_adapters/solid_queue_ext/recurring_tasks.rb index 66e7066b..cf37c404 100644 --- a/lib/active_job/queue_adapters/solid_queue_ext/recurring_tasks.rb +++ b/lib/active_job/queue_adapters/solid_queue_ext/recurring_tasks.rb @@ -26,6 +26,12 @@ def enqueue_recurring_task(task_id) end end + def can_enqueue_recurring_task?(task_id) + if task = SolidQueue::RecurringTask.find_by(key: task_id) + task.valid? + end + end + private def recurring_task_attributes_from_solid_queue_recurring_task(task) { diff --git a/test/controllers/recurring_tasks_controller_test.rb b/test/controllers/recurring_tasks_controller_test.rb index a4e2981f..77f2dcbb 100644 --- a/test/controllers/recurring_tasks_controller_test.rb +++ b/test/controllers/recurring_tasks_controller_test.rb @@ -23,6 +23,7 @@ class MissionControl::Jobs::RecurringTasksControllerTest < ActionDispatch::Integ assert_select "td", "PauseJob" assert_select "td", "every second" assert_select "td", /2024-10-30 19:07:1\d\.\d{3}/ + assert_select "button", "Run now" end end end @@ -53,6 +54,19 @@ class MissionControl::Jobs::RecurringTasksControllerTest < ActionDispatch::Integ end end + test "get recurring task with undefined class" do + # simulate recurring task inserted from another app, no validations or callbacks + SolidQueue::RecurringTask.insert({ key: "missing_class_task", class_name: "MissingJob", schedule: "every minute" }) + get mission_control_jobs.application_recurring_tasks_url(@application) + assert_response :ok + + assert_select "tr.recurring_task", 1 + assert_select "td a", "missing_class_task" + assert_select "td", "MissingJob" + assert_select "td", "every minute" + assert_select "button", text: "Run now", count: 0 # Can't be run because the class doesn't exist + end + test "enqueue recurring task successfully" do schedule_recurring_tasks_async(wait: 0.1.seconds) @@ -65,4 +79,17 @@ class MissionControl::Jobs::RecurringTasksControllerTest < ActionDispatch::Integ assert_equal "PauseJob", job.job_class_name assert_match /jobs\/#{job.job_id}\?server_id=solid_queue\z/, response.location end + + test "fail to enqueue recurring task with undefined class" do + # simulate recurring task inserted from another app, no validations or callbacks + SolidQueue::RecurringTask.insert({ key: "missing_class_task", class_name: "MissingJob", schedule: "every minute" }) + + assert_no_difference -> { ActiveJob.jobs.pending.count } do + put mission_control_jobs.application_recurring_task_url(@application, "missing_class_task") + assert_response :redirect + + follow_redirect! + assert_select "article.is-danger", /This task can.t be enqueued/ + end + end end