exekutor 0.1.0 → 0.1.2

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 (51) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +2 -3
  3. data/exe/exekutor +2 -2
  4. data/lib/active_job/queue_adapters/exekutor_adapter.rb +2 -1
  5. data/lib/exekutor/asynchronous.rb +143 -75
  6. data/lib/exekutor/cleanup.rb +27 -28
  7. data/lib/exekutor/configuration.rb +102 -48
  8. data/lib/exekutor/hook.rb +15 -11
  9. data/lib/exekutor/info/worker.rb +3 -3
  10. data/lib/exekutor/internal/base_record.rb +2 -1
  11. data/lib/exekutor/internal/callbacks.rb +55 -35
  12. data/lib/exekutor/internal/cli/app.rb +33 -23
  13. data/lib/exekutor/internal/cli/application_loader.rb +17 -6
  14. data/lib/exekutor/internal/cli/cleanup.rb +54 -40
  15. data/lib/exekutor/internal/cli/daemon.rb +9 -11
  16. data/lib/exekutor/internal/cli/default_option_value.rb +3 -1
  17. data/lib/exekutor/internal/cli/info.rb +117 -84
  18. data/lib/exekutor/internal/cli/manager.rb +234 -123
  19. data/lib/exekutor/internal/configuration_builder.rb +49 -30
  20. data/lib/exekutor/internal/database_connection.rb +6 -0
  21. data/lib/exekutor/internal/executable.rb +12 -7
  22. data/lib/exekutor/internal/executor.rb +50 -21
  23. data/lib/exekutor/internal/hooks.rb +11 -8
  24. data/lib/exekutor/internal/listener.rb +85 -43
  25. data/lib/exekutor/internal/logger.rb +29 -10
  26. data/lib/exekutor/internal/provider.rb +96 -77
  27. data/lib/exekutor/internal/reserver.rb +66 -19
  28. data/lib/exekutor/internal/status_server.rb +87 -54
  29. data/lib/exekutor/job.rb +1 -1
  30. data/lib/exekutor/job_error.rb +1 -1
  31. data/lib/exekutor/job_options.rb +22 -13
  32. data/lib/exekutor/plugins/appsignal.rb +7 -5
  33. data/lib/exekutor/plugins.rb +8 -4
  34. data/lib/exekutor/queue.rb +69 -30
  35. data/lib/exekutor/version.rb +1 -1
  36. data/lib/exekutor/worker.rb +89 -48
  37. data/lib/exekutor.rb +2 -2
  38. data/lib/generators/exekutor/configuration_generator.rb +11 -6
  39. data/lib/generators/exekutor/install_generator.rb +24 -15
  40. data/lib/generators/exekutor/templates/install/functions/exekutor_broadcast_job_enqueued.sql +10 -0
  41. data/lib/generators/exekutor/templates/install/functions/exekutor_requeue_orphaned_jobs.sql +11 -0
  42. data/lib/generators/exekutor/templates/install/migrations/create_exekutor_schema.rb.erb +23 -22
  43. data/lib/generators/exekutor/templates/install/triggers/exekutor_broadcast_job_enqueued.sql +7 -0
  44. data/lib/generators/exekutor/templates/install/triggers/exekutor_requeue_orphaned_jobs.sql +5 -0
  45. data.tar.gz.sig +0 -0
  46. metadata +67 -23
  47. metadata.gz.sig +0 -0
  48. data/lib/generators/exekutor/templates/install/functions/job_notifier.sql +0 -7
  49. data/lib/generators/exekutor/templates/install/functions/requeue_orphaned_jobs.sql +0 -7
  50. data/lib/generators/exekutor/templates/install/triggers/notify_workers.sql +0 -6
  51. data/lib/generators/exekutor/templates/install/triggers/requeue_orphaned_jobs.sql +0 -5
@@ -23,64 +23,43 @@ module Exekutor
23
23
  # @option config [Array<String>] :queues the queues to work on
24
24
  # @option config [Integer] :min_threads the minimum number of execution threads that should be active
25
25
  # @option config [Integer] :max_threads the maximum number of execution threads that may be active
