inst-jobs 2.0.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. checksums.yaml +4 -4
  2. data/db/migrate/20101216224513_create_delayed_jobs.rb +9 -7
  3. data/db/migrate/20110531144916_cleanup_delayed_jobs_indexes.rb +8 -13
  4. data/db/migrate/20110610213249_optimize_delayed_jobs.rb +8 -8
  5. data/db/migrate/20110831210257_add_delayed_jobs_next_in_strand.rb +25 -25
  6. data/db/migrate/20120510004759_delayed_jobs_delete_trigger_lock_for_update.rb +4 -8
  7. data/db/migrate/20120531150712_drop_psql_jobs_pop_fn.rb +1 -3
  8. data/db/migrate/20120607164022_delayed_jobs_use_advisory_locks.rb +11 -15
  9. data/db/migrate/20120607181141_index_jobs_on_locked_by.rb +1 -1
  10. data/db/migrate/20120608191051_add_jobs_run_at_index.rb +2 -2
  11. data/db/migrate/20120927184213_change_delayed_jobs_handler_to_text.rb +1 -1
  12. data/db/migrate/20140505215510_copy_failed_jobs_original_id.rb +2 -3
  13. data/db/migrate/20150807133223_add_max_concurrent_to_jobs.rb +9 -13
  14. data/db/migrate/20151210162949_improve_max_concurrent.rb +4 -8
  15. data/db/migrate/20161206323555_add_back_default_string_limits_jobs.rb +3 -2
  16. data/db/migrate/20181217155351_speed_up_max_concurrent_triggers.rb +13 -17
  17. data/db/migrate/20200330230722_add_id_to_get_delayed_jobs_index.rb +8 -8
  18. data/db/migrate/20200824222232_speed_up_max_concurrent_delete_trigger.rb +72 -77
  19. data/db/migrate/20200825011002_add_strand_order_override.rb +93 -97
  20. data/db/migrate/20210809145804_add_n_strand_index.rb +12 -0
  21. data/db/migrate/20210812210128_add_singleton_column.rb +200 -0
  22. data/db/migrate/20210917232626_add_delete_conflicting_singletons_before_unlock_trigger.rb +27 -0
  23. data/db/migrate/20210928174754_fix_singleton_condition_in_before_insert.rb +56 -0
  24. data/db/migrate/20210929204903_update_conflicting_singleton_function_to_use_index.rb +27 -0
  25. data/exe/inst_jobs +3 -2
  26. data/lib/delayed/backend/active_record.rb +211 -168
  27. data/lib/delayed/backend/base.rb +110 -72
  28. data/lib/delayed/batch.rb +11 -9
  29. data/lib/delayed/cli.rb +98 -84
  30. data/lib/delayed/core_ext/kernel.rb +4 -2
  31. data/lib/delayed/daemon.rb +70 -74
  32. data/lib/delayed/job_tracking.rb +26 -25
  33. data/lib/delayed/lifecycle.rb +27 -23
  34. data/lib/delayed/log_tailer.rb +17 -17
  35. data/lib/delayed/logging.rb +13 -16
  36. data/lib/delayed/message_sending.rb +43 -52
  37. data/lib/delayed/performable_method.rb +6 -8
  38. data/lib/delayed/periodic.rb +72 -68
  39. data/lib/delayed/plugin.rb +2 -4
  40. data/lib/delayed/pool.rb +205 -168
  41. data/lib/delayed/server/helpers.rb +6 -6
  42. data/lib/delayed/server.rb +51 -54
  43. data/lib/delayed/settings.rb +94 -81
  44. data/lib/delayed/testing.rb +21 -22
  45. data/lib/delayed/version.rb +1 -1
  46. data/lib/delayed/work_queue/in_process.rb +21 -17
  47. data/lib/delayed/work_queue/parent_process/client.rb +55 -53
  48. data/lib/delayed/work_queue/parent_process/server.rb +245 -207
  49. data/lib/delayed/work_queue/parent_process.rb +52 -53
  50. data/lib/delayed/worker/consul_health_check.rb +32 -33
  51. data/lib/delayed/worker/health_check.rb +34 -26
  52. data/lib/delayed/worker/null_health_check.rb +3 -1
  53. data/lib/delayed/worker/process_helper.rb +8 -9
  54. data/lib/delayed/worker.rb +272 -241
  55. data/lib/delayed/yaml_extensions.rb +12 -10
  56. data/lib/delayed_job.rb +37 -37
  57. data/lib/inst-jobs.rb +1 -1
  58. data/spec/active_record_job_spec.rb +143 -139
  59. data/spec/delayed/cli_spec.rb +7 -7
  60. data/spec/delayed/daemon_spec.rb +10 -9
  61. data/spec/delayed/message_sending_spec.rb +16 -9
  62. data/spec/delayed/periodic_spec.rb +14 -21
  63. data/spec/delayed/server_spec.rb +38 -38
  64. data/spec/delayed/settings_spec.rb +26 -25
  65. data/spec/delayed/work_queue/in_process_spec.rb +7 -8
  66. data/spec/delayed/work_queue/parent_process/client_spec.rb +17 -12
  67. data/spec/delayed/work_queue/parent_process/server_spec.rb +117 -41
  68. data/spec/delayed/work_queue/parent_process_spec.rb +21 -23
  69. data/spec/delayed/worker/consul_health_check_spec.rb +37 -50
  70. data/spec/delayed/worker/health_check_spec.rb +60 -52
  71. data/spec/delayed/worker_spec.rb +44 -21
  72. data/spec/sample_jobs.rb +45 -15
  73. data/spec/shared/delayed_batch.rb +74 -67
  74. data/spec/shared/delayed_method.rb +143 -102
  75. data/spec/shared/performable_method.rb +39 -38
  76. data/spec/shared/shared_backend.rb +550 -437
  77. data/spec/shared/testing.rb +14 -14
  78. data/spec/shared/worker.rb +156 -148
  79. data/spec/shared_jobs_specs.rb +13 -13
  80. data/spec/spec_helper.rb +53 -55
  81. metadata +148 -82
  82. data/lib/delayed/backend/redis/bulk_update.lua +0 -50
  83. data/lib/delayed/backend/redis/destroy_job.lua +0 -2
  84. data/lib/delayed/backend/redis/enqueue.lua +0 -29
  85. data/lib/delayed/backend/redis/fail_job.lua +0 -5
  86. data/lib/delayed/backend/redis/find_available.lua +0 -3
  87. data/lib/delayed/backend/redis/functions.rb +0 -59
  88. data/lib/delayed/backend/redis/get_and_lock_next_available.lua +0 -17
  89. data/lib/delayed/backend/redis/includes/jobs_common.lua +0 -203
  90. data/lib/delayed/backend/redis/job.rb +0 -535
  91. data/lib/delayed/backend/redis/set_running.lua +0 -5
  92. data/lib/delayed/backend/redis/tickle_strand.lua +0 -2
  93. data/spec/gemfiles/42.gemfile +0 -7
  94. data/spec/gemfiles/50.gemfile +0 -7
  95. data/spec/gemfiles/51.gemfile +0 -7
  96. data/spec/gemfiles/52.gemfile +0 -7
  97. data/spec/gemfiles/60.gemfile +0 -7
  98. data/spec/redis_job_spec.rb +0 -148
