Skip to content

Commit

Permalink
Merge branch 'rails:main' into error-when-invalid-recurring-task
Browse files Browse the repository at this point in the history
  • Loading branch information
jherdman authored Dec 3, 2024
2 parents 3bf4dd1 + be8f367 commit 2657a3c
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 62 deletions.
120 changes: 61 additions & 59 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -12,32 +12,32 @@ PATH
GEM
remote: https://rubygems.org/
specs:
actionpack (7.1.3.4)
actionview (= 7.1.3.4)
activesupport (= 7.1.3.4)
actionpack (7.1.4.1)
actionview (= 7.1.4.1)
activesupport (= 7.1.4.1)
nokogiri (>= 1.8.5)
racc
rack (>= 2.2.4)
rack-session (>= 1.0.1)
rack-test (>= 0.6.3)
rails-dom-testing (~> 2.2)
rails-html-sanitizer (~> 1.6)
actionview (7.1.3.4)
activesupport (= 7.1.3.4)
actionview (7.1.4.1)
activesupport (= 7.1.4.1)
builder (~> 3.1)
erubi (~> 1.11)
rails-dom-testing (~> 2.2)
rails-html-sanitizer (~> 1.6)
activejob (7.1.3.4)
activesupport (= 7.1.3.4)
activejob (7.1.4.1)
activesupport (= 7.1.4.1)
globalid (>= 0.3.6)
activemodel (7.1.3.4)
activesupport (= 7.1.3.4)
activerecord (7.1.3.4)
activemodel (= 7.1.3.4)
activesupport (= 7.1.3.4)
activemodel (7.1.4.1)
activesupport (= 7.1.4.1)
activerecord (7.1.4.1)
activemodel (= 7.1.4.1)
activesupport (= 7.1.4.1)
timeout (>= 0.4.0)
activesupport (7.1.3.4)
activesupport (7.1.4.1)
base64
bigdecimal
concurrent-ruby (~> 1.0, >= 1.0.2)
Expand Down Expand Up @@ -66,91 +66,92 @@ GEM
raabro (~> 1.4)
globalid (1.2.1)
activesupport (>= 6.1)
i18n (1.14.5)
i18n (1.14.6)
concurrent-ruby (~> 1.0)
io-console (0.6.0)
irb (1.6.2)
reline (>= 0.3.0)
json (2.7.1)
io-console (0.7.2)
irb (1.14.1)
rdoc (>= 4.0.0)
reline (>= 0.4.2)
json (2.8.2)
language_server-protocol (3.17.0.3)
loofah (2.22.0)
loofah (2.23.1)
crass (~> 1.0.2)
nokogiri (>= 1.12.0)
mini_portile2 (2.8.1)
minitest (5.24.0)
mini_portile2 (2.8.8)
minitest (5.25.2)
mocha (2.1.0)
ruby2_keywords (>= 0.0.5)
mutex_m (0.2.0)
mysql2 (0.5.4)
nio4r (2.7.0)
nokogiri (1.16.6-arm64-darwin)
mutex_m (0.3.0)
mysql2 (0.5.6)
nio4r (2.7.4)
nokogiri (1.16.7-arm64-darwin)
racc (~> 1.4)
nokogiri (1.16.6-x86_64-darwin)
nokogiri (1.16.7-x86_64-darwin)
racc (~> 1.4)
nokogiri (1.16.6-x86_64-linux)
nokogiri (1.16.7-x86_64-linux)
racc (~> 1.4)
parallel (1.24.0)
parser (3.3.0.5)
parallel (1.26.3)
parser (3.3.6.0)
ast (~> 2.4.1)
racc
pg (1.5.4)
puma (6.4.2)
psych (5.2.0)
stringio
puma (6.4.3)
nio4r (~> 2.0)
raabro (1.4.0)
racc (1.8.0)
rack (3.1.5)
racc (1.8.1)
rack (3.1.8)
rack-session (2.0.0)
rack (>= 3.0.0)
rack-test (2.1.0)
rack (>= 1.3)
rackup (2.1.0)
rackup (2.2.1)
rack (>= 3)
webrick (~> 1.8)
rails-dom-testing (2.2.0)
activesupport (>= 5.0.0)
minitest
nokogiri (>= 1.6)
rails-html-sanitizer (1.6.0)
loofah (~> 2.21)
nokogiri (~> 1.14)
railties (7.1.3.4)
actionpack (= 7.1.3.4)
activesupport (= 7.1.3.4)
railties (7.1.4.1)
actionpack (= 7.1.4.1)
activesupport (= 7.1.4.1)
irb
rackup (>= 1.0.0)
rake (>= 12.2)
thor (~> 1.0, >= 1.2.2)
zeitwerk (~> 2.6)
rainbow (3.1.1)
rake (13.0.6)
regexp_parser (2.9.0)
reline (0.3.2)
rake (13.2.1)
rdoc (6.8.1)
psych (>= 4.0.0)
regexp_parser (2.9.2)
reline (0.5.12)
io-console (~> 0.5)
rexml (3.3.6)
strscan
rubocop (1.62.1)
rubocop (1.69.0)
json (~> 2.3)
language_server-protocol (>= 3.17.0)
parallel (~> 1.10)
parser (>= 3.3.0.2)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 1.8, < 3.0)
rexml (>= 3.2.5, < 4.0)
rubocop-ast (>= 1.31.1, < 2.0)
regexp_parser (>= 2.4, < 3.0)
rubocop-ast (>= 1.36.1, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 3.0)
rubocop-ast (1.31.2)
parser (>= 3.3.0.4)
rubocop-minitest (0.35.0)
unicode-display_width (>= 2.4.0, < 4.0)
rubocop-ast (1.36.2)
parser (>= 3.3.1.0)
rubocop-minitest (0.36.0)
rubocop (>= 1.61, < 2.0)
rubocop-ast (>= 1.31.1, < 2.0)
rubocop-performance (1.21.0)
rubocop-performance (1.23.0)
rubocop (>= 1.48.1, < 2.0)
rubocop-ast (>= 1.31.1, < 2.0)
rubocop-rails (2.24.1)
rubocop-rails (2.27.0)
activesupport (>= 4.2.0)
rack (>= 1.1)
rubocop (>= 1.33.0, < 2.0)
rubocop (>= 1.52.0, < 2.0)
rubocop-ast (>= 1.31.1, < 2.0)
rubocop-rails-omakase (1.0.0)
rubocop
Expand All @@ -161,14 +162,15 @@ GEM
ruby2_keywords (0.0.5)
sqlite3 (1.5.4)
mini_portile2 (~> 2.8.0)
strscan (3.1.0)
thor (1.3.1)
timeout (0.4.1)
stringio (3.1.2)
thor (1.3.2)
timeout (0.4.2)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
unicode-display_width (2.5.0)
webrick (1.8.1)
zeitwerk (2.6.12)
unicode-display_width (3.1.2)
unicode-emoji (~> 4.0, >= 4.0.4)
unicode-emoji (4.0.4)
zeitwerk (2.7.1)