26
- # @option config [Integer] :max_thread_idletime the maximum number of seconds a thread may be idle before being stopped
27
- # @option config [Integer] :polling_interval the polling interval in seconds
26
+ # @option config [ActiveSupport::Duration] :max_thread_idletime the maximum duration a thread may be idle before
27
+ # being stopped
28
+ # @option config [ActiveSupport::Duration] :polling_interval the polling interval
28
29
  # @option config [Float] :poling_jitter the polling jitter
29
30
  # @option config [Boolean] :set_db_connection_name whether the DB connection name should be set
30
- # @option config [Integer,Boolean] :wait_for_termination how long the worker should wait on jobs to be completed before exiting
31
+ # @option config [Integer,Boolean] :wait_for_termination how long the worker should wait on jobs to be completed
32
+ # before exiting
31
33
  # @option config [Integer] :status_server_port the port to run the status server on
32
34
  # @option config [String] :status_server_handler The name of the rack handler to use for the status server
33
- # @option config [Integer] :healthcheck_timeout The timeout of a worker in minutes before the healthcheck server deems it as down
35
+ # @option config [ActiveSupport::Duration] :healthcheck_timeout The timeout of a worker in minutes before the
36
+ # healthcheck server deems it as down
34
37
  def initialize(config = {})
35
38
  super()
36
39
  @config = config
37
40
  @record = create_record!
38
41
 
39
- @reserver = Internal::Reserver.new @record.id, config[:queues]
40
- @executor = Internal::Executor.new(**config.slice(:min_threads, :max_threads, :max_thread_idletime,
41
- :delete_completed_jobs, :delete_discarded_jobs,
42
- :delete_failed_jobs))
42
+ provider_pool = create_provider_pool(config)
43
43
 
44
- provider_threads = 1
45
- provider_threads += 1 if config.fetch(:enable_listener, true)
46
- provider_threads += 1 if config[:status_server_port].to_i > 0
47
-
48
- provider_pool = Concurrent::FixedThreadPool.new provider_threads, max_queue: provider_threads,
49
- name: "exekutor-provider"
50
-
51
- @provider = Internal::Provider.new reserver: @reserver, executor: @executor, pool: provider_pool,
52
- **provider_options(config)
44
+ @executor = create_executor(config)
45
+ @provider = create_provider(config, @executor, provider_pool)
53
46
 
54
47
  @executables = [@executor, @provider]
55
- if config.fetch(:enable_listener, true)
56
- listener = Internal::Listener.new worker_id: @record.id, provider: @provider, pool: provider_pool,
57
- **listener_options(config)
58
- @executables << listener
59
- end
60
- if config[:status_server_port].to_i > 0
61
- server = Internal::StatusServer.new worker: self, pool: provider_pool, **status_server_options(config)
62
- @executables << server
63
- end
48
+ create_listener(provider_pool, config) if config.fetch(:enable_listener, true)
49
+ create_status_server(provider_pool, config) if config[:status_server_port].to_i.positive?
64
50
  @executables.freeze
65
-
66
- @executor.after_execute(@record) do |_job, worker_info|
67
- worker_info.heartbeat! rescue nil
68
- @provider.poll if @provider.running?
69
- end
70
- @provider.on_queue_empty(@record) do |worker_info|
71
- worker_info.heartbeat! rescue nil
72
- @executor.prune_pool
73
- end
74
51
  end
75
52
 
76
53
  # Starts the worker. Does nothing if the worker has already started.
77
54
  # @return [Boolean] whether the worker was started
78
55
  def start
79
56
  return false unless compare_and_set_state(:pending, :started)
57
+
80
58
  Internal::Hooks.run :startup, self do
81
59
  @executables.each(&:start)
82
60
  @record.update(status: "r")
83
61
  end
62
+
84
63
  true
85
64
  end
86
65
 
@@ -89,22 +68,21 @@ module Exekutor
89
68
  # @return true
90
69
  def stop
91
70
  Internal::Hooks.run :shutdown, self do
92
- set_state :stopped
71
+ self.state = :stopped
93
72
  unless @record.destroyed?
94
73
  begin
95
74
  @record.update(status: "s")
96
- rescue
97
- #ignored
75
+ rescue StandardError
76
+ # ignored
98
77
  end
99
78
  end
100
79
  @executables.reverse_each(&:stop)
101
-
102
- wait_for_termination @config[:wait_for_termination] if @config[:wait_for_termination]
80
+ wait_for_termination @config[:wait_for_termination]
103
81
 