@@ -1,34 +1,32 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'sinatra/base'
4
- require 'sinatra/json'
5
- require 'json'
6
- require 'delayed_job'
3
+ require "sinatra/base"
4
+ require "sinatra/json"
5
+ require "json"
6
+ require "delayed_job"
7
7
 
8
8
  module Delayed
9
9
  class Server < Sinatra::Base
10
10
  APP_DIR = File.dirname(File.expand_path(__FILE__))
11
- set :views, File.join(APP_DIR, 'server', 'views')
12
- set :public_folder, File.join(APP_DIR, 'server', 'public')
11
+ set :views, File.join(APP_DIR, "server", "views")
12
+ set :public_folder, File.join(APP_DIR, "server", "public")
13
13
 
14
- def initialize(*args, &block)
14
+ def initialize(*args)
15
15
  super()
16
16
  # Rails will take care of establishing the DB connection for us if there is
17
17
  # an application present
18
18
  if using_active_record? && !ActiveRecord::Base.connected?
19
- ActiveRecord::Base.establish_connection(ENV['DATABASE_URL'])
19
+ ActiveRecord::Base.establish_connection(ENV["DATABASE_URL"])
20
20
  end
21
21
 
22
- @allow_update = args.length > 0 && args[0][:update]
22
+ @allow_update = args.length.positive? && args[0][:update]
23
23
  end