PLATFORMS
arm64-darwin-22
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,9 @@ The supervisor is in charge of managing these processes, and it responds to the

When receiving a `QUIT` signal, if workers still have jobs in-flight, these will be returned to the queue when the processes are deregistered.

If processes have no chance of cleaning up before exiting (e.g. if someone pulls a cable somewhere), in-flight jobs might remain claimed by the processes executing them. Processes send heartbeats, and the supervisor checks and prunes processes with expired heartbeats, which will release any claimed jobs back to their queues. You can configure both the frequency of heartbeats and the threshold to consider a process dead. See the section below for this.
If processes have no chance of cleaning up before exiting (e.g. if someone pulls a cable somewhere), in-flight jobs might remain claimed by the processes executing them. Processes send heartbeats, and the supervisor checks and prunes processes with expired heartbeats. Jobs that were claimed by processes with an expired heartbeat will be marked as failed with a `SolidQueue::Processes::ProcessPrunedError`. You can configure both the frequency of heartbeats and the threshold to consider a process dead. See the section below for this.

In a similar way, if a worker is terminated in any other way not initiated by the above signals (e.g. a worker is sent a `KILL` signal), jobs in progress will be marked as failed so that they can be inspected, with a `SolidQueue::Processes::Process::ProcessExitError`. Sometimes a job in particular is responsible for this, for example, if it has a memory leak and you have a mechanism to kill processes over a certain memory threshold, so this will help identifying this kind of situation.