104
82
  begin
105
83
  @record.destroy
106
- rescue
107
- #ignored
84
+ rescue StandardError
85
+ # ignored
108
86
  end
109
87
  @stop_event&.set if defined?(@stop_event)
110
88
  end
@@ -121,8 +99,8 @@ module Exekutor
121
99
  @executor.kill
122
100
  begin
123
101
  @record.destroy
124
- rescue
125
- #ignored
102
+ rescue StandardError
103
+ # ignored
126
104
  end
127
105
  true
128
106
  end
@@ -138,7 +116,7 @@ module Exekutor
138
116
 
139
117
  # Reserves and executes jobs.
140
118
  def reserve_jobs
141
- @provider.poll
119
+ @provider.poll if @provider&.running?
142
120
  end
143
121
 
144
122
  # The worker ID.
@@ -146,24 +124,76 @@ module Exekutor
146
124
  @record.id
147
125
  end
148
126
 
127
+ # @return [Time,nil] The timestamp of the last heartbeat. The timestamp is truncated to whole minutes.
149
128
  def last_heartbeat
150
129
  @record.last_heartbeat_at
151
130
  end
152
131
 
132
+ # Returns the thread usage for this worker. The resulting hash will contain the following key-value pairs:
133
+ # - +:minimum+, (Integer) the minimum number of threads that should be active;
134
+ # - +:maximum+, (Integer) the maximum number of threads may should be active;
135
+ # - +:available+, (Integer) the number of threads that are available to execute new jobs;
136
+ # - +:usage_percent+, (Float, 0-100) the percentage of workers that are currently busy executing jobs.
137
+ # @return [Hash] the thread usage
153
138
  def thread_stats
154
139
  available = @executor.available_threads
140
+ usage_percent = (((100 - (available * 100.0 / @executor.maximum_threads))).round(2) if @executor.running?)
155
141
  {
156
142
  minimum: @executor.minimum_threads,
157
143
  maximum: @executor.maximum_threads,
158
144
  available: available,
159
- usage_percent: if @executor.running?
160
- ((1 - (available.to_f / @executor.maximum_threads)) * 100).round(2)
161
- end
145
+ usage_percent: usage_percent
162
146
  }
163
147
  end
164
148
 
165
149
  private
166
150
 
151
+ def create_provider_pool(config)
152
+ provider_threads = 1
153
+ provider_threads += 1 if config.fetch(:enable_listener, true)
154
+ provider_threads += 1 if config[:status_server_port].to_i.positive?
155
+
156
+ Concurrent::FixedThreadPool.new provider_threads, max_queue: provider_threads, name: "exekutor-provider"
157
+ end
158
+
159
+ def create_executor(worker_options)
160
+ executor = Internal::Executor.new(**executor_options(worker_options))
161
+
162
+ executor.after_execute(@record) do |_job, worker_info|
163
+ begin
164
+ worker_info.heartbeat!
165
+ rescue StandardError
166
+ # ignored
167
+ end
168
+ reserve_jobs
169
+ end
170
+
171
+ executor
172
+ end
173
+
174
+ def executor_options(worker_options)
175
+ worker_options.slice(:min_threads, :max_threads, :max_thread_idletime,
176
+ :delete_completed_jobs, :delete_discarded_jobs,
177
+ :delete_failed_jobs)
178
+ end
179
+
180
+ def create_provider(worker_options, executor, thread_pool)
181
+ @reserver = Internal::Reserver.new @record.id, **worker_options.slice(:queues, :min_priority, :max_priority)
182
+ provider = Internal::Provider.new reserver: @reserver, executor: executor, pool: thread_pool,
183
+ **provider_options(worker_options)
184
+
185
+ provider.on_queue_empty(@record, executor) do |worker_info, thr_executor|
186
+ begin
187
+ worker_info.heartbeat!
188
+ rescue StandardError
189
+ # ignored
190
+ end
191
+ thr_executor.prune_pool
192
+ end
193
+
194
+ provider
195
+ end
196
+
167
197
  def provider_options(worker_options)
168
198
  worker_options.slice(:polling_interval, :polling_jitter).transform_keys do |key|
169
199
  case key
@@ -175,10 +205,21 @@ module Exekutor
175
205
  end
176
206
  end
177
207
 