24
24
 
25
25
  def using_active_record?
26
26
  Delayed::Job == Delayed::Backend::ActiveRecord::Job
27
27
  end
28
28
 
29
- def allow_update
30
- @allow_update
31
- end
29
+ attr_reader :allow_update
32
30
 
33
31
  # Ensure we're connected to the DB before processing the request
34
32
  before do
@@ -43,72 +41,72 @@ module Delayed
43
41
  end
44
42
 
45
43
  configure :development do
46
- require 'sinatra/reloader'
44
+ require "sinatra/reloader"
47
45
  register Sinatra::Reloader
48
46
  end
49
47
 
50
48
  helpers do
51
49
  # this can't get required until the class has been opened for the first time
52
- require 'delayed/server/helpers'
50
+ require "delayed/server/helpers"
53
51
  include Delayed::Server::Helpers
54
52
  end
55
53
 
56
- get '/' do
54
+ get "/" do
57
55
  erb :index
58
56
  end
59
57
 
60
- get '/running' do
58
+ get "/running" do
61
59
  content_type :json
62
60
  json({
63
- draw: params['draw'].to_i,
64
- recordsTotal: Delayed::Job.running.count,
65
- recordsFiltered: Delayed::Job.running.count,
66
- data: Delayed::Job.running_jobs.map{ |j|
67
- j.as_json(include_root: false, except: [:handler, :last_error])
68
- },
69
- })
61
+ draw: params["draw"].to_i,
62
+ recordsTotal: Delayed::Job.running.count,
63
+ recordsFiltered: Delayed::Job.running.count,
64
+ data: Delayed::Job.running_jobs.map do |j|
65
+ j.as_json(include_root: false, except: %i[handler last_error])
66
+ end
67
+ })
70
68
  end
71
69
 
72
- get '/tags' do
70
+ get "/tags" do
73
71
  content_type :json
74
72
  json({
75
- draw: params['draw'].to_i,
76
- data: Delayed::Job.tag_counts('current', 10)
77
- })
73
+ draw: params["draw"].to_i,
74
+ data: Delayed::Job.tag_counts("current", 10)
75
+ })
78
76
  end
79
77
 
80
78
  DEFAULT_PAGE_SIZE = 10
81
79
  MAX_PAGE_SIZE = 100
82
- get '/jobs' do
80
+ get "/jobs" do
83
81
  content_type :json
84
- flavor = params['flavor'] || 'current'
82
+ flavor = params["flavor"] || "current"
85
83
  page_size = extract_page_size
86
- offset = Integer(params['start'] || 0)
84
+ offset = Integer(params["start"] || 0)
87
85
  case flavor
88
- when 'id'
89
- jobs = Delayed::Job.where(id: params['search_term'])
86
+ when "id"
87
+ jobs = Delayed::Job.where(id: params["search_term"])
90
88
  total_records = 1
91
- when 'future', 'current', 'failed'
89
+ when "future", "current", "failed"
92
90
  jobs = Delayed::Job.list_jobs(flavor, page_size, offset)