### Database configuration
Expand Down
13 changes: 13 additions & 0 deletions app/models/solid_queue/queue.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,19 @@ def size
@size ||= ReadyExecution.queued_as(name).count
end

def latency
@latency ||= begin
now = Time.current
oldest_enqueued_at = ReadyExecution.queued_as(name).minimum(:created_at) || now

(now - oldest_enqueued_at).to_i
end
end

def human_latency
ActiveSupport::Duration.build(latency).inspect
end

def ==(queue)
name == queue.name
end
Expand Down
1 change: 1 addition & 0 deletions lib/solid_queue/scheduler/recurring_schedule.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ def task_keys

private
def persist_tasks
SolidQueue::RecurringTask.static.where.not(key: task_keys).delete_all
SolidQueue::RecurringTask.create_or_update_all configured_tasks
end

Expand Down
4 changes: 2 additions & 2 deletions test/integration/recurring_tasks_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,13 @@ class RecurringTasksTest < ActiveSupport::TestCase
scheduler1 = SolidQueue::Scheduler.new(recurring_tasks: another_task).tap(&:start)
wait_for_registered_processes(6, timeout: 1.second)

assert_recurring_tasks configured_task.merge(another_task)
assert_recurring_tasks another_task

updated_task = { example_task: { class: "AddToBufferJob", schedule: "every minute" } }
scheduler2 = SolidQueue::Scheduler.new(recurring_tasks: updated_task).tap(&:start)
wait_for_registered_processes(7, timeout: 1.second)

assert_recurring_tasks configured_task.merge(updated_task)
assert_recurring_tasks updated_task

terminate_process(@pid)
scheduler1.stop
Expand Down
33 changes: 33 additions & 0 deletions test/unit/queue_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

class QueueTest < ActiveSupport::TestCase
setup do
freeze_time

5.times do
AddToBufferJob.perform_later "hey!"
end
Expand Down Expand Up @@ -39,4 +41,35 @@ class QueueTest < ActiveSupport::TestCase
@default_queue.resume
end
end

test "return latency in seconds on each queue" do
travel_to 5.minutes.from_now

assert_in_delta 5.minutes.to_i, @background_queue.latency, 1.second.to_i
assert_equal 0, @default_queue.latency

@background_queue = SolidQueue::Queue.find_by_name("background")
@default_queue = SolidQueue::Queue.find_by_name("default")
travel_to 10.minutes.from_now

assert_in_delta 15.minutes.to_i, @background_queue.latency, 1.second.to_i
assert_equal 0, @default_queue.latency
end

test "returns memoized latency after the first call" do
travel_to 5.minutes.from_now

assert_in_delta 5.minutes.to_i, @background_queue.latency, 1.second.to_i

travel_to 10.minutes.from_now

assert_in_delta 5.minutes.to_i, @background_queue.latency, 1.second.to_i
end

test "return human latency on each queue" do
travel_to 5.minutes.from_now

assert_match (/5 minutes/), @background_queue.human_latency
assert_match (/0 seconds/), @default_queue.human_latency
end
end

0 comments on commit 2657a3c

Please sign in to comment.