208
+ def create_listener(provider_pool, config)
209
+ listener = Internal::Listener.new worker_id: @record.id, provider: @provider, pool: provider_pool,
210
+ **listener_options(config)
211
+ @executables << listener
212
+ end
213
+
178
214
  def listener_options(worker_options)
179
215
  worker_options.slice(:queues, :set_db_connection_name)
180
216
  end
181
217
 
218
+ def create_status_server(provider_pool, config)
219
+ server = Internal::StatusServer.new worker: self, pool: provider_pool, **status_server_options(config)
220
+ @executables << server
221
+ end
222
+
182
223
  def status_server_options(worker_options)
183
224
  worker_options.slice(:status_server_port, :status_server_handler, :healthcheck_timeout).transform_keys do |key|
184
225
  case key
data/lib/exekutor.rb CHANGED
@@ -2,8 +2,8 @@
2
2
 
3
3
  require_relative "exekutor/version"
4
4
 
5
+ # The Exekutor namespace
5
6
  module Exekutor
6
-
7
7
  # Base error class
8
8
  class Error < StandardError; end
9
9
 
@@ -45,5 +45,5 @@ ActiveSupport.on_load(:active_record) do
45
45
  end
46
46
  end
47
47
 
48
- Exekutor.private_constant "Internal"
48
+ Exekutor.private_constant :Internal
49
49
  ActiveSupport.run_load_hooks(:exekutor, Exekutor)
@@ -1,18 +1,23 @@
1
1
  # frozen_string_literal: true
2
- require 'rails/generators'
2
+
3
+ require "rails/generators"
3
4
 
4
5
  module Exekutor
6
+ # Generates a YAML configuration file
5
7
  class ConfigurationGenerator < Rails::Generators::Base
6
- desc 'Create YAML configuration for Exekutor'
8
+ desc "Create YAML configuration for Exekutor"
7
9
 
8
- class_option :identifier, type: :string, aliases: %i(--id), desc: "The worker identifier"
10
+ class_option :identifier, type: :string, aliases: %i[--id], desc: "The worker identifier"
9
11
 
12
+ # Creates the configuration file at +config/exekutor.yml+. Uses the current worker configuration as the base.
10
13
  def create_configuration_file
11
14
  config = { queues: %w[queues to watch] }.merge(Exekutor.config.worker_options)
12
- config[:status_port] = 8765
15
+ config[:status_port] = 12_677
13
16
  config[:set_db_connection_name] = true
14
17
  config[:wait_for_termination] = 120
15
- create_file "config/exekutor#{".#{options[:identifier]}" if options[:identifier]}.yml", { "exekutor" => config.stringify_keys }.to_yaml
18
+
19
+ filename = "config/exekutor#{".#{options[:identifier]}" if options[:identifier]}.yml"
20
+ create_file filename, { "exekutor" => config.stringify_keys }.to_yaml
16
21
  end
17
22
  end
18
- end
23
+ end
@@ -1,29 +1,27 @@
1
1
  # frozen_string_literal: true
2
- require 'rails/generators'
3
- require 'rails/generators/active_record'
2
+
3
+ require "rails/generators"
4
+ require "rails/generators/active_record"
4
5
 
5
6
  module Exekutor
7
+ # Generates the initializer and migrations
6
8
  class InstallGenerator < Rails::Generators::Base
7
9
  include ActiveRecord::Generators::Migration
8
- desc 'Create migrations for Exekutor'
10
+ desc "Create migrations for Exekutor"
9
11
 
10
- TEMPLATE_DIR = File.join(__dir__, 'templates/install')
12
+ TEMPLATE_DIR = File.join(__dir__, "templates/install")
11
13
  source_paths << TEMPLATE_DIR
12
14
 
15
+ # Creates the initializer file at +config/initializers/exekutor.rb+
13
16
  def create_initializer_file
14
- template 'initializers/exekutor.rb.erb', 'config/initializers/exekutor.rb'
17
+ template "initializers/exekutor.rb.erb", "config/initializers/exekutor.rb"
15
18
  end
16
19
 
20
+ # Creates the migration file in the migrations folder
17
21
  def create_migration_file
