good_job 1.99.0 → 2.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +58 -0
- data/README.md +34 -19
- data/lib/generators/good_job/install_generator.rb +6 -6
- data/lib/generators/good_job/templates/install/migrations/create_good_jobs.rb.erb +1 -0
- data/lib/generators/good_job/templates/update/migrations/01_create_good_jobs.rb +8 -0
- data/lib/generators/good_job/update_generator.rb +4 -6
- data/lib/good_job/active_job_extensions/concurrency.rb +6 -2
- data/lib/good_job/adapter.rb +7 -37
- data/lib/good_job/configuration.rb +21 -20
- data/lib/good_job/job.rb +9 -65
- data/lib/good_job/lockable.rb +4 -4
- data/lib/good_job/scheduler.rb +3 -1
- data/lib/good_job/version.rb +1 -1
- data/lib/good_job.rb +1 -29
- metadata +2 -5
- data/lib/generators/good_job/templates/update/migrations/02_add_active_job_id_concurrency_key_cron_key_to_good_jobs.rb +0 -16
- data/lib/generators/good_job/templates/update/migrations/03_add_active_job_id_index_and_concurrency_key_index_to_good_jobs.rb +0 -33
- data/lib/generators/good_job/templates/update/migrations/04_add_retried_good_job_id_to_good_jobs.rb +0 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 11a59540e5e10acc24b9010cb14dc8cbce2f43e8c2f1fe886b6fcf0895a978f2
|
4
|
+
data.tar.gz: 6fea5677587740d390f6eaa3dc903cee7c26a8576f14dd91f85f8886637d634b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '087af5fa1eaf81eff5078b5e3303e202aa73ea022d7018d60f01c6abb5a808a9442278e87490f846475c626bb5b5dd320537d68c16697ca54e9f30147f5b9225'
|
7
|
+
data.tar.gz: d19960b918937484e0f37eb0456fc3352dc2f4394fab4b0477bde7dedab789f2ce63c48b4971e38d2ff3a5d8725f1761afd425426ad384766f34cf549c35009e
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,63 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [v2.0.2](https://github.com/bensheldon/good_job/tree/v2.0.2) (2021-08-27)
|
4
|
+
|
5
|
+
[Full Changelog](https://github.com/bensheldon/good_job/compare/v1.99.1...v2.0.2)
|
6
|
+
|
7
|
+
**Closed issues:**
|
8
|
+
|
9
|
+
- Migrations generator assumes migrations are in db/migrate [\#352](https://github.com/bensheldon/good_job/issues/352)
|
10
|
+
|
11
|
+
**Merged pull requests:**
|
12
|
+
|
13
|
+
- v2.0: Generators support multiple databases: `--database` option, `migrations_paths`, custom `GoodJob.active_record_parent_class` [\#354](https://github.com/bensheldon/good_job/pull/354) ([bensheldon](https://github.com/bensheldon))
|
14
|
+
- README style/typo fixes: "web server" and possessive "Rails'" [\#350](https://github.com/bensheldon/good_job/pull/350) ([aried3r](https://github.com/aried3r))
|
15
|
+
- Add examples of setting config.good\_job.queues [\#349](https://github.com/bensheldon/good_job/pull/349) ([zachmargolis](https://github.com/zachmargolis))
|
16
|
+
|
17
|
+
## [v1.99.1](https://github.com/bensheldon/good_job/tree/v1.99.1) (2021-08-27)
|
18
|
+
|
19
|
+
[Full Changelog](https://github.com/bensheldon/good_job/compare/v2.0.1...v1.99.1)
|
20
|
+
|
21
|
+
**Closed issues:**
|
22
|
+
|
23
|
+
- Does Good job support delay method? [\#344](https://github.com/bensheldon/good_job/issues/344)
|
24
|
+
|
25
|
+
## [v2.0.1](https://github.com/bensheldon/good_job/tree/v2.0.1) (2021-08-24)
|
26
|
+
|
27
|
+
[Full Changelog](https://github.com/bensheldon/good_job/compare/v2.0.0...v2.0.1)
|
28
|
+
|
29
|
+
**Implemented enhancements:**
|
30
|
+
|
31
|
+
- Suppress backtrace of ConcurrencyExceededError [\#348](https://github.com/bensheldon/good_job/pull/348) ([reczy](https://github.com/reczy))
|
32
|
+
|
33
|
+
**Closed issues:**
|
34
|
+
|
35
|
+
- Is there any value in seeing a backtrace for ConcurrencyExceededError? [\#347](https://github.com/bensheldon/good_job/issues/347)
|
36
|
+
- Release GoodJob 2.0 [\#307](https://github.com/bensheldon/good_job/issues/307)
|
37
|
+
- Unhandled ActiveJob errors should trigger GoodJob.on\_thread\_error [\#247](https://github.com/bensheldon/good_job/issues/247)
|
38
|
+
|
39
|
+
## [v2.0.0](https://github.com/bensheldon/good_job/tree/v2.0.0) (2021-08-24)
|
40
|
+
|
41
|
+
[Full Changelog](https://github.com/bensheldon/good_job/compare/v1.99.0...v2.0.0)
|
42
|
+
|
43
|
+
**Implemented enhancements:**
|
44
|
+
|
45
|
+
- Concurrency's enqueue\_limit should exclude performing jobs from count [\#317](https://github.com/bensheldon/good_job/issues/317)
|
46
|
+
- Rename `:async` to `:async_all`; `:async_server` to `:async` and set as Development environment default; do not poll in async development [\#343](https://github.com/bensheldon/good_job/pull/343) ([bensheldon](https://github.com/bensheldon))
|
47
|
+
- Exclude executing jobs from Concurrency's enqueue\_limit's count [\#342](https://github.com/bensheldon/good_job/pull/342) ([bensheldon](https://github.com/bensheldon))
|
48
|
+
- Unhandled ActiveJob errors should trigger GoodJob.on\_thread\_error [\#312](https://github.com/bensheldon/good_job/pull/312) ([bensheldon](https://github.com/bensheldon))
|
49
|
+
|
50
|
+
**Closed issues:**
|
51
|
+
|
52
|
+
- Swap behavior of `async` with `async_server`; rename `async` execution mode to be `async_all`; default `async` in Development; [\#340](https://github.com/bensheldon/good_job/issues/340)
|
53
|
+
- Add hyphen to lock key. e.g. "\[table\_name\]-\[column\]" instead of "\[table\_name\]\[column\]" [\#335](https://github.com/bensheldon/good_job/issues/335)
|
54
|
+
- Use `async_server` as default execution mode in Development environment [\#139](https://github.com/bensheldon/good_job/issues/139)
|
55
|
+
|
56
|
+
**Merged pull requests:**
|
57
|
+
|
58
|
+
- Remove v1.0 deprecation notices and incremental migrations [\#338](https://github.com/bensheldon/good_job/pull/338) ([bensheldon](https://github.com/bensheldon))
|
59
|
+
- Lock GoodJob::Job on active\_job\_id instead of the row id; adds separator hyphen to lock key [\#337](https://github.com/bensheldon/good_job/pull/337) ([bensheldon](https://github.com/bensheldon))
|
60
|
+
|
3
61
|
## [v1.99.0](https://github.com/bensheldon/good_job/tree/v1.99.0) (2021-08-24)
|
4
62
|
|
5
63
|
[Full Changelog](https://github.com/bensheldon/good_job/compare/v1.13.2...v1.99.0)
|
data/README.md
CHANGED
@@ -86,6 +86,13 @@ For more of the story of GoodJob, read the [introductory blog post](https://isla
|
|
86
86
|
$ bin/rails db:migrate
|
87
87
|
```
|
88
88
|
|
89
|
+
Optional: If using Rails' multiple databases with the `migrations_paths` configuration option, use the `--database` option:
|
90
|
+
|
91
|
+
```bash
|
92
|
+
bin/rails g good_job:install --database animals
|
93
|
+
bin/rails db:migrate:animals
|
94
|
+
```
|
95
|
+
|
89
96
|
1. Configure the ActiveJob adapter:
|
90
97
|
|
91
98
|
```ruby
|
@@ -125,10 +132,10 @@ For more of the story of GoodJob, read the [introductory blog post](https://isla
|
|
125
132
|
- GoodJob can also be configured to execute jobs within the web server process to save on resources. This is useful for low-workloads when economy is paramount.
|
126
133
|
|
127
134
|
```
|
128
|
-
$ GOOD_JOB_EXECUTION_MODE=
|
135
|
+
$ GOOD_JOB_EXECUTION_MODE=async rails server
|
129
136
|
```
|
130
137
|
|
131
|
-
Additional configuration is likely necessary, see the reference below for
|
138
|
+
Additional configuration is likely necessary, see the reference below for configuration.
|
132
139
|
|
133
140
|
## Compatibility
|
134
141
|
|
@@ -213,16 +220,17 @@ Additional configuration can be provided via `config.good_job.OPTION = ...` for
|
|
213
220
|
config.active_job.queue_adapter = :good_job
|
214
221
|
|
215
222
|
# Configure options individually...
|
216
|
-
config.good_job.execution_mode = :
|
223
|
+
config.good_job.execution_mode = :async
|
217
224
|
config.good_job.max_threads = 5
|
218
225
|
config.good_job.poll_interval = 30 # seconds
|
219
226
|
config.good_job.shutdown_timeout = 25 # seconds
|
220
227
|
config.good_job.enable_cron = true
|
221
228
|
config.good_job.cron = { example: { cron: '0 * * * *', class: 'ExampleJob' } }
|
229
|
+
config.good_job.queues = '*'
|
222
230
|
|
223
231
|
# ...or all at once.
|
224
232
|
config.good_job = {
|
225
|
-
execution_mode: :
|
233
|
+
execution_mode: :async,
|
226
234
|
max_threads: 5,
|
227
235
|
poll_interval: 30,
|
228
236
|
shutdown_timeout: 25,
|
@@ -233,6 +241,7 @@ config.good_job = {
|
|
233
241
|
class: 'ExampleJob'
|
234
242
|
},
|
235
243
|
},
|
244
|
+
queues: '*',
|
236
245
|
}
|
237
246
|
```
|
238
247
|
|
@@ -241,11 +250,11 @@ Available configuration options are:
|
|
241
250
|
- `execution_mode` (symbol) specifies how and where jobs should be executed. You can also set this with the environment variable `GOOD_JOB_EXECUTION_MODE`. It can be any one of:
|
242
251
|
- `:inline` executes jobs immediately in whatever process queued them (usually the web server process). This should only be used in test and development environments.
|
243
252
|
- `:external` causes the adapter to enqueue jobs, but not execute them. When using this option (the default for production environments), you’ll need to use the command-line tool to actually execute your jobs.
|
244
|
-
- `:async_server` executes jobs in separate threads within the Rails
|
245
|
-
- `:
|
246
|
-
- `max_threads` (integer) sets the maximum number of threads to use when `execution_mode` is set to `:async
|
247
|
-
- `queues` (string) determines which queues to execute jobs from when `execution_mode` is set to `:async
|
248
|
-
- `poll_interval` (integer) sets the number of seconds between polls for jobs when `execution_mode` is set to `:async
|
253
|
+
- `:async` (or `:async_server`) executes jobs in separate threads within the Rails web server process (`bundle exec rails server`). It can be more economical for small workloads because you don’t need a separate machine or environment for running your jobs, but if your web server is under heavy load or your jobs require a lot of resources, you should choose `:external` instead. When not in the Rails web server, jobs will execute in `:external` mode to ensure jobs are not executed within `rails console`, `rails db:migrate`, `rails assets:prepare`, etc.
|
254
|
+
- `:async_all` executes jobs in separate threads in _any_ Rails process.
|
255
|
+
- `max_threads` (integer) sets the maximum number of threads to use when `execution_mode` is set to `:async`. You can also set this with the environment variable `GOOD_JOB_MAX_THREADS`.
|
256
|
+
- `queues` (string) determines which queues to execute jobs from when `execution_mode` is set to `:async`. See the description of `good_job start` for more details on the format of this string. You can also set this with the environment variable `GOOD_JOB_QUEUES`.
|
257
|
+
- `poll_interval` (integer) sets the number of seconds between polls for jobs when `execution_mode` is set to `:async`. You can also set this with the environment variable `GOOD_JOB_POLL_INTERVAL`.
|
249
258
|
- `max_cache` (integer) sets the maximum number of scheduled jobs that will be stored in memory to reduce execution latency when also polling for scheduled jobs. Caching 10,000 scheduled jobs uses approximately 20MB of memory. You can also set this with the environment variable `GOOD_JOB_MAX_CACHE`.
|
250
259
|
- `shutdown_timeout` (float) number of seconds to wait for jobs to finish when shutting down before stopping the thread. Defaults to forever: `-1`. You can also set this with the environment variable `GOOD_JOB_SHUTDOWN_TIMEOUT`.
|
251
260
|
- `enable_cron` (boolean) whether to run cron process. Defaults to `false`. You can also set this with the environment variable `GOOD_JOB_ENABLE_CRON`.
|
@@ -257,7 +266,7 @@ By default, GoodJob configures the following execution modes per environment:
|
|
257
266
|
|
258
267
|
# config/environments/development.rb
|
259
268
|
config.active_job.queue_adapter = :good_job
|
260
|
-
config.good_job.execution_mode = :
|
269
|
+
config.good_job.execution_mode = :async
|
261
270
|
|
262
271
|
# config/environments/test.rb
|
263
272
|
config.active_job.queue_adapter = :good_job
|
@@ -387,7 +396,7 @@ config.good_job.enable_cron = ENV['DYNO'] == 'worker.1' # or `true` or via $GOOD
|
|
387
396
|
|
388
397
|
# Configure cron with a hash that has a unique key for each recurring job
|
389
398
|
config.good_job.cron = {
|
390
|
-
# Every 15 minutes, enqueue `ExampleJob.set(priority: -10).perform_later(
|
399
|
+
# Every 15 minutes, enqueue `ExampleJob.set(priority: -10).perform_later(42, name: "Alice")`
|
391
400
|
frequent_task: { # each recurring job must have a unique key
|
392
401
|
cron: "*/15 * * * *", # cron-style scheduling format by fugit gem
|
393
402
|
class: "ExampleJob", # reference the Job class with a string
|
@@ -419,6 +428,12 @@ To perform upgrades to the GoodJob database tables:
|
|
419
428
|
bin/rails g good_job:update
|
420
429
|
```
|
421
430
|
|
431
|
+
Optional: If using Rails' multiple databases with the `migrations_paths` configuration option, use the `--database` option:
|
432
|
+
|
433
|
+
```bash
|
434
|
+
$ bin/rails g good_job:update --database animals
|
435
|
+
```
|
436
|
+
|
422
437
|
1. Run the database migration locally
|
423
438
|
|
424
439
|
```bash
|
@@ -430,8 +445,7 @@ To perform upgrades to the GoodJob database tables:
|
|
430
445
|
|
431
446
|
#### Upgrading v1 to v2
|
432
447
|
|
433
|
-
GoodJob v2 introduces a new Advisory Lock key format that is different than the v1 advisory lock key format; it's therefore necessary to perform a simple, but staged production upgrade. If you are already using `>= v1.12+` no other changes are
|
434
|
-
necessary.
|
448
|
+
GoodJob v2 introduces a new Advisory Lock key format that is different than the v1 advisory lock key format; it's therefore necessary to perform a simple, but staged production upgrade. If you are already using `>= v1.12+` no other changes are necessary.
|
435
449
|
|
436
450
|
1. Upgrade your production environment to `v1.99.x` following the minor version upgrade process, including database migrations. `v1.99` is a transitional release that is safely compatible with both `v1.x` and `v2.0.0` because it uses both `v1`- and `v2`-formatted advisory locks.
|
437
451
|
1. Address any deprecation warnings generated by `v1.99`.
|
@@ -441,6 +455,7 @@ Notable changes:
|
|
441
455
|
|
442
456
|
- Renames `:async_server` execution mode to `:async`; renames prior `:async` execution mode to `:async_all`.
|
443
457
|
- Sets default Development environment's execution mode to `:async` with disabled polling.
|
458
|
+
- Excludes performing jobs from `enqueue_limit`'s count in `GoodJob::ActiveJobExtensions::Concurrency`.
|
444
459
|
- Triggers `GoodJob.on_thread_error` for unhandled ActiveJob exceptions.
|
445
460
|
- Renames `GoodJob.reperform_jobs_on_standard_error` accessor to `GoodJob.retry_on_unhandled_error`.
|
446
461
|
- Renames `GoodJob::Adapter.shutdown(wait:)` argument to `GoodJob::Adapter.shutdown(timeout:)`.
|
@@ -599,7 +614,7 @@ Keep in mind, queue operations and management is an advanced discipline. This st
|
|
599
614
|
|
600
615
|
### Database connections
|
601
616
|
|
602
|
-
Each GoodJob execution thread requires its own database connection that is automatically checked out from Rails’
|
617
|
+
Each GoodJob execution thread requires its own database connection that is automatically checked out from Rails’ connection pool. _Allowing GoodJob to create more threads than available database connections can lead to timeouts and is not recommended._ For example:
|
603
618
|
|
604
619
|
```yaml
|
605
620
|
# config/database.yml
|
@@ -608,7 +623,7 @@ pool: <%= [ENV.fetch("RAILS_MAX_THREADS", 5).to_i, ENV.fetch("GOOD_JOB_MAX_THREA
|
|
608
623
|
|
609
624
|
### Execute jobs async / in-process
|
610
625
|
|
611
|
-
GoodJob can execute jobs "async" in the same process as the
|
626
|
+
GoodJob can execute jobs "async" in the same process as the web server (e.g. `bin/rails s`). GoodJob's async execution mode offers benefits of economy by not requiring a separate job worker process, but with the tradeoff of increased complexity. Async mode can be configured in two ways:
|
612
627
|
|
613
628
|
- Via Rails configuration:
|
614
629
|
|
@@ -617,11 +632,11 @@ GoodJob can execute jobs "async" in the same process as the webserver (e.g. `bin
|
|
617
632
|
config.active_job.queue_adapter = :good_job
|
618
633
|
|
619
634
|
# To change the execution mode
|
620
|
-
config.good_job.execution_mode = :
|
635
|
+
config.good_job.execution_mode = :async
|
621
636
|
|
622
637
|
# Or with more configuration
|
623
638
|
config.good_job = {
|
624
|
-
execution_mode: :
|
639
|
+
execution_mode: :async,
|
625
640
|
max_threads: 4,
|
626
641
|
poll_interval: 30
|
627
642
|
}
|
@@ -630,7 +645,7 @@ GoodJob can execute jobs "async" in the same process as the webserver (e.g. `bin
|
|
630
645
|
- Or, with environment variables:
|
631
646
|
|
632
647
|
```bash
|
633
|
-
$ GOOD_JOB_EXECUTION_MODE=
|
648
|
+
$ GOOD_JOB_EXECUTION_MODE=async GOOD_JOB_MAX_THREADS=4 GOOD_JOB_POLL_INTERVAL=30 bin/rails server
|
634
649
|
```
|
635
650
|
|
636
651
|
Depending on your application configuration, you may need to take additional steps:
|
@@ -642,7 +657,7 @@ Depending on your application configuration, you may need to take additional ste
|
|
642
657
|
pool: <%= ENV.fetch("RAILS_MAX_THREADS", 5).to_i + ENV.fetch("GOOD_JOB_MAX_THREADS", 4).to_i %>
|
643
658
|
```
|
644
659
|
|
645
|
-
- When running Puma with workers (`WEB_CONCURRENCY > 0`) or another process-forking
|
660
|
+
- When running Puma with workers (`WEB_CONCURRENCY > 0`) or another process-forking web server, GoodJob's threadpool schedulers should be stopped before forking, restarted after fork, and cleanly shut down on exit. Stopping GoodJob's scheduler pre-fork is recommended to ensure that GoodJob does not continue executing jobs in the parent/controller process. For example, with Puma:
|
646
661
|
|
647
662
|
```ruby
|
648
663
|
# config/puma.rb
|
@@ -1,23 +1,23 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
require 'rails/generators'
|
3
3
|
require 'rails/generators/active_record'
|
4
|
+
|
4
5
|
module GoodJob
|
5
6
|
#
|
6
7
|
# Rails generator used for setting up GoodJob in a Rails application.
|
7
8
|
# Run it with +bin/rails g good_job:install+ in your console.
|
8
9
|
#
|
9
10
|
class InstallGenerator < Rails::Generators::Base
|
10
|
-
include
|
11
|
+
include ActiveRecord::Generators::Migration
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
end
|
13
|
+
TEMPLATES = File.join(File.dirname(__FILE__), "templates/install")
|
14
|
+
source_paths << TEMPLATES
|
15
15
|
|
16
|
-
|
16
|
+
class_option :database, type: :string, aliases: %i(--db), desc: "The database for your migration. By default, the current environment's primary database is used."
|
17
17
|
|
18
18
|
# Generates monolithic migration file that contains all database changes.
|
19
19
|
def create_migration_file
|
20
|
-
migration_template 'migrations/create_good_jobs.rb.erb',
|
20
|
+
migration_template 'migrations/create_good_jobs.rb.erb', File.join(db_migrate_path, "create_good_jobs.rb")
|
21
21
|
end
|
22
22
|
end
|
23
23
|
end
|
@@ -13,9 +13,17 @@ class CreateGoodJobs < ActiveRecord::Migration[5.2]
|
|
13
13
|
t.text :error
|
14
14
|
|
15
15
|
t.timestamps
|
16
|
+
|
17
|
+
t.uuid :active_job_id
|
18
|
+
t.text :concurrency_key
|
19
|
+
t.text :cron_key
|
20
|
+
t.uuid :retried_good_job_id
|
16
21
|
end
|
17
22
|
|
18
23
|
add_index :good_jobs, :scheduled_at, where: "(finished_at IS NULL)", name: "index_good_jobs_on_scheduled_at"
|
19
24
|
add_index :good_jobs, [:queue_name, :scheduled_at], where: "(finished_at IS NULL)", name: :index_good_jobs_on_queue_name_and_scheduled_at
|
25
|
+
add_index :good_jobs, [:active_job_id, :created_at], name: :index_good_jobs_on_active_job_id_and_created_at
|
26
|
+
add_index :good_jobs, :concurrency_key, where: "(finished_at IS NULL)", name: :index_good_jobs_on_concurrency_key_when_unfinished
|
27
|
+
add_index :good_jobs, [:cron_key, :created_at], name: :index_good_jobs_on_cron_key_and_created_at
|
20
28
|
end
|
21
29
|
end
|
@@ -8,22 +8,20 @@ module GoodJob
|
|
8
8
|
# Run it with +bin/rails g good_job:update+ in your console.
|
9
9
|
#
|
10
10
|
class UpdateGenerator < Rails::Generators::Base
|
11
|
-
include
|
12
|
-
|
13
|
-
class << self
|
14
|
-
delegate :next_migration_number, to: ActiveRecord::Generators::Base
|
15
|
-
end
|
11
|
+
include ActiveRecord::Generators::Migration
|
16
12
|
|
17
13
|
TEMPLATES = File.join(File.dirname(__FILE__), "templates/update")
|
18
14
|
source_paths << TEMPLATES
|
19
15
|
|
16
|
+
class_option :database, type: :string, aliases: %i(--db), desc: "The database for your migration. By default, the current environment's primary database is used."
|
17
|
+
|
20
18
|
# Generates incremental migration files unless they already exist.
|
21
19
|
# All migrations should be idempotent e.g. +add_index+ is guarded with +if_index_exists?+
|
22
20
|
def update_migration_files
|
23
21
|
migration_templates = Dir.children(File.join(TEMPLATES, 'migrations')).sort
|
24
22
|
migration_templates.each do |template_file|
|
25
23
|
destination_file = template_file.match(/^\d*_(.*\.rb)/)[1] # 01_create_good_jobs.rb.erb => create_good_jobs.rb
|
26
|
-
migration_template "migrations/#{template_file}",
|
24
|
+
migration_template "migrations/#{template_file}", File.join(db_migrate_path, destination_file), skip: true
|
27
25
|
end
|
28
26
|
end
|
29
27
|
end
|
@@ -4,7 +4,11 @@ module GoodJob
|
|
4
4
|
module Concurrency
|
5
5
|
extend ActiveSupport::Concern
|
6
6
|
|
7
|
-
ConcurrencyExceededError
|
7
|
+
class ConcurrencyExceededError < StandardError
|
8
|
+
def backtrace
|
9
|
+
[] # suppress backtrace
|
10
|
+
end
|
11
|
+
end
|
8
12
|
|
9
13
|
included do
|
10
14
|
class_attribute :good_job_concurrency_config, instance_accessor: false, default: {}
|
@@ -24,7 +28,7 @@ module GoodJob
|
|
24
28
|
|
25
29
|
GoodJob::Job.new.with_advisory_lock(key: key, function: "pg_advisory_lock") do
|
26
30
|
# TODO: Why is `unscoped` necessary? Nested scope is bleeding into subsequent query?
|
27
|
-
enqueue_concurrency = GoodJob::Job.unscoped.where(concurrency_key: key).unfinished.count
|
31
|
+
enqueue_concurrency = GoodJob::Job.unscoped.where(concurrency_key: key).unfinished.advisory_unlocked.count
|
28
32
|
# The job has not yet been enqueued, so check if adding it will go over the limit
|
29
33
|
block.call unless enqueue_concurrency + 1 > limit
|
30
34
|
end
|
data/lib/good_job/adapter.rb
CHANGED
@@ -4,16 +4,13 @@ module GoodJob
|
|
4
4
|
# ActiveJob Adapter.
|
5
5
|
#
|
6
6
|
class Adapter
|
7
|
-
# Valid execution modes.
|
8
|
-
EXECUTION_MODES = [:async, :async_server, :external, :inline].freeze
|
9
|
-
|
10
7
|
# @param execution_mode [Symbol, nil] specifies how and where jobs should be executed. You can also set this with the environment variable +GOOD_JOB_EXECUTION_MODE+.
|
11
8
|
#
|
12
9
|
# - +:inline+ executes jobs immediately in whatever process queued them (usually the web server process). This should only be used in test and development environments.
|
13
10
|
# - +:external+ causes the adapter to enqueue jobs, but not execute them. When using this option (the default for production environments), you'll need to use the command-line tool to actually execute your jobs.
|
14
|
-
# - +:async_server+ executes jobs in separate threads within the Rails
|
15
|
-
# When not in the Rails
|
16
|
-
# - +:
|
11
|
+
# - +:async+ (or +:async_server+) executes jobs in separate threads within the Rails web server process (`bundle exec rails server`). It can be more economical for small workloads because you don't need a separate machine or environment for running your jobs, but if your web server is under heavy load or your jobs require a lot of resources, you should choose +:external+ instead.
|
12
|
+
# When not in the Rails web server, jobs will execute in +:external+ mode to ensure jobs are not executed within `rails console`, `rails db:migrate`, `rails assets:prepare`, etc.
|
13
|
+
# - +:async_all+ executes jobs in any Rails process.
|
17
14
|
#
|
18
15
|
# The default value depends on the Rails environment:
|
19
16
|
#
|
@@ -24,23 +21,6 @@ module GoodJob
|
|
24
21
|
# @param queues [String, nil] determines which queues to execute jobs from when +execution_mode+ is set to +:async+. See {file:README.md#optimize-queues-threads-and-processes} for more details on the format of this string. You can also set this with the environment variable +GOOD_JOB_QUEUES+. Defaults to +"*"+.
|
25
22
|
# @param poll_interval [Integer, nil] sets the number of seconds between polls for jobs when +execution_mode+ is set to +:async+. You can also set this with the environment variable +GOOD_JOB_POLL_INTERVAL+. Defaults to +1+.
|
26
23
|
def initialize(execution_mode: nil, queues: nil, max_threads: nil, poll_interval: nil)
|
27
|
-
if caller[0..4].find { |c| c.include?("/config/application.rb") || c.include?("/config/environments/") }
|
28
|
-
ActiveSupport::Deprecation.warn(<<~DEPRECATION)
|
29
|
-
GoodJob no longer recommends creating a GoodJob::Adapter instance:
|
30
|
-
|
31
|
-
config.active_job.queue_adapter = GoodJob::Adapter.new...
|
32
|
-
|
33
|
-
Instead, configure GoodJob through configuration:
|
34
|
-
|
35
|
-
config.active_job.queue_adapter = :good_job
|
36
|
-
config.good_job.execution_mode = :#{execution_mode}
|
37
|
-
config.good_job.max_threads = #{max_threads}
|
38
|
-
config.good_job.poll_interval = #{poll_interval}
|
39
|
-
# etc...
|
40
|
-
|
41
|
-
DEPRECATION
|
42
|
-
end
|
43
|
-
|
44
24
|
@configuration = GoodJob::Configuration.new(
|
45
25
|
{
|
46
26
|
execution_mode: execution_mode,
|
@@ -105,18 +85,8 @@ module GoodJob
|
|
105
85
|
# * +-1+, the scheduler will wait until the shutdown is complete.
|
106
86
|
# * +0+, the scheduler will immediately shutdown and stop any threads.
|
107
87
|
# * A positive number will wait that many seconds before stopping any remaining active threads.
|
108
|
-
# @param wait [Boolean, nil] Deprecated. Use +timeout:+ instead.
|
109
88
|
# @return [void]
|
110
|
-
def shutdown(timeout: :default
|
111
|
-
timeout = if wait.nil?
|
112
|
-
timeout
|
113
|
-
else
|
114
|
-
ActiveSupport::Deprecation.warn(
|
115
|
-
"Using `GoodJob::Adapter.shutdown` with `wait:` kwarg is deprecated; use `timeout:` kwarg instead e.g. GoodJob::Adapter.shutdown(timeout: #{wait ? '-1' : 'nil'})"
|
116
|
-
)
|
117
|
-
wait ? -1 : nil
|
118
|
-
end
|
119
|
-
|
89
|
+
def shutdown(timeout: :default)
|
120
90
|
timeout = if timeout == :default
|
121
91
|
@configuration.shutdown_timeout
|
122
92
|
else
|
@@ -130,15 +100,15 @@ module GoodJob
|
|
130
100
|
# Whether in +:async+ execution mode.
|
131
101
|
# @return [Boolean]
|
132
102
|
def execute_async?
|
133
|
-
@configuration.execution_mode
|
134
|
-
@configuration.execution_mode
|
103
|
+
@configuration.execution_mode == :async_all ||
|
104
|
+
@configuration.execution_mode.in?([:async, :async_server]) && in_server_process?
|
135
105
|
end
|
136
106
|
|
137
107
|
# Whether in +:external+ execution mode.
|
138
108
|
# @return [Boolean]
|
139
109
|
def execute_externally?
|
140
110
|
@configuration.execution_mode == :external ||
|
141
|
-
@configuration.execution_mode
|
111
|
+
@configuration.execution_mode.in?([:async, :async_server]) && !in_server_process?
|
142
112
|
end
|
143
113
|
|
144
114
|
# Whether in +:inline+ execution mode.
|
@@ -12,6 +12,8 @@ module GoodJob
|
|
12
12
|
DEFAULT_MAX_THREADS = 5
|
13
13
|
# Default number of seconds between polls for jobs
|
14
14
|
DEFAULT_POLL_INTERVAL = 10
|
15
|
+
# Default poll interval for async in development environment
|
16
|
+
DEFAULT_DEVELOPMENT_ASYNC_POLL_INTERVAL = -1
|
15
17
|
# Default number of threads to use per {Scheduler}
|
16
18
|
DEFAULT_MAX_CACHE = 10000
|
17
19
|
# Default number of seconds to preserve jobs for {CLI#cleanup_preserved_jobs}
|
@@ -58,19 +60,10 @@ module GoodJob
|
|
58
60
|
end
|
59
61
|
|
60
62
|
if mode
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
execution mode to be equivalent to 'async_server' and only execute
|
66
|
-
within the webserver process.
|
67
|
-
|
68
|
-
To continue using the v1.0 semantics of 'async', use `async_all` instead.
|
69
|
-
|
70
|
-
DEPRECATION
|
71
|
-
end
|
72
|
-
mode_sym
|
73
|
-
elsif Rails.env.development? || Rails.env.test?
|
63
|
+
mode.to_sym
|
64
|
+
elsif Rails.env.development?
|
65
|
+
:async
|
66
|
+
elsif Rails.env.test?
|
74
67
|
:inline
|
75
68
|
else
|
76
69
|
:external
|
@@ -109,12 +102,19 @@ module GoodJob
|
|
109
102
|
# poll (using this interval) for new queued jobs to execute.
|
110
103
|
# @return [Integer]
|
111
104
|
def poll_interval
|
112
|
-
(
|
105
|
+
interval = (
|
113
106
|
options[:poll_interval] ||
|
114
107
|
rails_config[:poll_interval] ||
|
115
|
-
env['GOOD_JOB_POLL_INTERVAL']
|
116
|
-
|
117
|
-
|
108
|
+
env['GOOD_JOB_POLL_INTERVAL']
|
109
|
+
)
|
110
|
+
|
111
|
+
if interval
|
112
|
+
interval.to_i
|
113
|
+
elsif Rails.env.development? && execution_mode.in?([:async, :async_all, :async_server])
|
114
|
+
DEFAULT_DEVELOPMENT_ASYNC_POLL_INTERVAL
|
115
|
+
else
|
116
|
+
DEFAULT_POLL_INTERVAL
|
117
|
+
end
|
118
118
|
end
|
119
119
|
|
120
120
|
# The maximum number of future-scheduled jobs to store in memory.
|
@@ -147,12 +147,13 @@ module GoodJob
|
|
147
147
|
def enable_cron
|
148
148
|
value = ActiveModel::Type::Boolean.new.cast(
|
149
149
|
options[:enable_cron] ||
|
150
|
-
|
151
|
-
|
152
|
-
|
150
|
+
rails_config[:enable_cron] ||
|
151
|
+
env['GOOD_JOB_ENABLE_CRON'] ||
|
152
|
+
false
|
153
153
|
)
|
154
154
|
value && cron.size.positive?
|
155
155
|
end
|
156
|
+
|
156
157
|
alias enable_cron? enable_cron
|
157
158
|
|
158
159
|
def cron
|
data/lib/good_job/job.rb
CHANGED
@@ -16,7 +16,7 @@ module GoodJob
|
|
16
16
|
DEFAULT_PRIORITY = 0
|
17
17
|
|
18
18
|
self.table_name = 'good_jobs'
|
19
|
-
self.advisory_lockable_column = '
|
19
|
+
self.advisory_lockable_column = 'active_job_id'
|
20
20
|
|
21
21
|
attr_readonly :serialized_params
|
22
22
|
|
@@ -52,20 +52,6 @@ module GoodJob
|
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
55
|
-
def self._migration_pending_warning
|
56
|
-
ActiveSupport::Deprecation.warn(<<~DEPRECATION)
|
57
|
-
GoodJob has pending database migrations. To create the migration files, run:
|
58
|
-
|
59
|
-
rails generate good_job:update
|
60
|
-
|
61
|
-
To apply the migration files, run:
|
62
|
-
|
63
|
-
rails db:migrate
|
64
|
-
|
65
|
-
DEPRECATION
|
66
|
-
nil
|
67
|
-
end
|
68
|
-
|
69
55
|
# Get Jobs with given class name
|
70
56
|
# @!method with_job_class
|
71
57
|
# @!scope class
|
@@ -78,14 +64,7 @@ module GoodJob
|
|
78
64
|
# @!method unfinished
|
79
65
|
# @!scope class
|
80
66
|
# @return [ActiveRecord::Relation]
|
81
|
-
scope :unfinished, (
|
82
|
-
if column_names.include?('finished_at')
|
83
|
-
where(finished_at: nil)
|
84
|
-
else
|
85
|
-
ActiveSupport::Deprecation.warn('GoodJob expects a good_jobs.finished_at column to exist. Please see the GoodJob README.md for migration instructions.')
|
86
|
-
nil
|
87
|
-
end
|
88
|
-
end)
|
67
|
+
scope :unfinished, -> { where(finished_at: nil) }
|
89
68
|
|
90
69
|
# Get Jobs that are not scheduled for a later time than now (i.e. jobs that
|
91
70
|
# are not scheduled or scheduled for earlier than the current time).
|
@@ -231,6 +210,7 @@ module GoodJob
|
|
231
210
|
def self.enqueue(active_job, scheduled_at: nil, create_with_advisory_lock: false)
|
232
211
|
ActiveSupport::Notifications.instrument("enqueue_job.good_job", { active_job: active_job, scheduled_at: scheduled_at, create_with_advisory_lock: create_with_advisory_lock }) do |instrument_payload|
|
233
212
|
good_job_args = {
|
213
|
+
active_job_id: active_job.job_id,
|
234
214
|
queue_name: active_job.queue_name.presence || DEFAULT_QUEUE_NAME,
|
235
215
|
priority: active_job.priority || DEFAULT_PRIORITY,
|
236
216
|
serialized_params: active_job.serialize,
|
@@ -238,26 +218,12 @@ module GoodJob
|
|
238
218
|
create_with_advisory_lock: create_with_advisory_lock,
|
239
219
|
}
|
240
220
|
|
241
|
-
if
|
242
|
-
good_job_args[:active_job_id] = active_job.job_id
|
243
|
-
else
|
244
|
-
_migration_pending_warning
|
245
|
-
end
|
246
|
-
|
247
|
-
if column_names.include?('concurrency_key')
|
248
|
-
good_job_args[:concurrency_key] = active_job.good_job_concurrency_key if active_job.respond_to?(:good_job_concurrency_key)
|
249
|
-
else
|
250
|
-
_migration_pending_warning
|
251
|
-
end
|
221
|
+
good_job_args[:concurrency_key] = active_job.good_job_concurrency_key if active_job.respond_to?(:good_job_concurrency_key)
|
252
222
|
|
253
|
-
if
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
good_job_args[:cron_key] = CurrentExecution.good_job.cron_key
|
258
|
-
end
|
259
|
-
else
|
260
|
-
_migration_pending_warning
|
223
|
+
if CurrentExecution.cron_key
|
224
|
+
good_job_args[:cron_key] = CurrentExecution.cron_key
|
225
|
+
elsif CurrentExecution.active_job_id == active_job.job_id
|
226
|
+
good_job_args[:cron_key] = CurrentExecution.good_job.cron_key
|
261
227
|
end
|
262
228
|
|
263
229
|
good_job = GoodJob::Job.new(**good_job_args)
|
@@ -267,11 +233,7 @@ module GoodJob
|
|
267
233
|
good_job.save!
|
268
234
|
active_job.provider_job_id = good_job.id
|
269
235
|
|
270
|
-
if
|
271
|
-
CurrentExecution.good_job.retried_good_job_id = good_job.id if CurrentExecution.good_job && CurrentExecution.good_job.active_job_id == active_job.job_id
|
272
|
-
else
|
273
|
-
_migration_pending_warning
|
274
|
-
end
|
236
|
+
CurrentExecution.good_job.retried_good_job_id = good_job.id if CurrentExecution.good_job && CurrentExecution.good_job.active_job_id == active_job.job_id
|
275
237
|
|
276
238
|
good_job
|
277
239
|
end
|
@@ -311,24 +273,6 @@ module GoodJob
|
|
311
273
|
self.class.unscoped.unfinished.owns_advisory_locked.exists?(id: id)
|
312
274
|
end
|
313
275
|
|
314
|
-
def active_job_id
|
315
|
-
if self.class.column_names.include?('active_job_id')
|
316
|
-
super
|
317
|
-
else
|
318
|
-
self.class._migration_pending_warning
|
319
|
-
serialized_params['job_id']
|
320
|
-
end
|
321
|
-
end
|
322
|
-
|
323
|
-
def cron_key
|
324
|
-
if self.class.column_names.include?('cron_key')
|
325
|
-
super
|
326
|
-
else
|
327
|
-
self.class._migration_pending_warning
|
328
|
-
nil
|
329
|
-
end
|
330
|
-
end
|
331
|
-
|
332
276
|
private
|
333
277
|
|
334
278
|
# @return [ExecutionResult]
|
data/lib/good_job/lockable.rb
CHANGED
@@ -51,7 +51,7 @@ module GoodJob
|
|
51
51
|
composed_cte = Arel::Nodes::As.new(cte_table, Arel::Nodes::SqlLiteral.new([cte_type, "(", cte_query.to_sql, ")"].join(' ')))
|
52
52
|
query = cte_table.project(cte_table[:id])
|
53
53
|
.with(composed_cte)
|
54
|
-
.where(Arel.sql(sanitize_sql_for_conditions(["#{function}(('x' || substr(md5(:table_name || #{connection.quote_table_name(cte_table.name)}.#{connection.quote_column_name(column)}::text), 1, 16))::bit(64)::bigint)", { table_name: table_name }])))
|
54
|
+
.where(Arel.sql(sanitize_sql_for_conditions(["#{function}(('x' || substr(md5(:table_name || '-' || #{connection.quote_table_name(cte_table.name)}.#{connection.quote_column_name(column)}::text), 1, 16))::bit(64)::bigint)", { table_name: table_name }])))
|
55
55
|
|
56
56
|
limit = original_query.arel.ast.limit
|
57
57
|
query.limit = limit.value if limit.present?
|
@@ -75,8 +75,8 @@ module GoodJob
|
|
75
75
|
join_sql = <<~SQL.squish
|
76
76
|
LEFT JOIN pg_locks ON pg_locks.locktype = 'advisory'
|
77
77
|
AND pg_locks.objsubid = 1
|
78
|
-
AND pg_locks.classid = ('x' || substr(md5(:table_name || #{quoted_table_name}.#{connection.quote_column_name(column)}::text), 1, 16))::bit(32)::int
|
79
|
-
AND pg_locks.objid = (('x' || substr(md5(:table_name || #{quoted_table_name}.#{connection.quote_column_name(column)}::text), 1, 16))::bit(64) << 32)::bit(32)::int
|
78
|
+
AND pg_locks.classid = ('x' || substr(md5(:table_name || '-' || #{quoted_table_name}.#{connection.quote_column_name(column)}::text), 1, 16))::bit(32)::int
|
79
|
+
AND pg_locks.objid = (('x' || substr(md5(:table_name || '-' || #{quoted_table_name}.#{connection.quote_column_name(column)}::text), 1, 16))::bit(64) << 32)::bit(32)::int
|
80
80
|
SQL
|
81
81
|
|
82
82
|
joins(sanitize_sql_for_conditions([join_sql, { table_name: table_name }]))
|
@@ -315,7 +315,7 @@ module GoodJob
|
|
315
315
|
# Default Advisory Lock key
|
316
316
|
# @return [String]
|
317
317
|
def lockable_key
|
318
|
-
|
318
|
+
"#{self.class.table_name}-#{self[self.class._advisory_lockable_column]}"
|
319
319
|
end
|
320
320
|
|
321
321
|
delegate :pg_or_jdbc_query, to: :class
|
data/lib/good_job/scheduler.rb
CHANGED
@@ -168,7 +168,9 @@ module GoodJob # :nodoc:
|
|
168
168
|
# @!visibility private
|
169
169
|
# @return [void]
|
170
170
|
def task_observer(time, output, thread_error)
|
171
|
-
|
171
|
+
error = thread_error || (output.is_a?(GoodJob::ExecutionResult) ? output.unhandled_error : nil)
|
172
|
+
GoodJob.on_thread_error.call(error) if error && GoodJob.on_thread_error.respond_to?(:call)
|
173
|
+
|
172
174
|
instrument("finished_job_task", { result: output, error: thread_error, time: time })
|
173
175
|
create_task if output
|
174
176
|
end
|
data/lib/good_job/version.rb
CHANGED
data/lib/good_job.rb
CHANGED
@@ -55,25 +55,6 @@ module GoodJob
|
|
55
55
|
# @return [Boolean, nil]
|
56
56
|
mattr_accessor :retry_on_unhandled_error, default: true
|
57
57
|
|
58
|
-
# @deprecated Use {GoodJob#retry_on_unhandled_error} instead.
|
59
|
-
# @return [Boolean, nil]
|
60
|
-
def self.reperform_jobs_on_standard_error
|
61
|
-
ActiveSupport::Deprecation.warn(
|
62
|
-
"Calling 'GoodJob.reperform_jobs_on_standard_error' is deprecated. Please use 'retry_on_unhandled_error'"
|
63
|
-
)
|
64
|
-
retry_on_unhandled_error
|
65
|
-
end
|
66
|
-
|
67
|
-
# @deprecated Use {GoodJob#retry_on_unhandled_error=} instead.
|
68
|
-
# @param value [Boolean]
|
69
|
-
# @return [Boolean]
|
70
|
-
def self.reperform_jobs_on_standard_error=(value)
|
71
|
-
ActiveSupport::Deprecation.warn(
|
72
|
-
"Setting 'GoodJob.reperform_jobs_on_standard_error=' is deprecated. Please use 'retry_on_unhandled_error='"
|
73
|
-
)
|
74
|
-
self.retry_on_unhandled_error = value
|
75
|
-
end
|
76
|
-
|
77
58
|
# @!attribute [rw] on_thread_error
|
78
59
|
# @!scope class
|
79
60
|
# This callable will be called when an exception reaches GoodJob (default: +nil+).
|
@@ -96,16 +77,7 @@ module GoodJob
|
|
96
77
|
# * +1..+, the scheduler will wait that many seconds before stopping any remaining active tasks.
|
97
78
|
# @param wait [Boolean] whether to wait for shutdown
|
98
79
|
# @return [void]
|
99
|
-
def self.shutdown(timeout: -1
|
100
|
-
timeout = if wait.nil?
|
101
|
-
timeout
|
102
|
-
else
|
103
|
-
ActiveSupport::Deprecation.warn(
|
104
|
-
"Using `GoodJob.shutdown` with `wait:` kwarg is deprecated; use `timeout:` kwarg instead e.g. GoodJob.shutdown(timeout: #{wait ? '-1' : 'nil'})"
|
105
|
-
)
|
106
|
-
wait ? -1 : nil
|
107
|
-
end
|
108
|
-
|
80
|
+
def self.shutdown(timeout: -1)
|
109
81
|
_shutdown_all(_executables, timeout: timeout)
|
110
82
|
end
|
111
83
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: good_job
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ben Sheldon
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-08-
|
11
|
+
date: 2021-08-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activejob
|
@@ -372,9 +372,6 @@ files:
|
|
372
372
|
- lib/generators/good_job/install_generator.rb
|
373
373
|
- lib/generators/good_job/templates/install/migrations/create_good_jobs.rb.erb
|
374
374
|
- lib/generators/good_job/templates/update/migrations/01_create_good_jobs.rb
|
375
|
-
- lib/generators/good_job/templates/update/migrations/02_add_active_job_id_concurrency_key_cron_key_to_good_jobs.rb
|
376
|
-
- lib/generators/good_job/templates/update/migrations/03_add_active_job_id_index_and_concurrency_key_index_to_good_jobs.rb
|
377
|
-
- lib/generators/good_job/templates/update/migrations/04_add_retried_good_job_id_to_good_jobs.rb
|
378
375
|
- lib/generators/good_job/update_generator.rb
|
379
376
|
- lib/good_job.rb
|
380
377
|
- lib/good_job/active_job_extensions.rb
|
@@ -1,16 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
class AddActiveJobIdConcurrencyKeyCronKeyToGoodJobs < ActiveRecord::Migration[5.2]
|
3
|
-
def change
|
4
|
-
reversible do |dir|
|
5
|
-
dir.up do
|
6
|
-
# Ensure this incremental update migration is idempotent
|
7
|
-
# with monolithic install migration.
|
8
|
-
return if connection.column_exists?(:good_jobs, :active_job_id)
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
add_column :good_jobs, :active_job_id, :uuid
|
13
|
-
add_column :good_jobs, :concurrency_key, :text
|
14
|
-
add_column :good_jobs, :cron_key, :text
|
15
|
-
end
|
16
|
-
end
|
@@ -1,33 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
class AddActiveJobIdIndexAndConcurrencyKeyIndexToGoodJobs < ActiveRecord::Migration[5.2]
|
3
|
-
disable_ddl_transaction!
|
4
|
-
|
5
|
-
UPDATE_BATCH_SIZE = 1_000
|
6
|
-
|
7
|
-
class GoodJobJobs < ActiveRecord::Base
|
8
|
-
self.table_name = "good_jobs"
|
9
|
-
end
|
10
|
-
|
11
|
-
def change
|
12
|
-
reversible do |dir|
|
13
|
-
dir.up do
|
14
|
-
# Ensure this incremental update migration is idempotent
|
15
|
-
# with monolithic install migration.
|
16
|
-
return if connection.index_name_exists?(:good_jobs, :index_good_jobs_on_active_job_id_and_created_at)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
add_index :good_jobs, [:active_job_id, :created_at], algorithm: :concurrently, name: :index_good_jobs_on_active_job_id_and_created_at
|
21
|
-
add_index :good_jobs, :concurrency_key, where: "(finished_at IS NULL)", algorithm: :concurrently, name: :index_good_jobs_on_concurrency_key_when_unfinished
|
22
|
-
add_index :good_jobs, [:cron_key, :created_at], algorithm: :concurrently, name: :index_good_jobs_on_cron_key_and_created_at
|
23
|
-
|
24
|
-
reversible do |dir|
|
25
|
-
dir.up do
|
26
|
-
start_time = Time.current
|
27
|
-
loop do
|
28
|
-
break if GoodJobJobs.where(active_job_id: nil, finished_at: nil).where("created_at < ?", start_time).limit(UPDATE_BATCH_SIZE).update_all("active_job_id = (serialized_params->>'job_id')::uuid").zero?
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
data/lib/generators/good_job/templates/update/migrations/04_add_retried_good_job_id_to_good_jobs.rb
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
class AddRetriedGoodJobIdToGoodJobs < ActiveRecord::Migration[5.2]
|
3
|
-
def change
|
4
|
-
reversible do |dir|
|
5
|
-
dir.up do
|
6
|
-
# Ensure this incremental update migration is idempotent
|
7
|
-
# with monolithic install migration.
|
8
|
-
return if connection.column_exists?(:good_jobs, :retried_good_job_id)
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
add_column :good_jobs, :retried_good_job_id, :uuid
|
13
|
-
end
|
14
|
-
end
|