good_job 4.1.0 → 4.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +71 -0
  3. data/README.md +10 -10
  4. data/app/charts/good_job/performance_index_chart.rb +1 -1
  5. data/app/charts/good_job/performance_show_chart.rb +1 -1
  6. data/app/controllers/good_job/application_controller.rb +1 -1
  7. data/app/controllers/good_job/batches_controller.rb +6 -0
  8. data/app/controllers/good_job/frontends_controller.rb +6 -2
  9. data/app/controllers/good_job/performance_controller.rb +1 -1
  10. data/app/frontend/good_job/icons.svg +79 -0
  11. data/app/frontend/good_job/style.css +5 -0
  12. data/app/helpers/good_job/icons_helper.rb +8 -5
  13. data/app/models/concerns/good_job/advisory_lockable.rb +17 -7
  14. data/app/models/concerns/good_job/error_events.rb +2 -2
  15. data/app/models/concerns/good_job/reportable.rb +8 -12
  16. data/app/models/good_job/batch.rb +31 -9
  17. data/app/models/good_job/batch_record.rb +19 -20
  18. data/app/models/good_job/discrete_execution.rb +6 -59
  19. data/app/models/good_job/execution.rb +59 -4
  20. data/app/models/good_job/execution_result.rb +6 -6
  21. data/app/models/good_job/job.rb +543 -12
  22. data/app/models/good_job/process.rb +14 -3
  23. data/app/views/good_job/batches/_jobs.erb +1 -1
  24. data/app/views/good_job/batches/_table.erb +7 -1
  25. data/app/views/good_job/batches/show.html.erb +8 -0
  26. data/app/views/good_job/jobs/index.html.erb +1 -1
  27. data/app/views/layouts/good_job/application.html.erb +7 -7
  28. data/config/brakeman.ignore +75 -0
  29. data/config/locales/de.yml +54 -49
  30. data/config/locales/en.yml +5 -0
  31. data/config/locales/es.yml +19 -14
  32. data/config/locales/fr.yml +5 -0
  33. data/config/locales/it.yml +5 -0
  34. data/config/locales/ja.yml +10 -5
  35. data/config/locales/ko.yml +9 -4
  36. data/config/locales/nl.yml +5 -0
  37. data/config/locales/pt-BR.yml +5 -0
  38. data/config/locales/ru.yml +5 -0
  39. data/config/locales/tr.yml +5 -0
  40. data/config/locales/uk.yml +6 -1
  41. data/config/routes.rb +8 -4
  42. data/lib/good_job/active_job_extensions/concurrency.rb +109 -98
  43. data/lib/good_job/adapter/inline_buffer.rb +73 -0
  44. data/lib/good_job/adapter.rb +59 -53
  45. data/lib/good_job/capsule_tracker.rb +2 -2
  46. data/lib/good_job/configuration.rb +13 -12
  47. data/lib/good_job/cron_manager.rb +1 -3
  48. data/lib/good_job/current_thread.rb +4 -4
  49. data/lib/good_job/notifier/process_heartbeat.rb +3 -2
  50. data/lib/good_job/version.rb +1 -1
  51. data/lib/good_job.rb +6 -5
  52. metadata +6 -20
  53. data/app/models/good_job/base_execution.rb +0 -605
  54. data/app/views/good_job/shared/icons/_arrow_clockwise.html.erb +0 -5
  55. data/app/views/good_job/shared/icons/_check.html.erb +0 -5
  56. data/app/views/good_job/shared/icons/_circle_half.html.erb +0 -4
  57. data/app/views/good_job/shared/icons/_clock.html.erb +0 -5
  58. data/app/views/good_job/shared/icons/_dash_circle.html.erb +0 -5
  59. data/app/views/good_job/shared/icons/_dots.html.erb +0 -3
  60. data/app/views/good_job/shared/icons/_eject.html.erb +0 -4
  61. data/app/views/good_job/shared/icons/_exclamation.html.erb +0 -5
  62. data/app/views/good_job/shared/icons/_globe.html.erb +0 -3
  63. data/app/views/good_job/shared/icons/_info.html.erb +0 -4
  64. data/app/views/good_job/shared/icons/_moon_stars_fill.html.erb +0 -5
  65. data/app/views/good_job/shared/icons/_pause.html.erb +0 -4
  66. data/app/views/good_job/shared/icons/_play.html.erb +0 -4
  67. data/app/views/good_job/shared/icons/_skip_forward.html.erb +0 -4
  68. data/app/views/good_job/shared/icons/_stop.html.erb +0 -4
  69. data/app/views/good_job/shared/icons/_sun_fill.html.erb +0 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: aead87131c66c247222ce6733d9fe579b6d61fa0cc166b23ae75c6011e2b52db
4
- data.tar.gz: 4158e3be14f1b93f46bb2eeefbeee246b4a2d98347519166b507811d343234ab
3
+ metadata.gz: 6b8f73f25f420a1b95841f757ef3eae435fc19e442f157bae03af0e751d619a2
4
+ data.tar.gz: e6737d5a487ed8d43c0c9dc078b72c075784cfb00889835e63b8ca2ba8788333
5
5
  SHA512:
6
- metadata.gz: f7c522339ad17886675ac8c97104087a1d132767fe9e90c5a7f62005fced53abc40f29488e431b18e1a3a1ce528202245448617123eabaef1bda478576a9bfde
7
- data.tar.gz: ce6fdd69c377f1e834b41640c5307e3bd030ac95d247b7037eab3fc5e806e6fb3030e57cc2de9d1f18a9e1f22e314e6b7e4a5aee709e2551b74b3d47f1e84388
6
+ metadata.gz: fd113e9ed755d014fdbd324bd7aaf62837e384176412d7eeeb4bf277fbd7ed9cb5eba82a39dc4f1e54f4753e635f8c8076194f45d1de461f92301864081cf08f
7
+ data.tar.gz: 9e028ead209f0467bfe8e2d323ebfe812503ef8310a792270604b525f4aeb5429b7857fbf644bfbc600e14593c0545cf0e628f309aabb8276ca34c6f3ae98367
data/CHANGELOG.md CHANGED
@@ -1,5 +1,76 @@
1
1
  # Changelog
2
2
 