18
- migration_template 'migrations/create_exekutor_schema.rb.erb', File.join(db_migrate_path, 'create_exekutor_schema.rb')
19
- if defined? Fx
20
- %w(job_notifier requeue_orphaned_jobs).each do |function|
21
- copy_file "functions/#{function}.sql", Fx::Definition.new(name: function, version: 1).full_path
22
- end
23
- %w(notify_workers requeue_orphaned_jobs).each do |trigger|
24
- copy_file "triggers/#{trigger}.sql", Fx::Definition.new(name: trigger, version: 1, type: "trigger").full_path
25
- end
26
- end
22
+ migration_template "migrations/create_exekutor_schema.rb.erb",
23
+ File.join(db_migrate_path, "create_exekutor_schema.rb")
24
+ create_fx_files
27
25
  end
28
26
 
29
27
  protected
@@ -39,5 +37,16 @@ module Exekutor
39
37
  def trigger_sql(name)
40
38
  File.read File.join(TEMPLATE_DIR, "triggers/#{name}.sql")
41
39
  end
40
+
41
+ private
42
+
43
+ def create_fx_files
44
+ return unless defined?(Fx)
45
+
46
+ %w[exekutor_broadcast_job_enqueued exekutor_requeue_orphaned_jobs].each do |name|
47
+ copy_file "functions/#{name}.sql", Fx::Definition.new(name: name, version: 1).full_path
48
+ copy_file "triggers/#{name}.sql", Fx::Definition.new(name: name, version: 1, type: "trigger").full_path
49
+ end
50
+ end
42
51
  end
43
- end
52
+ end
@@ -0,0 +1,10 @@
1
+ CREATE
2
+ OR REPLACE FUNCTION exekutor_broadcast_job_enqueued() RETURNS TRIGGER AS $$
3
+ BEGIN
4
+ PERFORM
5
+ pg_notify('exekutor::job_enqueued',
6
+ CONCAT('id:', NEW.id,';q:', NEW.queue,';p:', NEW.priority, ';t:', extract ('epoch' from NEW.scheduled_at)));
7
+ RETURN NULL;
8
+ END;
9
+ $$
10
+ LANGUAGE plpgsql
@@ -0,0 +1,11 @@
1
+ CREATE
2
+ OR REPLACE FUNCTION exekutor_requeue_orphaned_jobs() RETURNS TRIGGER AS $$
3
+ BEGIN
4
+ UPDATE exekutor_jobs
5
+ SET status = 'p'
6
+ WHERE worker_id = OLD.id
7
+ AND status = 'e';
8
+ RETURN OLD;
9
+ END;
10
+ $$
11
+ LANGUAGE plpgsql
@@ -7,20 +7,20 @@ class CreateExekutorSchema < ActiveRecord::Migration[<%= migration_version %>]
7
7
 
8
8
  t.jsonb :info, null: false
9
9
 
10
- t.datetime :created_at, null: false, default: -> { 'now()' }
11
- t.datetime :last_heartbeat_at, null: false, default: -> { 'now()' }
10
+ t.datetime :started_at, null: false, default: -> { "now()" }
11
+ t.datetime :last_heartbeat_at, null: false, default: -> { "now()" }
12
12
 
13
- t.column :status, :char, null: false, default: 'i'
13
+ t.column :status, :char, null: false, default: "i"
14
14
 
15
15
  t.index [:hostname, :pid], unique: true
16
16
  end
17
17
 
18
18
  create_table :exekutor_jobs, id: :uuid do |t|
19
19
  # Worker options
20
- t.string :queue, null: false, default: 'default', limit: 200, index: true
21
- t.integer :priority, null: false, default: 16383, limit: 2
22
- t.datetime :enqueued_at, null: false, default: -> { 'now()' }
23
- t.datetime :scheduled_at, null: false, default: -> { 'now()' }
20
+ t.string :queue, null: false, default: "default", limit: 200, index: true
21
+ t.integer :priority, null: false, default: 16_383, limit: 2
22
+ t.datetime :enqueued_at, null: false, default: -> { "now()" }
23
+ t.datetime :scheduled_at, null: false, default: -> { "now()" }
24
24
 
25
25
  # Job options
26
26
  t.uuid :active_job_id, null: false, index: true
@@ -28,53 +28,54 @@ class CreateExekutorSchema < ActiveRecord::Migration[<%= migration_version %>]
28
28
  t.jsonb :options
29
29
 
