solid_queue 1.0.2 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +14 -5
- data/app/models/solid_queue/queue.rb +13 -0
- data/lib/generators/solid_queue/install/install_generator.rb +5 -3
- data/lib/solid_queue/processes/interruptible.rb +10 -18
- data/lib/solid_queue/scheduler/recurring_schedule.rb +1 -0
- data/lib/solid_queue/version.rb +1 -1
- metadata +34 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e843e842397e1d8141e0457b5b278026b71effe6ebf83d8300d2c4098db56adf
|
4
|
+
data.tar.gz: a5db37bdea8dacec796f2dcb912ab8f2a69c929487dff081d8a53fe10c20086c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a6831f7114c24d68ae8ed7b5aebfd4d3df0cc2c7b4e0046e6275a5bf5e46f8da8f5b79e9a303ae908e3581e8b96a132776f4c1a3f55bbf550dd008541e679665
|
7
|
+
data.tar.gz: e51b90234b3a60355a96c9163bfc7d95a1f5eb95fcf7a2dc1faf553f04a7c242da2d48493ba5b6574c2dbf4b0d259cb69af1dda576475f1510a31f8325be5f8b
|
data/README.md
CHANGED
@@ -239,7 +239,9 @@ The supervisor is in charge of managing these processes, and it responds to the
|
|
239
239
|
|
240
240
|
When receiving a `QUIT` signal, if workers still have jobs in-flight, these will be returned to the queue when the processes are deregistered.
|
241
241
|
|
242
|
-
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
|
242
|
+
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.
|
243
|
+
|
244
|
+
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.
|
243
245
|
|
244
246
|
|
245
247
|
### Database configuration
|
@@ -412,13 +414,19 @@ to your `puma.rb` configuration.
|
|
412
414
|
|
413
415
|
|
414
416
|
## Jobs and transactional integrity
|
415
|
-
:warning: Having your jobs in the same ACID-compliant database as your application data enables a powerful yet sharp tool: taking advantage of transactional integrity to ensure some action in your app is not committed unless your job is also committed and
|
417
|
+
:warning: Having your jobs in the same ACID-compliant database as your application data enables a powerful yet sharp tool: taking advantage of transactional integrity to ensure some action in your app is not committed unless your job is also committed and vice versa, and ensuring that your job won't be enqueued until the transaction within which you're enqueuing it is committed. This can be very powerful and useful, but it can also backfire if you base some of your logic on this behaviour, and in the future, you move to another active job backend, or if you simply move Solid Queue to its own database, and suddenly the behaviour changes under you. Because this can be quite tricky and many people shouldn't need to worry about it, by default Solid Queue is configured in a different database as the main app.
|
416
418
|
|
417
|
-
|
419
|
+
Starting from Rails 8, an option which doesn't rely on this transactional integrity and which Active Job provides is to defer the enqueueing of a job inside an Active Record transaction until that transaction successfully commits. This option can be set via the [`enqueue_after_transaction_commit`](https://edgeapi.rubyonrails.org/classes/ActiveJob/Enqueuing.html#method-c-enqueue_after_transaction_commit) class method on the job level and is by default disabled. Either it can be enabled for individual jobs or for all jobs through `ApplicationJob`:
|
418
420
|
|
419
|
-
|
421
|
+
```ruby
|
422
|
+
class ApplicationJob < ActiveJob::Base
|
423
|
+
self.enqueue_after_transaction_commit = true
|
424
|
+
end
|
425
|
+
```
|
426
|
+
|
427
|
+
Using this option, you can also use Solid Queue in the same database as your app but not rely on transactional integrity.
|
420
428
|
|
421
|
-
If you set
|
429
|
+
If you don't set this option but still want to make sure you're not inadvertently on transactional integrity, you can make sure that:
|
422
430
|
- Your jobs relying on specific data are always enqueued on [`after_commit` callbacks](https://guides.rubyonrails.org/active_record_callbacks.html#after-commit-and-after-rollback) or otherwise from a place where you're certain that whatever data the job will use has been committed to the database before the job is enqueued.
|
423
431
|
- Or, you configure a different database for Solid Queue, even if it's the same as your app, ensuring that a different connection on the thread handling requests or running jobs for your app will be used to enqueue jobs. For example:
|
424
432
|
|
@@ -433,6 +441,7 @@ If you set that to `never` but still want to make sure you're not inadvertently
|
|
433
441
|
config.solid_queue.connects_to = { database: { writing: :primary, reading: :replica } }
|
434
442
|
```
|
435
443
|
|
444
|
+
|
436
445
|
## Recurring tasks
|
437
446
|
|
438
447
|
Solid Queue supports defining recurring tasks that run at specific times in the future, on a regular basis like cron jobs. These are managed by the scheduler process and are defined in their own configuration file. By default, the file is located in `config/recurring.yml`, but you can set a different path using the environment variable `SOLID_QUEUE_RECURRING_SCHEDULE` or by using the `--recurring_schedule_file` option with `bin/jobs`, like this:
|
@@ -40,6 +40,19 @@ module SolidQueue
|
|
40
40
|
@size ||= ReadyExecution.queued_as(name).count
|
41
41
|
end
|
42
42
|
|
43
|
+
def latency
|
44
|
+
@latency ||= begin
|
45
|
+
now = Time.current
|
46
|
+
oldest_enqueued_at = ReadyExecution.queued_as(name).minimum(:created_at) || now
|
47
|
+
|
48
|
+
(now - oldest_enqueued_at).to_i
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def human_latency
|
53
|
+
ActiveSupport::Duration.build(latency).inspect
|
54
|
+
end
|
55
|
+
|
43
56
|
def ==(queue)
|
44
57
|
name == queue.name
|
45
58
|
end
|
@@ -11,9 +11,11 @@ class SolidQueue::InstallGenerator < Rails::Generators::Base
|
|
11
11
|
chmod "bin/jobs", 0755 & ~File.umask, verbose: false
|
12
12
|
end
|
13
13
|
|
14
|
-
def
|
15
|
-
|
16
|
-
|
14
|
+
def configure_adapter_and_database
|
15
|
+
pathname = Pathname(destination_root).join("config/environments/production.rb")
|
16
|
+
|
17
|
+
gsub_file pathname, /\n\s*config\.solid_queue\.connects_to\s+=.*\n/, "\n", verbose: false
|
18
|
+
gsub_file pathname, /(# )?config\.active_job\.queue_adapter\s+=.*\n/,
|
17
19
|
"config.active_job.queue_adapter = :solid_queue\n" +
|
18
20
|
" config.solid_queue.connects_to = { database: { writing: :queue } }\n"
|
19
21
|
end
|
@@ -7,31 +7,23 @@ module SolidQueue::Processes
|
|
7
7
|
end
|
8
8
|
|
9
9
|
private
|
10
|
-
SELF_PIPE_BLOCK_SIZE = 11
|
11
10
|
|
12
11
|
def interrupt
|
13
|
-
|
14
|
-
rescue Errno::EAGAIN, Errno::EINTR
|
15
|
-
# Ignore writes that would block and retry
|
16
|
-
# if another signal arrived while writing
|
17
|
-
retry
|
12
|
+
queue << true
|
18
13
|
end
|
19
14
|
|
20
15
|
def interruptible_sleep(time)
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
16
|
+
# Invoking from the main thread can result in a 35% slowdown (at least when running the test suite).
|
17
|
+
# Using some form of Async (Futures) addresses this performance issue.
|
18
|
+
Concurrent::Promises.future(time) do |timeout|
|
19
|
+
if timeout > 0 && queue.pop(timeout:)
|
20
|
+
queue.clear
|
21
|
+
end
|
22
|
+
end.value
|
25
23
|
end
|
26
24
|
|
27
|
-
|
28
|
-
|
29
|
-
@self_pipe ||= create_self_pipe
|
30
|
-
end
|
31
|
-
|
32
|
-
def create_self_pipe
|
33
|
-
reader, writer = IO.pipe
|
34
|
-
{ reader: reader, writer: writer }
|
25
|
+
def queue
|
26
|
+
@queue ||= Queue.new
|
35
27
|
end
|
36
28
|
end
|
37
29
|
end
|
data/lib/solid_queue/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: solid_queue
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rosa Gutierrez
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-12-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -98,16 +98,16 @@ dependencies:
|
|
98
98
|
name: debug
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
|
-
- - "
|
101
|
+
- - "~>"
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version: '
|
103
|
+
version: '1.9'
|
104
104
|
type: :development
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
|
-
- - "
|
108
|
+
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version: '
|
110
|
+
version: '1.9'
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
112
|
name: mocha
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
@@ -192,6 +192,34 @@ dependencies:
|
|
192
192
|
- - ">="
|
193
193
|
- !ruby/object:Gem::Version
|
194
194
|
version: '0'
|
195
|
+
- !ruby/object:Gem::Dependency
|
196
|
+
name: rdoc
|
197
|
+
requirement: !ruby/object:Gem::Requirement
|
198
|
+
requirements:
|
199
|
+
- - ">="
|
200
|
+
- !ruby/object:Gem::Version
|
201
|
+
version: '0'
|
202
|
+
type: :development
|
203
|
+
prerelease: false
|
204
|
+
version_requirements: !ruby/object:Gem::Requirement
|
205
|
+
requirements:
|
206
|
+
- - ">="
|
207
|
+
- !ruby/object:Gem::Version
|
208
|
+
version: '0'
|
209
|
+
- !ruby/object:Gem::Dependency
|
210
|
+
name: logger
|
211
|
+
requirement: !ruby/object:Gem::Requirement
|
212
|
+
requirements:
|
213
|
+
- - ">="
|
214
|
+
- !ruby/object:Gem::Version
|
215
|
+
version: '0'
|
216
|
+
type: :development
|
217
|
+
prerelease: false
|
218
|
+
version_requirements: !ruby/object:Gem::Requirement
|
219
|
+
requirements:
|
220
|
+
- - ">="
|
221
|
+
- !ruby/object:Gem::Version
|
222
|
+
version: '0'
|
195
223
|
description: Database-backed Active Job backend.
|
196
224
|
email:
|
197
225
|
- rosa@37signals.com
|