93
- total_records = Delayed::Job.jobs_count(flavor)
91
+ total_records = Delayed::Job.jobs_count(flavor)
94
92
  else
95
- query = params['search_term']
96
- if query.present?
97
- jobs = Delayed::Job.list_jobs(flavor, page_size, offset, query)
98
- else
99
- jobs = []
100
- end
101
- total_records = Delayed::Job.jobs_count(flavor, query)
93
+ query = params["search_term"]
94
+ jobs = if query.present?
95
+ Delayed::Job.list_jobs(flavor, page_size, offset, query)
96
+ else
97
+ []
98
+ end
99
+ total_records = Delayed::Job.jobs_count(flavor, query)
102
100
  end
103
101
  json({
104
- draw: params['draw'].to_i,
105
- recordsTotal: total_records,
106
- recordsFiltered: jobs.size,
107
- data: build_jobs_json(jobs),
108
- })
102
+ draw: params["draw"].to_i,
103
+ recordsTotal: total_records,
104
+ recordsFiltered: jobs.size,
105
+ data: build_jobs_json(jobs)
106
+ })
109
107
  end
110
108
 
111
- post '/bulk_update' do
109
+ post "/bulk_update" do
112
110
  content_type :json
113
111
 
114
112
  halt 403 unless @allow_update
@@ -117,25 +115,24 @@ module Delayed
117
115
  Delayed::Job.bulk_update(payload[:action], { ids: payload[:ids] })
118
116
 
119
117
  json({
120
- success: true
121
- })
118
+ success: true
119
+ })
122
120
  end
123
121
 
124
122
  private
125
123
 
126
124
  def extract_page_size
127
- page_size = Integer(params['length'] || DEFAULT_PAGE_SIZE)
125
+ page_size = Integer(params["length"] || DEFAULT_PAGE_SIZE)
128
126
  # if dataTables wants all of the records it will send us -1 but we don't
129
127
  # want the potential to kill our servers with this request so we'll limit it
130
128
  page_size = DEFAULT_PAGE_SIZE if page_size == -1
131
129
  [page_size, MAX_PAGE_SIZE].min
132
130
  end
133
131
 
134
-
135
132
  def build_jobs_json(jobs)
136
- json = jobs.map{ |j|
137
- j.as_json(root: false, except: [:handler, :last_error])
138
- }
133
+ jobs.map do |j|
134
+ j.as_json(root: false, except: %i[handler last_error])
135
+ end
139
136
  end
140
137
  end
141
138
  end
@@ -1,16 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'yaml'
4
- require 'erb'
5
- require 'active_support/core_ext/hash/indifferent_access'
3
+ require "yaml"
4
+ require "erb"
5
+ require "active_support/core_ext/hash/indifferent_access"
6
6
 
7
7
  module Delayed
8
8
  module Settings
9
9
  SETTINGS = [
10
10
  :default_job_options,
11
+ :disable_abandoned_job_cleanup,
11
12
  :disable_periodic_jobs,
12
13
  :disable_automatic_orphan_unlocking,
13
14
  :fetch_batch_size,
15
+ # this is a transitional setting, so that you don't have a time where a
16
+ # singleton switches to using the singleton column, but there are old
17
+ # jobs that only used strand
18
+ :infer_strand_from_singleton,
14
19
  :kill_workers_on_exit,
15
20
  :last_ditch_logfile,
16
21
  :max_attempts,
@@ -23,23 +28,13 @@ module Delayed
23
28
  :slow_exit_timeout,
24
29
  :worker_health_check_type,
25
30
  :worker_health_check_config,
26
- :worker_procname_prefix,
27
- ]
28
- SETTINGS_WITH_ARGS = [
29
- :job_detailed_log_format,
30
- :num_strands
31
- ]
32
-
33
- SETTINGS.each do |setting|
34
- mattr_writer(setting)
35
- self.send("#{setting}=", nil)
36
- define_singleton_method(setting) do
37
- val = class_variable_get(:"@@#{setting}")
38
- val.respond_to?(:call) ? val.call() : val
39
- end
40
- end
31
+ :worker_procname_prefix
32
+ ].freeze
41
33
 