30
30
  # Execution options
31
- t.column :status, :char, index: true, null: false, default: 'p'
31
+ t.column :status, :char, index: true, null: false, default: "p"
32
32
  t.float :runtime
33
33
  t.references :worker, type: :uuid, foreign_key: { to_table: :exekutor_workers, on_delete: :nullify }
34
34
 
35
- t.index [:priority, :scheduled_at, :enqueued_at], where: %Q{"status"='p'}, name: :index_exekutor_jobs_on_dequeue_order
35
+ t.index [:priority, :scheduled_at, :enqueued_at], where: %q("status"='p'),
36
+ name: :index_exekutor_jobs_on_dequeue_order
36
37
  end
37
38
 
38
39
  create_table :exekutor_job_errors, id: :uuid do |t|
39
40
  t.references :job, type: :uuid, null: false, foreign_key: { to_table: :exekutor_jobs, on_delete: :cascade }
40
- t.datetime :created_at, null: false, default: -> { 'now()' }
41
+ t.datetime :created_at, null: false, default: -> { "now()" }
41
42
  t.jsonb :error, null: false
42
43
  end
43
44
  <% if defined? Fx %>
44
- create_function :job_notifier
45
- create_trigger :notify_workers
45
+ create_function :exekutor_broadcast_job_enqueued
46
+ create_trigger :exekutor_broadcast_job_enqueued, on: :exekutor_jobs
46
47
 
47
- create_function :requeue_orphaned_jobs
48
- create_trigger :requeue_orphaned_jobs
48
+ create_function :exekutor_requeue_orphaned_jobs
49
+ create_trigger :exekutor_requeue_orphaned_jobs, on: :exekutor_workers
49
50
  <% else %>
50
51
  reversible do |direction|
51
52
  direction.up do
52
53
  execute <<~SQL
53
- <%= function_sql "job_notifier" %>
54
+ <%= function_sql "exekutor_broadcast_job_enqueued" %>
54
55
  SQL
55
56
  execute <<~SQL
56
- <%= trigger_sql "notify_workers" %>
57
+ <%= trigger_sql "exekutor_broadcast_job_enqueued" %>
57
58
  SQL
58
59
 
59
60
  execute <<~SQL
60
- <%= function_sql "requeue_orphaned_jobs" %>
61
+ <%= function_sql "exekutor_requeue_orphaned_jobs" %>
61
62
  SQL
62
63
  execute <<~SQL
63
- <%= trigger_sql "requeue_orphaned_jobs" %>
64
+ <%= trigger_sql "exekutor_requeue_orphaned_jobs" %>
64
65
  SQL
65
66
  end
66
67
  direction.down do
67
68
  execute <<~SQL
68
- DROP TRIGGER requeue_orphaned_jobs ON exekutor_workers
69
+ DROP TRIGGER exekutor_requeue_orphaned_jobs ON exekutor_workers
69
70
  SQL
70
71
  execute <<~SQL
71
- DROP FUNCTION requeue_orphaned_jobs
72
+ DROP FUNCTION exekutor_requeue_orphaned_jobs
72
73
  SQL
73
74
  execute <<~SQL
74
- DROP TRIGGER notify_exekutor_workers ON exekutor_jobs
75
+ DROP TRIGGER exekutor_broadcast_job_enqueued ON exekutor_jobs
75
76
  SQL
76
77
  execute <<~SQL
77
- DROP FUNCTION exekutor_job_notifier
78
+ DROP FUNCTION exekutor_broadcast_job_enqueued
78
79
  SQL
79
80
  end
80
81
  end
@@ -0,0 +1,7 @@
1
+ CREATE TRIGGER exekutor_broadcast_job_enqueued
2
+ AFTER INSERT OR
3
+ UPDATE OF queue, scheduled_at, status
4
+ ON exekutor_jobs
5
+ FOR EACH ROW
6
+ WHEN (NEW.status = 'p')
7
+ EXECUTE FUNCTION exekutor_broadcast_job_enqueued()
@@ -0,0 +1,5 @@
1
+ CREATE TRIGGER exekutor_requeue_orphaned_jobs
2
+ BEFORE DELETE
3
+ ON exekutor_workers
4
+ FOR EACH ROW
5
+ EXECUTE FUNCTION exekutor_requeue_orphaned_jobs()
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: exekutor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Roy
@@ -34,7 +34,7 @@ cert_chain:
34
34
  LMMHpsz0vpxVqcs8USL9494hQUWRVlYd1F2PJeWtdKi0bU8dCduphJd8cTvCtS2l
