Skip to content

Commit e7a25c8

Browse files
committed
Watch for changes in dynamic recurring tasks
1 parent a07b84a commit e7a25c8

File tree

3 files changed

+86
-0
lines changed

3 files changed

+86
-0
lines changed

lib/solid_queue/scheduler.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@ def run
3030
loop do
3131
break if shutting_down?
3232

33+
recurring_schedule.update_scheduled_tasks.tap do |updated_tasks|
34+
if updated_tasks.any?
35+
process.update_columns(metadata: metadata.compact)
36+
end
37+
end
38+
3339
interruptible_sleep(SLEEP_INTERVAL)
3440
end
3541
ensure

lib/solid_queue/scheduler/recurring_schedule.rb

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,23 @@ def dynamic_tasks
3131
SolidQueue::RecurringTask.dynamic
3232
end
3333

34+
def schedule_new_dynamic_tasks
35+
dynamic_tasks.where.not(key: scheduled_tasks.keys).each do |task|
36+
schedule_task(task)
37+
end
38+
end
39+
40+
def unschedule_old_dynamic_tasks
41+
(scheduled_tasks.keys - SolidQueue::RecurringTask.pluck(:key)).each do |key|
42+
scheduled_tasks[key].cancel
43+
scheduled_tasks.delete(key)
44+
end
45+
end
46+
47+
def update_scheduled_tasks
48+
schedule_new_dynamic_tasks + unschedule_old_dynamic_tasks
49+
end
50+
3451
def schedule_task(task)
3552
scheduled_tasks[task.key] = schedule(task)
3653
end

test/unit/scheduler_test.rb

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,4 +68,67 @@ class SchedulerTest < ActiveSupport::TestCase
6868
assert_equal 1, run_at_times[i + 1] - run_at_times[i]
6969
end
7070
end
71+
72+
test "updates metadata after adding dynamic task post-start" do
73+
scheduler = SolidQueue::Scheduler.new(recurring_tasks: {}).tap do |s|
74+
s.define_singleton_method(:interruptible_sleep) { |interval| sleep 0.1 }
75+
s.start
76+
end
77+
78+
wait_for_registered_processes(1, timeout: 1.second)
79+
80+
process = SolidQueue::Process.first
81+
# initially there are no recurring_schedule keys
82+
assert process.metadata, {}
83+
84+
# now create a dynamic task after the scheduler has booted
85+
SolidQueue::RecurringTask.create(
86+
key: "new_dynamic_task",
87+
static: false,
88+
class_name: "AddToBufferJob",
89+
schedule: "every second",
90+
arguments: [ 42 ]
91+
)
92+
93+
sleep 1
94+
95+
process.reload
96+
97+
# metadata should now include the new key
98+
assert_metadata process, recurring_schedule: [ "new_dynamic_task" ]
99+
ensure
100+
scheduler&.stop
101+
end
102+
103+
test "updates metadata after removing dynamic task post-start" do
104+
old_dynamic_task = SolidQueue::RecurringTask.create(
105+
key: "old_dynamic_task",
106+
static: false,
107+
class_name: "AddToBufferJob",
108+
schedule: "every second",
109+
arguments: [ 42 ]
110+
)
111+
112+
scheduler = SolidQueue::Scheduler.new(recurring_tasks: {}).tap do |s|
113+
s.define_singleton_method(:interruptible_sleep) { |interval| sleep 0.1 }
114+
s.start
115+
end
116+
117+
wait_for_registered_processes(1, timeout: 1.second)
118+
119+
process = SolidQueue::Process.first
120+
# initially there is one recurring_schedule key
121+
assert_metadata process, recurring_schedule: [ "old_dynamic_task" ]
122+
123+
old_dynamic_task.destroy
124+
125+
sleep 1
126+
127+
process.reload
128+
129+
# The task is unschedule after it's being removed, and it's reflected in the metadata
130+
assert process.metadata, {}
131+
ensure
132+
scheduler&.stop
133+
end
71134
end

0 commit comments

Comments
 (0)