42
- mattr_accessor(*SETTINGS_WITH_ARGS)
34
+ SETTINGS_WITH_ARGS = %i[
35
+ job_detailed_log_format
36
+ num_strands
37
+ ].freeze
43
38
 
44
39
  PARENT_PROCESS_DEFAULTS = {
45
40
  server_socket_timeout: 10.0,
@@ -49,17 +44,86 @@ module Delayed
49
44
 
50
45
  # We'll accept a partial, relative path and assume we want it inside
51
46
  # Rails.root with inst-jobs.sock appended if provided a directory.
52
- server_address: 'tmp',
47
+ server_address: "tmp"
53
48
  }.with_indifferent_access.freeze
54
49
 
55
- mattr_reader(:parent_process)
56
- @@parent_process = PARENT_PROCESS_DEFAULTS.dup
50
+ class << self
51
+ attr_accessor(*SETTINGS_WITH_ARGS)
52
+ attr_reader :parent_process
53
+
54
+ SETTINGS.each do |setting|
55
+ attr_writer setting
56
+
57
+ define_method(setting) do
58
+ val = instance_variable_get(:"@#{setting}")
59
+ val.respond_to?(:call) ? val.call : val
60
+ end
61
+ end
62
+
63
+ def queue=(queue_name)
64
+ raise ArgumentError, "queue_name must not be blank" if queue_name.blank?
65
+
66
+ @queue = queue_name
67
+ end
68
+
69
+ def worker_config(config_filename = nil)
70
+ config_filename ||= default_worker_config_name
71
+ config = YAML.load(ERB.new(File.read(config_filename)).result)
72
+ env = Rails.env || "development"
73
+ config = config[env] || config["default"]
74
+ # Backwards compatibility from when the config was just an array of queues
75
+ config = { workers: config } if config.is_a?(Array)
76
+ unless config.is_a?(Hash)
77
+ raise ArgumentError,
78
+ "Invalid config file #{config_filename}"
79
+ end
80
+ config = config.with_indifferent_access
81
+ config[:workers].map! do |worker_config|
82
+ config.except(:workers).merge(worker_config.with_indifferent_access)
83
+ end
84
+ config
85
+ end
86
+
87
+ def apply_worker_config!(config)
88
+ SETTINGS.each do |setting|
89
+ send("#{setting}=", config[setting.to_s]) if config.key?(setting.to_s)
90
+ end
91
+ if config.key?("parent_process_client_timeout")
92
+ parent_process.client_timeout = config["parent_process_client_timeout"]
93
+ end
94
+ self.parent_process = config["parent_process"] if config.key?("parent_process")
95
+ end
96
+
97
+ def default_worker_config_name
98
+ expand_rails_path("config/delayed_jobs.yml")
99
+ end
100
+
101
+ # Expands rails-relative paths, without depending on rails being loaded.
102
+ def expand_rails_path(path)
103
+ root = if defined?(Rails) && Rails.root
104
+ Rails.root.join("Gemfile")
105
+ else
106
+ ENV.fetch("BUNDLE_GEMFILE", "#{Dir.pwd}/Gemfile")
107
+ end
108
+ File.expand_path("../#{path}", root)
109
+ end
110
+
111
+ def parent_process_client_timeout=(val)
112
+ parent_process["server_socket_timeout"] = Integer(val)
113
+ end
114
+
115
+ def parent_process=(new_config)
116
+ raise "Parent process configurations must be a hash!" unless new_config.is_a?(Hash)
117
+
118
+ @parent_process = PARENT_PROCESS_DEFAULTS.merge(new_config)
119
+ end
57
120
 