35
35
  CAY756btGBLeeWMBZ/DRMj1Cz3ifI9DV+KHqXg==
36
36
  -----END CERTIFICATE-----
37
- date: 2023-03-23 00:00:00.000000000 Z
37
+ date: 2023-12-19 00:00:00.000000000 Z
38
38
  dependencies:
39
39
  - !ruby/object:Gem::Dependency
40
40
  name: activejob
@@ -152,20 +152,6 @@ dependencies:
152
152
  - - "~>"
153
153
  - !ruby/object:Gem::Version
154
154
  version: '3.0'
155
- - !ruby/object:Gem::Dependency
156
- name: brakeman
157
- requirement: !ruby/object:Gem::Requirement
158
- requirements:
159
- - - "~>"
160
- - !ruby/object:Gem::Version
161
- version: '5.4'
162
- type: :development
163
- prerelease: false
164
- version_requirements: !ruby/object:Gem::Requirement
165
- requirements:
166
- - - "~>"
167
- - !ruby/object:Gem::Version
168
- version: '5.4'
169
155
  - !ruby/object:Gem::Dependency
170
156
  name: combustion
171
157
  requirement: !ruby/object:Gem::Requirement
@@ -264,6 +250,48 @@ dependencies:
264
250
  - - "~>"
265
251
  - !ruby/object:Gem::Version
266
252
  version: '1.21'
253
+ - !ruby/object:Gem::Dependency
254
+ name: rubocop-minitest
255
+ requirement: !ruby/object:Gem::Requirement
256
+ requirements:
257
+ - - "~>"
258
+ - !ruby/object:Gem::Version
259
+ version: '0.29'
260
+ type: :development
261
+ prerelease: false
262
+ version_requirements: !ruby/object:Gem::Requirement
263
+ requirements:
264
+ - - "~>"
265
+ - !ruby/object:Gem::Version
266
+ version: '0.29'
267
+ - !ruby/object:Gem::Dependency
268
+ name: rubocop-performance
269
+ requirement: !ruby/object:Gem::Requirement
270
+ requirements:
271
+ - - "~>"
272
+ - !ruby/object:Gem::Version
273
+ version: '1.16'
274
+ type: :development
275
+ prerelease: false
276
+ version_requirements: !ruby/object:Gem::Requirement
277
+ requirements:
278
+ - - "~>"
279
+ - !ruby/object:Gem::Version
280
+ version: '1.16'
281
+ - !ruby/object:Gem::Dependency
282
+ name: rubocop-rails
283
+ requirement: !ruby/object:Gem::Requirement
284
+ requirements:
285
+ - - "~>"
286
+ - !ruby/object:Gem::Version
287
+ version: '2.18'
288
+ type: :development
289
+ prerelease: false
290
+ version_requirements: !ruby/object:Gem::Requirement
291
+ requirements:
292
+ - - "~>"
293
+ - !ruby/object:Gem::Version
294
+ version: '2.18'
267
295
  - !ruby/object:Gem::Dependency
268
296
  name: simplecov
269
297
  requirement: !ruby/object:Gem::Requirement
@@ -292,6 +320,20 @@ dependencies:
292
320
  - - "~>"
293
321
  - !ruby/object:Gem::Version
294
322
  version: '0.9'
323
+ - !ruby/object:Gem::Dependency
324
+ name: webrick
325
+ requirement: !ruby/object:Gem::Requirement
326
+ requirements:
327
+ - - "~>"
328
+ - !ruby/object:Gem::Version
329
+ version: '1.6'
330
+ type: :development
331
+ prerelease: false
332
+ version_requirements: !ruby/object:Gem::Requirement
333
+ requirements:
334
+ - - "~>"
335
+ - !ruby/object:Gem::Version
336
+ version: '1.6'
295
337
  - !ruby/object:Gem::Dependency
296
338
  name: yard
297
339
  requirement: !ruby/object:Gem::Requirement
@@ -320,8 +362,9 @@ dependencies:
320
362
  - - "~>"
321
363
  - !ruby/object:Gem::Version