3
+ ## [v4.2.0](https://github.com/bensheldon/good_job/tree/v4.2.0) (2024-08-16)
4
+
5
+ [Full Changelog](https://github.com/bensheldon/good_job/compare/v4.1.1...v4.2.0)
6
+
7
+ **Implemented enhancements:**
8
+
9
+ - Add retry functionality for batches [\#1456](https://github.com/bensheldon/good_job/pull/1456) ([bensheldon](https://github.com/bensheldon))
10
+
11
+ **Fixed bugs:**
12
+
13
+ - respect perform\_throttle even if perform\_limit is provided [\#1470](https://github.com/bensheldon/good_job/pull/1470) ([doits](https://github.com/doits))
14
+ - Do not use advisory lock on heartbeat in production [\#1451](https://github.com/bensheldon/good_job/pull/1451) ([bensheldon](https://github.com/bensheldon))
15
+
16
+ **Closed issues:**
17
+
18
+ - `perform_limit` and `perform_throttle` don't work both [\#1469](https://github.com/bensheldon/good_job/issues/1469)
19
+ - Edge rails changes breaking binding commits [\#1466](https://github.com/bensheldon/good_job/issues/1466)
20
+ - Dynamic creation of CronEntries [\#1457](https://github.com/bensheldon/good_job/issues/1457)
21
+ - Batch callback job not enqueued after success of retried job [\#1450](https://github.com/bensheldon/good_job/issues/1450)
22
+
23
+ **Merged pull requests:**
24
+
25
+ - Update cron documentation to remove confusion about multiple processes [\#1467](https://github.com/bensheldon/good_job/pull/1467) ([bensheldon](https://github.com/bensheldon))
26
+ - Update compatibility matrix, remove compatibility code [\#1465](https://github.com/bensheldon/good_job/pull/1465) ([Earlopain](https://github.com/Earlopain))
27
+ - Run tests with warnings enabled [\#1462](https://github.com/bensheldon/good_job/pull/1462) ([Earlopain](https://github.com/Earlopain))
28
+ - Add appraisal for Rails 7.2; bracket lowest PG version instead of enumerating all [\#1460](https://github.com/bensheldon/good_job/pull/1460) ([bensheldon](https://github.com/bensheldon))
29
+ - Fix a few method redefinition warnings [\#1459](https://github.com/bensheldon/good_job/pull/1459) ([Earlopain](https://github.com/Earlopain))
30
+ - Bump rexml from 3.3.2 to 3.3.3 [\#1455](https://github.com/bensheldon/good_job/pull/1455) ([dependabot[bot]](https://github.com/apps/dependabot))
31
+ - Remove `smaller_number_is_higher_priority` option from v4 [\#1453](https://github.com/bensheldon/good_job/pull/1453) ([bensheldon](https://github.com/bensheldon))
32
+
33
+ ## [v4.1.1](https://github.com/bensheldon/good_job/tree/v4.1.1) (2024-07-31)
34
+
35
+ [Full Changelog](https://github.com/bensheldon/good_job/compare/v1.99.2...v4.1.1)
36
+
37
+ **Implemented enhancements:**
38
+
39
+ - Convert Concurrency extension to use transaction-level \(xact\) advisory locks [\#1439](https://github.com/bensheldon/good_job/pull/1439) ([bensheldon](https://github.com/bensheldon))
40
+
41
+ **Fixed bugs:**
42
+
43
+ - Fix N+1 on dashboard batches index page [\#1442](https://github.com/bensheldon/good_job/pull/1442) ([bensheldon](https://github.com/bensheldon))
44
+ - Remove duplicate word on batches show page [\#1441](https://github.com/bensheldon/good_job/pull/1441) ([Earlopain](https://github.com/Earlopain))
45
+ - Ensure remaining inline jobs are unlocked when one job raises in Adapter\#enqueue\_all [\#1438](https://github.com/bensheldon/good_job/pull/1438) ([bensheldon](https://github.com/bensheldon))
46
+
47
+ **Closed issues:**
48
+
49
+ - Using Good Job to track all ActiveJob executions, even those with `perform_now` [\#1448](https://github.com/bensheldon/good_job/issues/1448)
50
+ - RuntimeError when running good\_job executable after updating v3 -\> v4 [\#1445](https://github.com/bensheldon/good_job/issues/1445)
51
+ - 2.99 -\> 3.0.2 migration not applying cleanly from a fresh DB [\#1435](https://github.com/bensheldon/good_job/issues/1435)
52
+ - \[Enhance\] Enhance performance via counter cache [\#1375](https://github.com/bensheldon/good_job/issues/1375)
53
+ - Change how svg images are inserted into partials [\#1364](https://github.com/bensheldon/good_job/issues/1364)
54
+
55
+ **Merged pull requests:**
56
+
57
+ - Improve some Spanish transcriptions [\#1452](https://github.com/bensheldon/good_job/pull/1452) ([sebastian-cloudnonic](https://github.com/sebastian-cloudnonic))
58
+ - All running jobs now have `performed_at` set so use that in status query; fix flaky test that took advisory lock in `before` block [\#1444](https://github.com/bensheldon/good_job/pull/1444) ([bensheldon](https://github.com/bensheldon))
59
+ - Handle empty asset format in Frontends controller [\#1443](https://github.com/bensheldon/good_job/pull/1443) ([bensheldon](https://github.com/bensheldon))
60
+ - Update development dependencies, Ruby 3.3.4 [\#1437](https://github.com/bensheldon/good_job/pull/1437) ([bensheldon](https://github.com/bensheldon))
61
+ - Refactor inline adapter to enable deferred execution after enqueue to allow batch-callbacks to use transaction-based advisory lock [\#1433](https://github.com/bensheldon/good_job/pull/1433) ([bensheldon](https://github.com/bensheldon))
62
+ - German translation pass [\#1432](https://github.com/bensheldon/good_job/pull/1432) ([Earlopain](https://github.com/Earlopain))
63
+ - Add Brakeman to linters [\#1431](https://github.com/bensheldon/good_job/pull/1431) ([bensheldon](https://github.com/bensheldon))
64
+ - Remove references to and ignore `good_jobs.retried_good_job_id` column [\#1430](https://github.com/bensheldon/good_job/pull/1430) ([bensheldon](https://github.com/bensheldon))
65
+ - Refactor Concurrency extension for Rails 6.1+ compatibility [\#1429](https://github.com/bensheldon/good_job/pull/1429) ([bensheldon](https://github.com/bensheldon))
66
+ - Use svg `use` for svg icons [\#1428](https://github.com/bensheldon/good_job/pull/1428) ([Earlopain](https://github.com/Earlopain))
67
+ - Replace references to "Discrete" executions with simply Executions; deprecate `GoodJob::DiscreteExecution` [\#1427](https://github.com/bensheldon/good_job/pull/1427) ([bensheldon](https://github.com/bensheldon))
68
+ - Refactor Adapter to reference jobs, not executions [\#1426](https://github.com/bensheldon/good_job/pull/1426) ([bensheldon](https://github.com/bensheldon))
69
+
70
+ ## [v1.99.2](https://github.com/bensheldon/good_job/tree/v1.99.2) (2024-07-18)
71
+
72
+ [Full Changelog](https://github.com/bensheldon/good_job/compare/v4.1.0...v1.99.2)
73
+
3
74
  ## [v4.1.0](https://github.com/bensheldon/good_job/tree/v4.1.0) (2024-07-16)
4
75
 
5
76
  [Full Changelog](https://github.com/bensheldon/good_job/compare/v3.99.1...v4.1.0)
data/README.md CHANGED
@@ -164,8 +164,8 @@ For more of the story of GoodJob, read the [introductory blog post](https://isla
164
164
 
165
165
  ## Compatibility
166
166
 
167
- - **Ruby on Rails:** 6.0+
168
- - **Ruby:** Ruby 2.6+. JRuby 9.3+
167
+ - **Ruby on Rails:** 6.1+
168
+ - **Ruby:** Ruby 3.0+. JRuby 9.4+
169
169
  - **Postgres:** 10.0+
170
170
 
171
171
  ## Configuration
@@ -307,7 +307,7 @@ Available configuration options are:
307
307
  - `inline_execution_respects_schedule` (boolean) Opt-in to future behavior of inline execution respecting scheduled jobs. Defaults to `false`.
308
308
  - `logger` ([Rails Logger](https://api.rubyonrails.org/classes/ActiveSupport/Logger.html)) lets you set a custom logger for GoodJob. It should be an instance of a Rails `Logger` (Default: `Rails.logger`).
309
309
  - `preserve_job_records` (boolean) keeps job records in your database even after jobs are completed. (Default: `true`)
310
- - `smaller_number_is_higher_priority` (boolean) allows you to specifiy that jobs should be run in ascending order of priority (smallest priority numbers first). This will be enabled by default in the next major version of GoodJob (v4.0), but jobs with the highest priority number are run first by default in all earlier versions of GoodJob.
310
+ - `advisory_lock_heartbeat` (boolean) whether to use an advisory lock for the purpose of determining whether an execeution process is active. (Default `true` in Development; `false` in other environments)
311
311
  - `retry_on_unhandled_error` (boolean) causes jobs to be re-queued and retried if they raise an instance of `StandardError`. Be advised this may lead to jobs being repeated infinitely ([see below for more on retries](#retries)). Instances of `Exception`, like SIGINT, will *always* be retried, regardless of this attribute’s value. (Default: `false`)
312
312
  - `on_thread_error` (proc, lambda, or callable) will be called when there is an Exception. It can be useful for logging errors to bug tracking services, like Sentry or Airbrake. Example:
313
313
 
@@ -499,7 +499,9 @@ As a second example, you may wish to show a link to a log aggregator next to eac
499
499
 
500
500
  ### Job priority
501
501
 
502
- Higher priority numbers run first in all versions of GoodJob v3.x and below. GoodJob v4.x will change job `priority` to give smaller numbers higher priority (default: `0`), in accordance with Active Job's definition of priority (see #524). To opt-in to this behavior now, set `config.good_job.smaller_number_is_higher_priority = true` in your GoodJob initializer or `application.rb`.
502
+ Smaller `priority` values have higher priority and run first (default: `0`), in accordance with [Active Job's definition of priority](https://github.com/rails/rails/blob/e17faead4f2aff28da079d50f02ea5b015322d5b/activejob/lib/active_job/core.rb#L22).
503
+
504
+ Prior to GoodJob v4, this was reversed: higher priority numbers ran first in all versions of GoodJob v3.x and below. When migrating from v3 to v4, new behavior can be opted into by setting `config.good_job.smaller_number_is_higher_priority = true` in your GoodJob initializer or `application.rb`.
503
505
 
504
506
  ### Labelled jobs
505
507
 
@@ -611,9 +613,7 @@ GoodJob's concurrency control strategy for `perform_limit` is "optimistic retry
611
613
 
612
614
  GoodJob can enqueue Active Job jobs on a recurring basis that can be used as a replacement for cron.
613
615
 
614
- Cron-style jobs can be performed by any GoodJob process (e.g., CLI or `:async` execution mode) that has `config.good_job.enable_cron` set to `true`. That is, one or more job executor processes can be configured to perform recurring jobs.
615
-
616
- GoodJob's cron uses unique indexes to ensure that only a single job is enqueued at the given time interval. In order for this to work, GoodJob must preserve cron-created job records; these records will be automatically deleted like any other preserved record.
616
+ Cron-style jobs can be enequeued by any GoodJob process (e.g., CLI or `:async` execution mode) that has `config.good_job.enable_cron` set to `true`. Enabling cron on multiple processes will not enqueue duplicate jobs; GoodJob's cron uses unique indexes to ensure that only a single job is enqueued for a given time interval. In order for this to work, GoodJob must preserve cron-created job records; these records will be automatically deleted like any other preserved record.
617
617
 
618
618
  Cron-format is parsed by the [`fugit`](https://github.com/floraison/fugit) gem, which has support for seconds-level resolution (e.g. `* * * * * *`) and natural language parsing (e.g. `every second`).
619
619
 
@@ -622,8 +622,8 @@ If you use the [Dashboard](#dashboard) the scheduled tasks can be viewed in the
622
622
  ```ruby
623
623
  # config/environments/application.rb or a specific environment e.g. production.rb
624
624
 
625
- # Enable cron in this process, e.g., only run on the first Heroku worker process
626
- config.good_job.enable_cron = ENV['DYNO'] == 'worker.1' # or `true` or via $GOOD_JOB_ENABLE_CRON
625
+ # Enable cron enqueuing in this process
626
+ config.good_job.enable_cron = true
627
627
 
628
628
  # Configure cron with a hash that has a unique key for each recurring job
629
629
  config.good_job.cron = {
@@ -890,7 +890,7 @@ To upgrade:
890
890
 
891
891
  Notable changes:
892
892
 
893
- - Only supports Rails 6.1+, CRuby 3.0+ and JRuby 9.4+, Postgres 12+. Rails 6.0 is no longer supported. CRuby 2.6 and 2.7 are no longer supported. JRuby 9.3 is no longer supported.
893
+ - Only supports Rails 6.1+, CRuby 3.0+ and JRuby 9.4+. Rails 6.0 is no longer supported. CRuby 2.6 and 2.7 are no longer supported. JRuby 9.3 is no longer supported.
894
894
  - Changes job `priority` to give smaller numbers higher priority (default: `0`), in accordance with Active Job's definition of priority.
895
895
  - Enqueues and executes jobs via the `GoodJob::Job` model instead of `GoodJob::Execution`
896
896
  - Setting `config.good_job.cleanup_interval_jobs`, `GOOD_JOB_CLEANUP_INTERVAL_JOBS`, `config.good_job.cleanup_interval_seconds`, or `GOOD_JOB_CLEANUP_INTERVAL_SECONDS` to `nil` or `""` no longer disables count- or time-based cleanups. Set to `false` to disable, or `-1` to run a cleanup after every job execution.
@@ -3,7 +3,7 @@
3
3
  module GoodJob
4
4
  class PerformanceIndexChart < BaseChart
5
5
  def data
6
- table_name = GoodJob::DiscreteExecution.table_name
6
+ table_name = GoodJob::Execution.table_name
7
7
 
8
8
  sum_query = Arel.sql(GoodJob::Job.pg_or_jdbc_query(<<~SQL.squish))
9
9
  SELECT *
@@ -18,7 +18,7 @@ module GoodJob
18
18
  end
19
19
 
20
20
  def data
21
- table_name = GoodJob::DiscreteExecution.table_name
21
+ table_name = GoodJob::Execution.table_name
22
22
 
23
23
  interval_entries = BUCKET_INTERVALS.map { "interval '#{_1}'" }.join(",")
24
24
  sum_query = Arel.sql(GoodJob::Job.pg_or_jdbc_query(<<~SQL.squish))
@@ -7,7 +7,7 @@ module GoodJob
7
7
  around_action :use_good_job_locale
8
8
 
9
9
  content_security_policy do |policy|
10
- policy.default_src(:none) if policy.default_src(*policy.default_src).blank?
10
+ policy.default_src(:self) if policy.default_src(*policy.default_src).blank?
11
11
  policy.connect_src(:self) if policy.connect_src(*policy.connect_src).blank?
12
12
  policy.base_uri(:none) if policy.base_uri(*policy.base_uri).blank?
13
13
  policy.font_src(:self) if policy.font_src(*policy.font_src).blank?
@@ -9,5 +9,11 @@ module GoodJob
9
9
  def show
10
10
  @batch = GoodJob::BatchRecord.find(params[:id])
11
11
  end
12
+
13
+ def retry
14
+ @batch = GoodJob::Batch.find(params[:id])
15
+ @batch.retry
16
+ redirect_back(fallback_location: batches_path, notice: t(".notice"))
17
+ end
12
18
  end
13
19
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  module GoodJob
4
4
  class FrontendsController < ActionController::Base # rubocop:disable Rails/ApplicationController
5
+ protect_from_forgery with: :exception
5
6
  skip_after_action :verify_same_origin_request, raise: false
6
7
 
7
8
  STATIC_ASSETS = {
@@ -15,6 +16,9 @@ module GoodJob
15
16
  es_module_shims: GoodJob::Engine.root.join("app", "frontend", "good_job", "vendor", "es_module_shims.js"),
16
17
  rails_ujs: GoodJob::Engine.root.join("app", "frontend", "good_job", "vendor", "rails_ujs.js"),
17
18
  },
19
+ svg: {
20
+ icons: GoodJob::Engine.root.join("app", "frontend", "good_job", "icons.svg"),
21
+ },
18
22
  }.freeze
19
23
 
20
24
  MODULE_OVERRIDES = {
@@ -34,13 +38,13 @@ module GoodJob
34
38
  end
35
39
 
36
40
  def static
37
- render file: STATIC_ASSETS.dig(params[:format].to_sym, params[:name].to_sym) || raise(ActionController::RoutingError, 'Not Found')
41
+ render file: STATIC_ASSETS.dig(params[:format]&.to_sym, params[:id]&.to_sym) || raise(ActionController::RoutingError, 'Not Found')
38
42
  end
39
43
 
40
44
  def module
41
45
  raise(ActionController::RoutingError, 'Not Found') if params[:format] != "js"
42
46
 
43
- render file: self.class.js_modules[params[:name].to_sym] || raise(ActionController::RoutingError, 'Not Found')
47
+ render file: self.class.js_modules[params[:id]&.to_sym] || raise(ActionController::RoutingError, 'Not Found')
44
48
  end
45
49
  end
46
50
  end
@@ -3,7 +3,7 @@
3
3
  module GoodJob
4
4
  class PerformanceController < ApplicationController
5
5
  def index
6
- @performances = GoodJob::DiscreteExecution
6
+ @performances = GoodJob::Execution
7
7
  .where.not(job_class: nil)
8
8
  .group(:job_class)
9
9
  .select("
@@ -0,0 +1,79 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <svg xmlns="http://www.w3.org/2000/svg">
3
+ <!-- https://icons.getbootstrap.com/icons/arrow-clockwise/ -->
4
+ <symbol id="arrow_clockwise" viewBox="0 0 16 16">
5
+ <path fill-rule="evenodd" d="M8 3a5 5 0 1 0 4.546 2.914.5.5 0 0 1 .908-.417A6 6 0 1 1 8 2v1z" />
6
+ <path d="M8 4.466V.534a.25.25 0 0 1 .41-.192l2.36 1.966c.12.1.12.284 0 .384L8.41 4.658A.25.25 0 0 1 8 4.466z" />
7
+ </symbol>
8
+ <!-- https://icons.getbootstrap.com/icons/check-circle/ -->
9
+ <symbol id="check" viewBox="0 0 16 16">
10
+ <path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z" />
11
+ <path d="M10.97 4.97a.235.235 0 0 0-.02.022L7.477 9.417 5.384 7.323a.75.75 0 0 0-1.06 1.06L6.97 11.03a.75.75 0 0 0 1.079-.02l3.992-4.99a.75.75 0 0 0-1.071-1.05z" />
12
+ </symbol>
13
+ <!-- https://icons.getbootstrap.com/icons/circle-half/ -->
14
+ <symbol id="circle_half" viewBox="0 0 16 16">
15
+ <path d="M8 15A7 7 0 1 0 8 1v14zm0 1A8 8 0 1 1 8 0a8 8 0 0 1 0 16z" />
16
+ </symbol>
17
+ <!-- https://icons.getbootstrap.com/icons/clock/ -->
18
+ <symbol id="clock" viewBox="0 0 16 16">
19
+ <path d="M8 3.5a.5.5 0 0 0-1 0V9a.5.5 0 0 0 .252.434l3.5 2a.5.5 0 0 0 .496-.868L8 8.71V3.5z" />
20
+ <path d="M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16zm7-8A7 7 0 1 1 1 8a7 7 0 0 1 14 0z" />
21
+ </symbol>
22
+ <!-- https://icons.getbootstrap.com/icons/dash-circle/ -->
23
+ <symbol id="dash_circle" viewBox="0 0 16 16">
24
+ <path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z" />
25
+ <path d="M4 8a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7A.5.5 0 0 1 4 8z" />
26
+ </symbol>
27
+ <!-- https://icons.getbootstrap.com/icons/three-dots/ -->
28
+ <symbol id="dots" viewBox="0 0 16 16">
29
+ <path d="M3 9.5a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zm5 0a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zm5 0a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3z" />
30
+ </symbol>
31
+ <!-- https://icons.getbootstrap.com/icons/eject/ -->
32
+ <symbol id="eject" viewBox="0 0 16 16">
33
+ <path d="M7.27 1.047a1 1 0 0 1 1.46 0l6.345 6.77c.6.638.146 1.683-.73 1.683H1.656C.78 9.5.326 8.455.926 7.816L7.27 1.047zM14.346 8.5 8 1.731 1.654 8.5h12.692zM.5 11.5a1 1 0 0 1 1-1h13a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1h-13a1 1 0 0 1-1-1v-1zm14 0h-13v1h13v-1z" />
34
+ </symbol>
35
+ <!-- https://icons.getbootstrap.com/icons/exclamation-circle/ -->
36
+ <symbol id="exclamation" viewBox="0 0 16 16">
37
+ <path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z" />
38
+ <path d="M7.002 11a1 1 0 1 1 2 0 1 1 0 0 1-2 0zM7.1 4.995a.905.905 0 1 1 1.8 0l-.35 3.507a.552.552 0 0 1-1.1 0L7.1 4.995z" />
39
+ </symbol>
40
+ <!-- https://icons.getbootstrap.com/icons/globe/ -->
41
+ <symbol id="globe" viewBox="0 0 16 16">
42
+ <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8m7.5-6.923c-.67.204-1.335.82-1.887 1.855A8 8 0 0 0 5.145 4H7.5zM4.09 4a9.3 9.3 0 0 1 .64-1.539 7 7 0 0 1 .597-.933A7.03 7.03 0 0 0 2.255 4zm-.582 3.5c.03-.877.138-1.718.312-2.5H1.674a7 7 0 0 0-.656 2.5zM4.847 5a12.5 12.5 0 0 0-.338 2.5H7.5V5zM8.5 5v2.5h2.99a12.5 12.5 0 0 0-.337-2.5zM4.51 8.5a12.5 12.5 0 0 0 .337 2.5H7.5V8.5zm3.99 0V11h2.653c.187-.765.306-1.608.338-2.5zM5.145 12q.208.58.468 1.068c.552 1.035 1.218 1.65 1.887 1.855V12zm.182 2.472a7 7 0 0 1-.597-.933A9.3 9.3 0 0 1 4.09 12H2.255a7 7 0 0 0 3.072 2.472M3.82 11a13.7 13.7 0 0 1-.312-2.5h-2.49c.062.89.291 1.733.656 2.5zm6.853 3.472A7 7 0 0 0 13.745 12H11.91a9.3 9.3 0 0 1-.64 1.539 7 7 0 0 1-.597.933M8.5 12v2.923c.67-.204 1.335-.82 1.887-1.855q.26-.487.468-1.068zm3.68-1h2.146c.365-.767.594-1.61.656-2.5h-2.49a13.7 13.7 0 0 1-.312 2.5m2.802-3.5a7 7 0 0 0-.656-2.5H12.18c.174.782.282 1.623.312 2.5zM11.27 2.461c.247.464.462.98.64 1.539h1.835a7 7 0 0 0-3.072-2.472c.218.284.418.598.597.933M10.855 4a8 8 0 0 0-.468-1.068C9.835 1.897 9.17 1.282 8.5 1.077V4z" />
43
+ </symbol>
44
+ <!-- https://icons.getbootstrap.com/icons/info-circle/ -->
45
+ <symbol id="info" viewBox="0 0 16 16">
46
+ <path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z" />
47
+ <path d="m8.93 6.588-2.29.287-.082.38.45.083c.294.07.352.176.288.469l-.738 3.468c-.194.897.105 1.319.808 1.319.545 0 1.178-.252 1.465-.598l.088-.416c-.2.176-.492.246-.686.246-.275 0-.375-.193-.304-.533L8.93 6.588zM9 4.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0z" />
48
+ </symbol>
49
+ <!-- https://icons.getbootstrap.com/icons/moon-stars-fill/ -->
50
+ <symbol id="moon_stars_fill" viewBox="0 0 16 16">
51
+ <path d="M6 .278a.768.768 0 0 1 .08.858 7.208 7.208 0 0 0-.878 3.46c0 4.021 3.278 7.277 7.318 7.277.527 0 1.04-.055 1.533-.16a.787.787 0 0 1 .81.316.733.733 0 0 1-.031.893A8.349 8.349 0 0 1 8.344 16C3.734 16 0 12.286 0 7.71 0 4.266 2.114 1.312 5.124.06A.752.752 0 0 1 6 .278z" />
52
+ <path d="M10.794 3.148a.217.217 0 0 1 .412 0l.387 1.162c.173.518.579.924 1.097 1.097l1.162.387a.217.217 0 0 1 0 .412l-1.162.387a1.734 1.734 0 0 0-1.097 1.097l-.387 1.162a.217.217 0 0 1-.412 0l-.387-1.162A1.734 1.734 0 0 0 9.31 6.593l-1.162-.387a.217.217 0 0 1 0-.412l1.162-.387a1.734 1.734 0 0 0 1.097-1.097l.387-1.162zM13.863.099a.145.145 0 0 1 .274 0l.258.774c.115.346.386.617.732.732l.774.258a.145.145 0 0 1 0 .274l-.774.258a1.156 1.156 0 0 0-.732.732l-.258.774a.145.145 0 0 1-.274 0l-.258-.774a1.156 1.156 0 0 0-.732-.732l-.774-.258a.145.145 0 0 1 0-.274l.774-.258c.346-.115.617-.386.732-.732L13.863.1z" />
53
+ </symbol>
54
+ <!-- https://icons.getbootstrap.com/icons/pause-btn/ -->
55
+ <symbol id="pause" viewBox="0 0 16 16">
56
+ <path d="M6 3.5a.5.5 0 0 1 .5.5v8a.5.5 0 0 1-1 0V4a.5.5 0 0 1 .5-.5zm4 0a.5.5 0 0 1 .5.5v8a.5.5 0 0 1-1 0V4a.5.5 0 0 1 .5-.5z" />
57
+ </symbol>
58
+ <!-- https://icons.getbootstrap.com/icons/play/ -->
59
+ <symbol id="play" viewBox="0 0 16 16">
60
+ <path d="M10.804 8 5 4.633v6.734L10.804 8zm.792-.696a.802.802 0 0 1 0 1.392l-6.363 3.692C4.713 12.69 4 12.345 4 11.692V4.308c0-.653.713-.998 1.233-.696l6.363 3.692z" />
61
+ </symbol>
62
+ <!-- https://icons.getbootstrap.com/icons/skip-forward/ -->
63
+ <symbol id="skip_forward" viewBox="0 0 16 16">
64
+ <path d="M15.5 3.5a.5.5 0 0 1 .5.5v8a.5.5 0 0 1-1 0V8.752l-6.267 3.636c-.52.302-1.233-.043-1.233-.696v-2.94l-6.267 3.636C.713 12.69 0 12.345 0 11.692V4.308c0-.653.713-.998 1.233-.696L7.5 7.248v-2.94c0-.653.713-.998 1.233-.696L15 7.248V4a.5.5 0 0 1 .5-.5zM1 4.633v6.734L6.804 8 1 4.633zm7.5 0v6.734L14.304 8 8.5 4.633z" />
65
+ </symbol>
66
+ <!-- https://icons.getbootstrap.com/icons/stop/ -->
67
+ <symbol id="stop" viewBox="0 0 16 16">
68
+ <path d="M3.5 5A1.5 1.5 0 0 1 5 3.5h6A1.5 1.5 0 0 1 12.5 5v6a1.5 1.5 0 0 1-1.5 1.5H5A1.5 1.5 0 0 1 3.5 11V5zM5 4.5a.5.5 0 0 0-.5.5v6a.5.5 0 0 0 .5.5h6a.5.5 0 0 0 .5-.5V5a.5.5 0 0 0-.5-.5H5z" />
69
+ </symbol>
70
+ <!-- https://icons.getbootstrap.com/icons/sun-fill/ -->
71
+ <symbol id="sun_fill" viewBox="0 0 16 16">
72
+ <path d="M8 12a4 4 0 1 0 0-8 4 4 0 0 0 0 8zM8 0a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-1 0v-2A.5.5 0 0 1 8 0zm0 13a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-1 0v-2A.5.5 0 0 1 8 13zm8-5a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1 0-1h2a.5.5 0 0 1 .5.5zM3 8a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1 0-1h2A.5.5 0 0 1 3 8zm10.657-5.657a.5.5 0 0 1 0 .707l-1.414 1.415a.5.5 0 1 1-.707-.708l1.414-1.414a.5.5 0 0 1 .707 0zm-9.193 9.193a.5.5 0 0 1 0 .707L3.05 13.657a.5.5 0 0 1-.707-.707l1.414-1.414a.5.5 0 0 1 .707 0zm9.193 2.121a.5.5 0 0 1-.707 0l-1.414-1.414a.5.5 0 0 1 .707-.707l1.414 1.414a.5.5 0 0 1 0 .707zM4.464 4.465a.5.5 0 0 1-.707 0L2.343 3.05a.5.5 0 1 1 .707-.707l1.414 1.414a.5.5 0 0 1 0 .708z" />
73
+ </symbol>
74
+ <!-- https://icons.getbootstrap.com/icons/trash/ -->
75
+ <symbol id="trash" viewBox="0 0 16 16">
76
+ <path d="M5.5 5.5A.5.5 0 0 1 6 6v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm2.5 0a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm3 .5a.5.5 0 0 0-1 0v6a.5.5 0 0 0 1 0V6z" />
77
+ <path fill-rule="evenodd" d="M14.5 3a1 1 0 0 1-1 1H13v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V4h-.5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1H6a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1h3.5a1 1 0 0 1 1 1v1zM4.118 4 4 4.059V13a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4.059L11.882 4H4.118zM2.5 3V2h11v1h-11z" />
78
+ </symbol>
79
+ </svg>
@@ -46,3 +46,8 @@
46
46
  .w-fit-content {
47
47
  width: fit-content
48
48
  }
49
+
50
+ .svg-icon {
51
+ height: 1rem;
52
+ width: 1rem;
53
+ }
@@ -31,11 +31,14 @@ module GoodJob
31
31
  content_tag :span, icon, **options
32
32
  end
33
33
 
34
- def render_icon(name, **options)
35
- # workaround to render svg icons without all of the log messages
36
- partial = lookup_context.find_template("good_job/shared/icons/#{name}", [], true)
37
- options[:class] = Array(options[:class]).join(" ")
38
- partial.render(self, { class: options[:class] })
34
+ def render_icon(name, class: nil, **options)
35
+ tag.svg(viewBox: "0 0 16 16", class: "svg-icon #{binding.local_variable_get(:class)}", **options) do
36
+ tag.use(fill: "currentColor", href: "#{icons_path}##{name}")
37
+ end
38
+ end
39
+
40
+ def icons_path
41
+ @_icons_path ||= frontend_static_path(:icons, format: :svg, locale: nil)
39
42
  end
40
43
  end
41
44
  end
@@ -49,8 +49,8 @@ module GoodJob
49
49
 
50
50
  lock_condition = "#{function}(('x' || substr(md5(#{connection.quote(table_name)} || '-' || #{connection.quote_table_name(cte_table.name)}.#{connection.quote_column_name(column)}::text), 1, 16))::bit(64)::bigint)"
51
51
  query = cte_table.project(cte_table[:id])
52
- .with(composed_cte)
53
- .where(defined?(Arel::Nodes::BoundSqlLiteral) ? Arel::Nodes::BoundSqlLiteral.new(lock_condition, [], {}) : Arel::Nodes::SqlLiteral.new(lock_condition))
52
+ .with(composed_cte)
53
+ .where(defined?(Arel::Nodes::BoundSqlLiteral) ? Arel::Nodes::BoundSqlLiteral.new(lock_condition, [], {}) : Arel::Nodes::SqlLiteral.new(lock_condition))
54
54
 
55
55
  limit = original_query.arel.ast.limit
56
56
  query.limit = limit.value if limit.present?
@@ -174,8 +174,11 @@ module GoodJob
174
174
  if unlock_session
175
175
  advisory_unlock_session
176
176
  else
177
- records.each do |record|
178
- record.advisory_unlock(key: record.lockable_column_key(column: column), function: advisory_unlockable_function(function))
177
+ unlock_function = advisory_unlockable_function(function)
178
+ if unlock_function
179
+ records.each do |record|
180
+ record.advisory_unlock(key: record.lockable_column_key(column: column), function: unlock_function)
181
+ end
179
182
  end
180
183
  end
181
184
  end
@@ -209,7 +212,8 @@ module GoodJob
209
212
  begin
210
213
  yield
211
214
  ensure
212
- advisory_unlock_key(key, function: advisory_unlockable_function(function))
215
+ unlock_function = advisory_unlockable_function(function)
216
+ advisory_unlock_key(key, function: unlock_function) if unlock_function
213
217
  end
214
218
  end
215
219
 
@@ -220,6 +224,9 @@ module GoodJob
220
224
  # @param function [String, Symbol] Postgres Advisory Lock function name to use
221
225
  # @return [Boolean] whether the lock was released.
222
226
  def advisory_unlock_key(key, function: advisory_unlockable_function)
227
+ raise ArgumentError, "Cannot unlock transactional locks" if function.include? "_xact_"
228
+ raise ArgumentError, "No unlock function provide" if function.blank?
229
+
223
230
  query = <<~SQL.squish
224
231
  SELECT #{function}(('x'||substr(md5($1::text), 1, 16))::bit(64)::bigint) AS unlocked
225
232
  SQL
@@ -284,6 +291,8 @@ module GoodJob
284
291
  # @param function [String, Symbol] name of advisory lock or unlock function
285
292
  # @return [Boolean]
286
293
  def advisory_unlockable_function(function = advisory_lockable_function)
294
+ return nil if function.include? "_xact_" # Cannot unlock transactional locks
295
+
287
296
  function.to_s.sub("_lock", "_unlock").sub("_try_", "_")
288
297
  end
289
298
 
@@ -358,7 +367,8 @@ module GoodJob
358
367
  begin
359
368
  yield
360
369
  ensure
361
- advisory_unlock(key: key, function: self.class.advisory_unlockable_function(function))
370
+ unlock_function = self.class.advisory_unlockable_function(function)
371
+ advisory_unlock(key: key, function: unlock_function) if unlock_function
362
372
  end
363
373
  end
364
374
 
@@ -403,7 +413,7 @@ module GoodJob
403
413
  # @param key [String, Symbol] Key to lock against
404
414
  # @param function [String, Symbol] Postgres Advisory Lock function name to use
405
415
  # @return [void]
406
- def advisory_unlock!(key: lockable_key, function: self.class.advisory_unlockable_function(advisory_lockable_function))
416
+ def advisory_unlock!(key: lockable_key, function: self.class.advisory_unlockable_function)
407
417
  advisory_unlock(key: key, function: function) while advisory_locked?
408
418
  end
409
419
 
@@ -15,9 +15,9 @@ module GoodJob
15
15
  discarded: 5,
16
16
  }
17
17
  if Gem::Version.new(Rails.version) >= Gem::Version.new('7.1.0.a')
18
- enum :error_event, error_event_enum, validate: { allow_nil: true }
18
+ enum :error_event, error_event_enum, validate: { allow_nil: true }, scopes: false
19
19
  else
20
- enum error_event: error_event_enum
20
+ enum error_event: error_event_enum, _scopes: false
21
21
  end
22
22
  end
23
23
  end
@@ -16,27 +16,23 @@ module GoodJob
16
16
  # @return [Symbol]
17
17
  def status
18
18
  if finished_at.present?
19
- if error.present? && retried_good_job_id.present?
20
- :retried
21
- elsif error.present? && retried_good_job_id.nil?
19
+ if error.present?
22
20
  :discarded
23
21
  else
24
22
  :succeeded
25
23
  end
26
- elsif (scheduled_at || created_at) > DateTime.current
27
- if serialized_params.fetch('executions', 0) > 1
28
- :retried
29
- else
30
- :scheduled
31
- end
32
- elsif running?
24
+ elsif performed_at.present?
33
25
  :running
34
- else
26
+ elsif (scheduled_at || created_at) <= DateTime.current
35
27
  :queued
28
+ elsif error.present?
29
+ :retried
30
+ else
31
+ :scheduled
36
32
  end
37
33
  end
38
34
 
39
- # The last relevant timestamp for this execution
35
+ # The last relevant timestamp for this job
40
36
  def last_status_at
41
37
  finished_at || performed_at || scheduled_at || created_at
42
38
  end
@@ -92,22 +92,29 @@ module GoodJob
92
92
  if record.new_record?
93
93
  record.save!
94
94
  else
95
- record.with_advisory_lock(function: "pg_advisory_lock") do
96
- record.enqueued_at_will_change!
97
- record.finished_at_will_change!
98
- record.update!(enqueued_at: nil, finished_at: nil)
95
+ record.transaction do
96
+ record.with_advisory_lock(function: "pg_advisory_xact_lock") do
97
+ record.enqueued_at_will_change!
98
+ record.finished_at_will_change!
99
+ record.update!(enqueued_at: nil, finished_at: nil)
100
+ end
99
101
  end
100
102
  end
101
103
 
102
104
  active_jobs = add(active_jobs, &block)
103
105
 
104
106
  Rails.application.executor.wrap do
105
- record.with_advisory_lock(function: "pg_advisory_lock") do
106
- record.update!(enqueued_at: Time.current)
107
-
108
- # During inline execution, this could enqueue and execute further jobs
109
- record._continue_discard_or_finish(lock: false)
107
+ buffer = GoodJob::Adapter::InlineBuffer.capture do
108
+ record.transaction do
109
+ record.with_advisory_lock(function: "pg_advisory_xact_lock") do
110
+ record.update!(enqueued_at: Time.current)
111
+
112
+ # During inline execution, this could enqueue and execute further jobs
113
+ record._continue_discard_or_finish(lock: false)
114
+ end
115
+ end
110
116
  end
117
+ buffer.call
111
118
  end
112
119
 
113
120
  active_jobs
@@ -130,6 +137,21 @@ module GoodJob
130
137
  buffer.active_jobs
131
138
  end
132
139
 
140
+ def retry
141
+ Rails.application.executor.wrap do
142
+ buffer = GoodJob::Adapter::InlineBuffer.capture do
143
+ record.transaction do
144
+ record.with_advisory_lock(function: "pg_advisory_xact_lock") do
145
+ record.update!(discarded_at: nil, finished_at: nil)
146
+ record.jobs.discarded.each(&:retry_job)
147
+ record._continue_discard_or_finish(lock: false)
148
+ end
149
+ end
150
+ end
151
+ buffer.call
152
+ end
153
+ end
154
+
133
155
  def active_jobs
134
156
  record.jobs.map(&:active_job)
135
157
  end
@@ -53,22 +53,25 @@ module GoodJob
53
53
  end
54
54
 
55
55
  def _continue_discard_or_finish(execution = nil, lock: true)
56
- execution_discarded = execution && execution.error.present? && execution.finished_at && execution.retried_good_job_id.nil?
57
- take_advisory_lock(lock) do
58
- Batch.within_thread(batch_id: nil, batch_callback_id: id) do
59
- reload
60
- if execution_discarded && !discarded_at
61
- update(discarded_at: Time.current)
62
- on_discard.constantize.set(priority: callback_priority, queue: callback_queue_name).perform_later(to_batch, { event: :discard }) if on_discard.present?
63
- end
64
-
65
- if enqueued_at && !finished_at && jobs.where(finished_at: nil).count.zero?
66
- update(finished_at: Time.current)
67
- on_success.constantize.set(priority: callback_priority, queue: callback_queue_name).perform_later(to_batch, { event: :success }) if !discarded_at && on_success.present?
68
- on_finish.constantize.set(priority: callback_priority, queue: callback_queue_name).perform_later(to_batch, { event: :finish }) if on_finish.present?
56
+ execution_discarded = execution && execution.finished_at.present? && execution.error.present?
57
+ buffer = GoodJob::Adapter::InlineBuffer.capture do
58
+ advisory_lock_maybe(lock) do
59
+ Batch.within_thread(batch_id: nil, batch_callback_id: id) do
60
+ reload
61
+ if execution_discarded && !discarded_at
62
+ update(discarded_at: Time.current)
63
+ on_discard.constantize.set(priority: callback_priority, queue: callback_queue_name).perform_later(to_batch, { event: :discard }) if on_discard.present?
64
+ end
65
+
66
+ if enqueued_at && !finished_at && jobs.where(finished_at: nil).count.zero?
67
+ update(finished_at: Time.current)
68
+ on_success.constantize.set(priority: callback_priority, queue: callback_queue_name).perform_later(to_batch, { event: :success }) if !discarded_at && on_success.present?
69
+ on_finish.constantize.set(priority: callback_priority, queue: callback_queue_name).perform_later(to_batch, { event: :finish }) if on_finish.present?
70
+ end
69
71
  end
70
72
  end
71
73
  end
74
+ buffer.call
72
75
  end
73
76
 
74
77
  class PropertySerializer
@@ -81,11 +84,7 @@ module GoodJob
81
84
  end
82
85
  end
83
86
 
84
- if Rails.gem_version < Gem::Version.new('6.1.0.alpha')
85
- # serialize does not yet take a default value, must set via Attributes API
86
- attribute :serialized_properties, :json, default: -> { {} }
87
- serialize :serialized_properties, PropertySerializer
88
- elsif Rails.gem_version < Gem::Version.new('7.1.0.alpha')
87
+ if Rails.gem_version < Gem::Version.new('7.1.0.alpha')
89
88
  serialize :serialized_properties, PropertySerializer, default: -> { {} }
90
89
  else
91
90
  serialize :serialized_properties, coder: PropertySerializer, default: -> { {} }
@@ -100,9 +99,9 @@ module GoodJob
100
99
 
101
100
  private
102
101
 
103
- def take_advisory_lock(value, &block)
102
+ def advisory_lock_maybe(value, &block)
104
103
  if value
105
- with_advisory_lock(function: "pg_advisory_lock", &block)
104
+ transaction { with_advisory_lock(function: "pg_advisory_xact_lock", &block) }
106
105
  else
107
106
  yield
108
107
  end