58
- def self.queue=(queue_name)
59
- raise(ArgumentError, "queue_name must not be blank") if queue_name.blank?
60
- @@queue = queue_name
121
+ def worker_health_check_config=(new_config)
122
+ @worker_health_check_config = (new_config || {}).with_indifferent_access
123
+ end
61
124
  end
62
125
 
126
+ self.parent_process = PARENT_PROCESS_DEFAULTS.dup
63
127
  self.queue = "queue"
64
128
  self.max_attempts = 1
65
129
  self.sleep_delay = 2.0
@@ -68,9 +132,11 @@ module Delayed
68
132
  self.select_random_from_batch = false
69
133
  self.silence_periodic_log = false
70
134
 
71
- self.num_strands = ->(strand_name){ nil }
72
- self.default_job_options = ->{ Hash.new }
73
- self.job_detailed_log_format = ->(job){ job.to_json(include_root: false, only: %w(tag strand priority attempts created_at max_attempts source)) }
135
+ self.num_strands = ->(_strand_name) {}
136
+ self.default_job_options = -> { {} }
137
+ self.job_detailed_log_format = lambda { |job|
138
+ job.to_json(include_root: false, only: %w[tag strand priority attempts created_at max_attempts source])
139
+ }
74
140
 
75
141
  # Send workers KILL after QUIT if they haven't exited within the
76
142
  # slow_exit_timeout
@@ -79,58 +145,5 @@ module Delayed
79
145
 
80
146
  self.worker_health_check_type = :none
81
147
  self.worker_health_check_config = {}
82
-
83
- def self.worker_config(config_filename = nil)
84
- config_filename ||= default_worker_config_name
85
- config = YAML.load(ERB.new(File.read(config_filename)).result)
86
- env = defined?(RAILS_ENV) ? RAILS_ENV : ENV['RAILS_ENV'] || 'development'
87
- config = config[env] || config['default']
88
- # Backwards compatibility from when the config was just an array of queues
89
- config = { :workers => config } if config.is_a?(Array)
90
- unless config && config.is_a?(Hash)
91
- raise ArgumentError,
92
- "Invalid config file #{config_filename}"
93
- end
94
- config = config.with_indifferent_access
95
- config[:workers].map! do |worker_config|
96
- config.except(:workers).merge(worker_config.with_indifferent_access)
97
- end
98
- config
99
- end
100
-
101
- def self.apply_worker_config!(config)
102
- SETTINGS.each do |setting|
103
- self.send("#{setting}=", config[setting.to_s]) if config.key?(setting.to_s)
104
- end
105
- parent_process.client_timeout = config['parent_process_client_timeout'] if config.key?('parent_process_client_timeout')
106
- self.parent_process = config['parent_process'] if config.key?('parent_process')
107
- end
108
-
109
- def self.default_worker_config_name
110
- expand_rails_path("config/delayed_jobs.yml")
111
- end
112
-
113
- # Expands rails-relative paths, without depending on rails being loaded.
114
- def self.expand_rails_path(path)
115
- root = if defined?(Rails) && Rails.root
116
- (Rails.root+"Gemfile").to_s
117
- else
118
- ENV.fetch('BUNDLE_GEMFILE', Dir.pwd+"/Gemfile")
119
- end
120
- File.expand_path("../#{path}", root)
121
- end
122
-
123
- def self.parent_process_client_timeout=(val)
124
- parent_process['server_socket_timeout'] = Integer(val)
125
- end
126
-
127
- def self.parent_process=(new_config)
128
- raise 'Parent process configurations must be a hash!' unless Hash === new_config
129
- @@parent_process = PARENT_PROCESS_DEFAULTS.merge(new_config)
130
- end
131
-
132
- def self.worker_health_check_config=(new_config)
133
- @@worker_health_check_config = (new_config || {}).with_indifferent_access
134
- end
135
148
  end
136
149
  end
@@ -1,34 +1,33 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Delayed
4
- module Testing
5
- def self.run_job(job)
6
- Delayed::Worker.new.perform(job)
7
- end
4
+ module Testing
5
+ def self.run_job(job)
6
+ Delayed::Worker.new.perform(job)
7
+ end
8
8
 