322
364
  version: '0.0'
323
- description: "PostgreSQL backed active job adapter which uses `LISTEN/NOTIFY` to listen
324
- for jobs and `FOR UPDATE SKIP LOCKED` to \nreserve jobs.\n"
365
+ description: |
366
+ PostgreSQL backed active job adapter which uses `LISTEN/NOTIFY` to listen for jobs and `FOR UPDATE SKIP LOCKED` to
367
+ reserve jobs.
325
368
  email:
326
369
  - roy@devdicated.com
327
370
  executables:
@@ -367,12 +410,12 @@ files:
367
410
  - lib/exekutor/worker.rb
368
411
  - lib/generators/exekutor/configuration_generator.rb
369
412
  - lib/generators/exekutor/install_generator.rb
370
- - lib/generators/exekutor/templates/install/functions/job_notifier.sql
371
- - lib/generators/exekutor/templates/install/functions/requeue_orphaned_jobs.sql
413
+ - lib/generators/exekutor/templates/install/functions/exekutor_broadcast_job_enqueued.sql
414
+ - lib/generators/exekutor/templates/install/functions/exekutor_requeue_orphaned_jobs.sql
372
415
  - lib/generators/exekutor/templates/install/initializers/exekutor.rb.erb
373
416
  - lib/generators/exekutor/templates/install/migrations/create_exekutor_schema.rb.erb
374
- - lib/generators/exekutor/templates/install/triggers/notify_workers.sql
375
- - lib/generators/exekutor/templates/install/triggers/requeue_orphaned_jobs.sql
417
+ - lib/generators/exekutor/templates/install/triggers/exekutor_broadcast_job_enqueued.sql
418
+ - lib/generators/exekutor/templates/install/triggers/exekutor_requeue_orphaned_jobs.sql
376
419
  homepage: https://github.com/devdicated/exekutor
377
420
  licenses:
378
421
  - MIT
@@ -381,6 +424,7 @@ metadata:
381
424
  source_code_uri: https://github.com/devdicated/exekutor
382
425
  changelog_uri: https://github.com/devdicated/exekutor/blob/master/CHANGELOG.md
383
426
  allowed_push_host: https://rubygems.org
427
+ rubygems_mfa_required: 'true'
384
428
  post_install_message:
385
429
  rdoc_options: []
386
430
  require_paths:
@@ -396,7 +440,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
396
440
  - !ruby/object:Gem::Version
397
441
  version: '0'
398
442
  requirements: []
399
- rubygems_version: 3.0.9
443
+ rubygems_version: 3.4.13
400
444
  signing_key:
401
445
  specification_version: 4
402
446
  summary: ActiveJob adapter with PostgreSQL backend.
metadata.gz.sig CHANGED
Binary file
@@ -1,7 +0,0 @@
1
- CREATE OR REPLACE FUNCTION exekutor_job_notifier() RETURNS TRIGGER AS $$
2
- BEGIN
3
- PERFORM pg_notify('exekutor::job_enqueued',
4
- CONCAT('id:', NEW.id,';q:', NEW.queue,';t:', extract ('epoch' from NEW.scheduled_at)));
5
- RETURN NULL;
6
- END;
7
- $$ LANGUAGE plpgsql
@@ -1,7 +0,0 @@
1
- CREATE OR REPLACE FUNCTION requeue_orphaned_jobs() RETURNS TRIGGER AS $$ BEGIN
2
- UPDATE exekutor_jobs
3
- SET status = 'p'
4
- WHERE worker_id = OLD.id
5
- AND status = 'e';
6
- RETURN OLD; END;
7
- $$ LANGUAGE plpgsql
@@ -1,6 +0,0 @@
1
- CREATE TRIGGER notify_exekutor_workers
2
- AFTER INSERT OR UPDATE OF queue, scheduled_at, status
3
- ON exekutor_jobs
4
- FOR EACH ROW
5
- WHEN (NEW.status = 'p')
6
- EXECUTE FUNCTION exekutor_job_notifier()
@@ -1,5 +0,0 @@
1
- CREATE TRIGGER requeue_orphaned_jobs
2
- BEFORE DELETE
3
- ON exekutor_workers
4
- FOR EACH ROW
5
- EXECUTE FUNCTION requeue_orphaned_jobs()