9
- def self.drain
10
- while job = Delayed::Job.get_and_lock_next_available(
11
- 'spec run_jobs',
9
+ def self.drain
10
+ while (job = Delayed::Job.get_and_lock_next_available(
11
+ "spec run_jobs",
12
12
  Delayed::Settings.queue,
13
13
  0,
14
- Delayed::MAX_PRIORITY)
15
- run_job(job)
14
+ Delayed::MAX_PRIORITY
15
+ ))
16
+ run_job(job)
17
+ end
16
18
  end
17
- end
18
19
 
19
- def self.track_created
20
- job_tracking = JobTracking.track { yield }
21
- job_tracking.created
22
- end
20
+ def self.track_created(&block)
21
+ job_tracking = JobTracking.track(&block)
22
+ job_tracking.created
23
+ end
23
24
 
24
- def self.clear_all!
25
- case Delayed::Job.name
26
- when /Redis/
27
- Delayed::Job.redis.flushdb
28
- when /ActiveRecord/
29
- Delayed::Job.delete_all
30
- Delayed::Job::Failed.delete_all
25
+ def self.clear_all!
26
+ case Delayed::Job.name
27
+ when /ActiveRecord/
28
+ Delayed::Job.delete_all
29
+ Delayed::Job::Failed.delete_all
30
+ end
31
31
  end
32
32
  end
33
33
  end
34
- end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Delayed
4
- VERSION = "2.0.0"
4
+ VERSION = "3.0.0"
5
5
  end
@@ -1,23 +1,27 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Delayed
4
- module WorkQueue
5
- # The simplest possible implementation of a WorkQueue -- just turns around and
6
- # queries the queue inline.
7
- class InProcess
8
- def get_and_lock_next_available(worker_name, worker_config)
9
- Delayed::Worker.lifecycle.run_callbacks(:work_queue_pop, self, worker_config) do
10
- Delayed::Job.get_and_lock_next_available(
11
- worker_name,
12
- worker_config[:queue],
13
- worker_config[:min_priority],
14
- worker_config[:max_priority])
4
+ module WorkQueue
5
+ # The simplest possible implementation of a WorkQueue -- just turns around and
6
+ # queries the queue inline.
7
+ class InProcess
8
+ def get_and_lock_next_available(worker_name, worker_config)
9
+ Delayed::Worker.lifecycle.run_callbacks(:work_queue_pop, self, worker_config) do
10
+ Delayed::Job.get_and_lock_next_available(
11
+ worker_name,
12
+ worker_config[:queue],
13
+ worker_config[:min_priority],
14
+ worker_config[:max_priority]
15
+ )
16
+ end
17
+ end
18
+
19
+ # intentional nops for compatibility w/ parent process
20
+ def init; end
21
+
22
+ def close; end
23
+
24
+ def wake_up; end
15
25
  end
16
26
  end
17
-
18
- # intentional nops for compatibility w/ parent process
19
- def close; end
20
- def wake_up; end
21
- end
22
- end
23
27
  end
@@ -1,73 +1,75 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Delayed
4
- module WorkQueue
5
- class ParentProcess
6
- class Client
7
- attr_reader :addrinfo
4
+ module WorkQueue
5
+ class ParentProcess
6
+ class Client
7
+ attr_reader :addrinfo
8
8
 
9
- include Delayed::Logging
9
+ include Delayed::Logging
10
10
 
11
- def initialize(addrinfo, config: Settings.parent_process)
12
- @addrinfo = addrinfo
13
- @connect_timeout = config['client_connect_timeout'] || 2
14
- @self_pipe = IO.pipe
15
- end
11
+ def initialize(addrinfo, config: Settings.parent_process)
12
+ @addrinfo = addrinfo
13
+ @connect_timeout = config["client_connect_timeout"] || 2
14
+ end
16
15
 
17
- def close
18
- reset_connection
19
- end
16
+ def init
17
+ @self_pipe ||= IO.pipe # rubocop:disable Naming/MemoizedInstanceVariableName
18
+ end
20
19
 
21
- def get_and_lock_next_available(worker_name, worker_config)
22
- Marshal.dump([worker_name, worker_config], socket)
20
+ def close
21
+ reset_connection
22
+ end
23
23
 
24
- # We're assuming there won't ever be a partial write here so we only need
25
- # to wait for anything to be available on the 'wire', this is a valid
26
- # assumption because we control the server and it's a Unix domain socket,
27
- # not TCP.
28
- if socket.eof?
29
- # Other end closed gracefully, so should we
30
- logger.debug("server closed connection")
31
- return reset_connection
32
- end
24
+ def get_and_lock_next_available(worker_name, worker_config)
25
+ Marshal.dump([worker_name, worker_config], socket)
26
+
27
+ # We're assuming there won't ever be a partial write here so we only need
28
+ # to wait for anything to be available on the 'wire', this is a valid
29
+ # assumption because we control the server and it's a Unix domain socket,
30
+ # not TCP.
31
+ if socket.eof?
32
+ # Other end closed gracefully, so should we
33
+ logger.debug("server closed connection")
34
+ return reset_connection
35
+ end
36
+
37
+ readers, = IO.select([socket, @self_pipe[0]])
33
38
 
34
- readers, _, _ = IO.select([socket, @self_pipe[0]])
39
+ if readers.include?(@self_pipe[0])
40
+ # we're probably exiting so we just want to break out of the blocking read
41
+ logger.debug("Broke out of select due to being awakened, exiting")
42
+ else
43
+ Marshal.load(socket).tap do |response|
44
+ unless response.nil? || (response.is_a?(Delayed::Job) && response.locked_by == worker_name)
45
+ raise(ProtocolError, "response is not a locked job: #{response.inspect}")
46
+ end
35
47
 
36
- if readers.include?(@self_pipe[0])
37
- # we're probably exiting so we just want to break out of the blocking read
38
- logger.debug("Broke out of select due to being awakened, exiting")
39
- else
40
- Marshal.load(socket).tap do |response|
41
- unless response.nil? || (response.is_a?(Delayed::Job) && response.locked_by == worker_name)
42
- raise(ProtocolError, "response is not a locked job: #{response.inspect}")
48
+ logger.debug("Received job #{response.id}")
49
+ end
43
50
  end
44
- logger.debug("Received job #{response.id}")
51
+ rescue SystemCallError, IOError => e
52
+ logger.error("Work queue connection lost, reestablishing on next poll. (#{e})")
53
+ # The work queue process died. Return nil to signal the worker
54
+ # process should sleep as if no job was found, and then retry.
55
+ reset_connection
45
56
  end
46
- end
47
- rescue SystemCallError, IOError => ex
48
- logger.error("Work queue connection lost, reestablishing on next poll. (#{ex})")
49
- # The work queue process died. Return nil to signal the worker
50
- # process should sleep as if no job was found, and then retry.
51
- reset_connection
52
- end
53
57
 
54
- def wake_up
55
- @self_pipe[1].write_nonblock('.', exception: false)
56
- end
58
+ def wake_up
59
+ @self_pipe[1].write_nonblock(".", exception: false)
60
+ end
57
61
 
58
- private
62
+ private
59
63
 
60
- def socket
61
- @socket ||= @addrinfo.connect(timeout: @connect_timeout)
62
- end
64
+ def socket
65
+ @socket ||= @addrinfo.connect(timeout: @connect_timeout)
66
+ end
63
67
 
64
- def reset_connection
65
- if @socket
66
- @socket.close
67
- @socket = nil
68
+ def reset_connection
69
+ @socket&.close
70
+ @socket = nil
71
+ end
68
72
  end
69
73
  end
70
74
  end
71
75
  end
72
- end
73
- end