inst-jobs 2.0.0 → 3.1.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.
- checksums.yaml +4 -4
- data/db/migrate/20101216224513_create_delayed_jobs.rb +9 -7
- data/db/migrate/20110531144916_cleanup_delayed_jobs_indexes.rb +8 -13
- data/db/migrate/20110610213249_optimize_delayed_jobs.rb +8 -8
- data/db/migrate/20110831210257_add_delayed_jobs_next_in_strand.rb +25 -25
- data/db/migrate/20120510004759_delayed_jobs_delete_trigger_lock_for_update.rb +4 -8
- data/db/migrate/20120531150712_drop_psql_jobs_pop_fn.rb +1 -3
- data/db/migrate/20120607164022_delayed_jobs_use_advisory_locks.rb +11 -15
- data/db/migrate/20120607181141_index_jobs_on_locked_by.rb +1 -1
- data/db/migrate/20120608191051_add_jobs_run_at_index.rb +2 -2
- data/db/migrate/20120927184213_change_delayed_jobs_handler_to_text.rb +1 -1
- data/db/migrate/20140505215510_copy_failed_jobs_original_id.rb +2 -3
- data/db/migrate/20150807133223_add_max_concurrent_to_jobs.rb +9 -13
- data/db/migrate/20151210162949_improve_max_concurrent.rb +4 -8
- data/db/migrate/20161206323555_add_back_default_string_limits_jobs.rb +3 -2
- data/db/migrate/20181217155351_speed_up_max_concurrent_triggers.rb +13 -17
- data/db/migrate/20200330230722_add_id_to_get_delayed_jobs_index.rb +8 -8
- data/db/migrate/20200824222232_speed_up_max_concurrent_delete_trigger.rb +72 -77
- data/db/migrate/20200825011002_add_strand_order_override.rb +93 -97
- data/db/migrate/20210809145804_add_n_strand_index.rb +12 -0
- data/db/migrate/20210812210128_add_singleton_column.rb +200 -0
- data/db/migrate/20210917232626_add_delete_conflicting_singletons_before_unlock_trigger.rb +27 -0
- data/db/migrate/20210928174754_fix_singleton_condition_in_before_insert.rb +56 -0
- data/db/migrate/20210929204903_update_conflicting_singleton_function_to_use_index.rb +27 -0
- data/db/migrate/20211101190934_update_after_delete_trigger_for_singleton_index.rb +137 -0
- data/db/migrate/20211207094200_update_after_delete_trigger_for_singleton_transition_cases.rb +171 -0
- data/db/migrate/20211220112800_fix_singleton_race_condition_insert.rb +59 -0
- data/db/migrate/20211220113000_fix_singleton_race_condition_delete.rb +207 -0
- data/db/migrate/20220127091200_fix_singleton_unique_constraint.rb +31 -0
- data/db/migrate/20220128084800_update_insert_trigger_for_singleton_unique_constraint_change.rb +60 -0
- data/db/migrate/20220128084900_update_delete_trigger_for_singleton_unique_constraint_change.rb +209 -0
- data/db/migrate/20220203063200_remove_old_singleton_index.rb +31 -0
- data/db/migrate/20220328152900_add_failed_jobs_indicies.rb +12 -0
- data/exe/inst_jobs +3 -2
- data/lib/delayed/backend/active_record.rb +226 -168
- data/lib/delayed/backend/base.rb +119 -72
- data/lib/delayed/batch.rb +11 -9
- data/lib/delayed/cli.rb +98 -84
- data/lib/delayed/core_ext/kernel.rb +4 -2
- data/lib/delayed/daemon.rb +70 -74
- data/lib/delayed/job_tracking.rb +26 -25
- data/lib/delayed/lifecycle.rb +28 -23
- data/lib/delayed/log_tailer.rb +17 -17
- data/lib/delayed/logging.rb +13 -16
- data/lib/delayed/message_sending.rb +43 -52
- data/lib/delayed/performable_method.rb +6 -8
- data/lib/delayed/periodic.rb +72 -68
- data/lib/delayed/plugin.rb +2 -4
- data/lib/delayed/pool.rb +205 -168
- data/lib/delayed/rails_reloader_plugin.rb +30 -0
- data/lib/delayed/server/helpers.rb +6 -6
- data/lib/delayed/server.rb +51 -54
- data/lib/delayed/settings.rb +96 -81
- data/lib/delayed/testing.rb +21 -22
- data/lib/delayed/version.rb +1 -1
- data/lib/delayed/work_queue/in_process.rb +21 -17
- data/lib/delayed/work_queue/parent_process/client.rb +55 -53
- data/lib/delayed/work_queue/parent_process/server.rb +245 -207
- data/lib/delayed/work_queue/parent_process.rb +52 -53
- data/lib/delayed/worker/consul_health_check.rb +32 -33
- data/lib/delayed/worker/health_check.rb +35 -27
- data/lib/delayed/worker/null_health_check.rb +3 -1
- data/lib/delayed/worker/process_helper.rb +11 -12
- data/lib/delayed/worker.rb +257 -244
- data/lib/delayed/yaml_extensions.rb +12 -10
- data/lib/delayed_job.rb +37 -37
- data/lib/inst-jobs.rb +1 -1
- data/spec/active_record_job_spec.rb +152 -139
- data/spec/delayed/cli_spec.rb +7 -7
- data/spec/delayed/daemon_spec.rb +10 -9
- data/spec/delayed/message_sending_spec.rb +16 -9
- data/spec/delayed/periodic_spec.rb +14 -21
- data/spec/delayed/server_spec.rb +38 -38
- data/spec/delayed/settings_spec.rb +26 -25
- data/spec/delayed/work_queue/in_process_spec.rb +8 -9
- data/spec/delayed/work_queue/parent_process/client_spec.rb +17 -12
- data/spec/delayed/work_queue/parent_process/server_spec.rb +118 -42
- data/spec/delayed/work_queue/parent_process_spec.rb +21 -23
- data/spec/delayed/worker/consul_health_check_spec.rb +37 -50
- data/spec/delayed/worker/health_check_spec.rb +60 -52
- data/spec/delayed/worker_spec.rb +53 -24
- data/spec/sample_jobs.rb +45 -15
- data/spec/shared/delayed_batch.rb +74 -67
- data/spec/shared/delayed_method.rb +143 -102
- data/spec/shared/performable_method.rb +39 -38
- data/spec/shared/shared_backend.rb +801 -440
- data/spec/shared/testing.rb +14 -14
- data/spec/shared/worker.rb +157 -149
- data/spec/shared_jobs_specs.rb +13 -13
- data/spec/spec_helper.rb +57 -56
- metadata +183 -103
- data/lib/delayed/backend/redis/bulk_update.lua +0 -50
- data/lib/delayed/backend/redis/destroy_job.lua +0 -2
- data/lib/delayed/backend/redis/enqueue.lua +0 -29
- data/lib/delayed/backend/redis/fail_job.lua +0 -5
- data/lib/delayed/backend/redis/find_available.lua +0 -3
- data/lib/delayed/backend/redis/functions.rb +0 -59
- data/lib/delayed/backend/redis/get_and_lock_next_available.lua +0 -17
- data/lib/delayed/backend/redis/includes/jobs_common.lua +0 -203
- data/lib/delayed/backend/redis/job.rb +0 -535
- data/lib/delayed/backend/redis/set_running.lua +0 -5
- data/lib/delayed/backend/redis/tickle_strand.lua +0 -2
- data/spec/gemfiles/42.gemfile +0 -7
- data/spec/gemfiles/50.gemfile +0 -7
- data/spec/gemfiles/51.gemfile +0 -7
- data/spec/gemfiles/52.gemfile +0 -7
- data/spec/gemfiles/60.gemfile +0 -7
- data/spec/redis_job_spec.rb +0 -148
    
        data/lib/delayed/daemon.rb
    CHANGED
    
    | @@ -1,97 +1,93 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            -
            require  | 
| 3 | 
            +
            require "fileutils"
         | 
| 4 4 |  | 
| 5 5 | 
             
            module Delayed
         | 
| 6 | 
            -
            # Daemon controls the parent proces that runs the Pool and monitors the Worker processes.
         | 
| 7 | 
            -
            class Daemon
         | 
| 8 | 
            -
             | 
| 6 | 
            +
              # Daemon controls the parent proces that runs the Pool and monitors the Worker processes.
         | 
| 7 | 
            +
              class Daemon
         | 
| 8 | 
            +
                attr_reader :pid_folder
         | 
| 9 9 |  | 
| 10 | 
            -
             | 
| 11 | 
            -
             | 
| 12 | 
            -
             | 
| 10 | 
            +
                def initialize(pid_folder)
         | 
| 11 | 
            +
                  @pid_folder = pid_folder
         | 
| 12 | 
            +
                end
         | 
| 13 13 |  | 
| 14 | 
            -
             | 
| 15 | 
            -
             | 
| 16 | 
            -
             | 
| 17 | 
            -
             | 
| 18 | 
            -
             | 
| 19 | 
            -
             | 
| 20 | 
            -
             | 
| 14 | 
            +
                def status(print: true, pid: self.pid)
         | 
| 15 | 
            +
                  alive = pid && (Process.kill(0, pid) rescue false) && :running
         | 
| 16 | 
            +
                  alive ||= :draining if pid && Process.kill(0, -pid) rescue false
         | 
| 17 | 
            +
                  if alive
         | 
| 18 | 
            +
                    puts "Delayed jobs #{alive}, pool PID: #{pid}" if print
         | 
| 19 | 
            +
                  elsif print && print != :alive
         | 
| 20 | 
            +
                    puts "No delayed jobs pool running"
         | 
| 21 | 
            +
                  end
         | 
| 22 | 
            +
                  alive
         | 
| 21 23 | 
             
                end
         | 
| 22 | 
            -
                alive
         | 
| 23 | 
            -
              end
         | 
| 24 24 |  | 
| 25 | 
            -
             | 
| 26 | 
            -
             | 
| 27 | 
            -
             | 
| 25 | 
            +
                def daemonize!
         | 
| 26 | 
            +
                  FileUtils.mkdir_p(pid_folder)
         | 
| 27 | 
            +
                  puts "Daemonizing..."
         | 
| 28 28 |  | 
| 29 | 
            -
             | 
| 30 | 
            -
             | 
| 31 | 
            -
             | 
| 32 | 
            -
             | 
| 29 | 
            +
                  exit if fork
         | 
| 30 | 
            +
                  Process.setsid
         | 
| 31 | 
            +
                  exit if fork
         | 
| 32 | 
            +
                  Process.setpgrp
         | 
| 33 33 |  | 
| 34 | 
            -
             | 
| 35 | 
            -
             | 
| 36 | 
            -
             | 
| 37 | 
            -
             | 
| 38 | 
            -
                   | 
| 39 | 
            -
             | 
| 40 | 
            -
             | 
| 41 | 
            -
                lock_file.puts(Process.pid.to_s)
         | 
| 42 | 
            -
                lock_file.flush
         | 
| 34 | 
            +
                  @daemon = true
         | 
| 35 | 
            +
                  lock_file = File.open(pid_file, "wb")
         | 
| 36 | 
            +
                  # someone else is already running; just exit
         | 
| 37 | 
            +
                  exit unless lock_file.flock(File::LOCK_EX | File::LOCK_NB)
         | 
| 38 | 
            +
                  at_exit { lock_file.flock(File::LOCK_UN) }
         | 
| 39 | 
            +
                  lock_file.puts(Process.pid.to_s)
         | 
| 40 | 
            +
                  lock_file.flush
         | 
| 43 41 |  | 
| 44 | 
            -
             | 
| 45 | 
            -
             | 
| 46 | 
            -
             | 
| 47 | 
            -
             | 
| 48 | 
            -
                   | 
| 42 | 
            +
                  # if we blow up so badly that we can't syslog the error, try to send
         | 
| 43 | 
            +
                  # it somewhere useful
         | 
| 44 | 
            +
                  last_ditch_logfile = Settings.last_ditch_logfile || "log/delayed_job.log"
         | 
| 45 | 
            +
                  last_ditch_logfile = Settings.expand_rails_path(last_ditch_logfile) if last_ditch_logfile[0] != "|"
         | 
| 46 | 
            +
                  $stdin.reopen("/dev/null")
         | 
| 47 | 
            +
                  $stdout.reopen(open(last_ditch_logfile, "a")) # rubocop:disable Security/Open
         | 
| 48 | 
            +
                  $stderr.reopen($stdout)
         | 
| 49 | 
            +
                  $stdout.sync = $stderr.sync = true
         | 
| 49 50 | 
             
                end
         | 
| 50 | 
            -
                STDIN.reopen("/dev/null")
         | 
| 51 | 
            -
                STDOUT.reopen(open(last_ditch_logfile, 'a'))
         | 
| 52 | 
            -
                STDERR.reopen(STDOUT)
         | 
| 53 | 
            -
                STDOUT.sync = STDERR.sync = true
         | 
| 54 | 
            -
              end
         | 
| 55 51 |  | 
| 56 | 
            -
             | 
| 57 | 
            -
             | 
| 58 | 
            -
             | 
| 59 | 
            -
             | 
| 60 | 
            -
             | 
| 61 | 
            -
             | 
| 62 | 
            -
             | 
| 63 | 
            -
             | 
| 64 | 
            -
             | 
| 65 | 
            -
             | 
| 52 | 
            +
                # stop the currently running daemon (not this current process, the one in the pid_file)
         | 
| 53 | 
            +
                def stop(kill: false, pid: self.pid)
         | 
| 54 | 
            +
                  alive = status(pid: pid, print: false)
         | 
| 55 | 
            +
                  if alive == :running || (kill && alive == :draining)
         | 
| 56 | 
            +
                    puts "Stopping pool #{pid}..."
         | 
| 57 | 
            +
                    signal = kill ? "TERM" : "QUIT"
         | 
| 58 | 
            +
                    begin
         | 
| 59 | 
            +
                      Process.kill(signal, pid)
         | 
| 60 | 
            +
                    rescue Errno::ESRCH
         | 
| 61 | 
            +
                      # ignore if the pid no longer exists
         | 
| 62 | 
            +
                    end
         | 
| 63 | 
            +
                    wait(kill)
         | 
| 64 | 
            +
                  else
         | 
| 65 | 
            +
                    status
         | 
| 66 66 | 
             
                  end
         | 
| 67 | 
            -
                  wait(kill)
         | 
| 68 | 
            -
                else
         | 
| 69 | 
            -
                  status
         | 
| 70 67 | 
             
                end
         | 
| 71 | 
            -
              end
         | 
| 72 68 |  | 
| 73 | 
            -
             | 
| 74 | 
            -
             | 
| 75 | 
            -
             | 
| 76 | 
            -
             | 
| 77 | 
            -
             | 
| 69 | 
            +
                def wait(kill)
         | 
| 70 | 
            +
                  if kill
         | 
| 71 | 
            +
                    sleep(0.5) while status(pid: pid, print: false)
         | 
| 72 | 
            +
                  else
         | 
| 73 | 
            +
                    sleep(0.5) while status(pid: pid, print: false) == :running
         | 
| 74 | 
            +
                  end
         | 
| 78 75 | 
             
                end
         | 
| 79 | 
            -
              end
         | 
| 80 76 |  | 
| 81 | 
            -
             | 
| 82 | 
            -
             | 
| 83 | 
            -
             | 
| 77 | 
            +
                def pid_file
         | 
| 78 | 
            +
                  File.join(pid_folder, "delayed_jobs_pool.pid")
         | 
| 79 | 
            +
                end
         | 
| 84 80 |  | 
| 85 | 
            -
             | 
| 86 | 
            -
             | 
| 87 | 
            -
             | 
| 88 | 
            -
             | 
| 81 | 
            +
                def pid
         | 
| 82 | 
            +
                  if File.file?(pid_file)
         | 
| 83 | 
            +
                    pid = File.read(pid_file).to_i
         | 
| 84 | 
            +
                    pid = nil unless pid.positive?
         | 
| 85 | 
            +
                  end
         | 
| 86 | 
            +
                  pid
         | 
| 89 87 | 
             
                end
         | 
| 90 | 
            -
                pid
         | 
| 91 | 
            -
              end
         | 
| 92 88 |  | 
| 93 | 
            -
             | 
| 94 | 
            -
             | 
| 89 | 
            +
                def daemonized?
         | 
| 90 | 
            +
                  !!@daemon
         | 
| 91 | 
            +
                end
         | 
| 95 92 | 
             
              end
         | 
| 96 93 | 
             
            end
         | 
| 97 | 
            -
            end
         | 
    
        data/lib/delayed/job_tracking.rb
    CHANGED
    
    | @@ -1,33 +1,34 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 3 | 
             
            module Delayed
         | 
| 4 | 
            -
            # Used when a block of code wants to track what jobs are created,
         | 
| 5 | 
            -
            # for instance in tests.
         | 
| 6 | 
            -
            # Delayed::Job.track_jobs { ...block... } returns a JobTracking object
         | 
| 7 | 
            -
            # Right now this just tracks created jobs, it could be expanded to track a
         | 
| 8 | 
            -
            # lot more about what's going on in Delayed Jobs as it's needed.
         | 
| 9 | 
            -
             | 
| 10 | 
            -
             | 
| 11 | 
            -
             | 
| 12 | 
            -
             | 
| 13 | 
            -
             | 
| 14 | 
            -
             | 
| 15 | 
            -
             | 
| 16 | 
            -
             | 
| 4 | 
            +
              # Used when a block of code wants to track what jobs are created,
         | 
| 5 | 
            +
              # for instance in tests.
         | 
| 6 | 
            +
              # Delayed::Job.track_jobs { ...block... } returns a JobTracking object
         | 
| 7 | 
            +
              # Right now this just tracks created jobs, it could be expanded to track a
         | 
| 8 | 
            +
              # lot more about what's going on in Delayed Jobs as it's needed.
         | 
| 9 | 
            +
              JobTracking = Struct.new(:created) do
         | 
| 10 | 
            +
                def self.track
         | 
| 11 | 
            +
                  @current_tracking = new
         | 
| 12 | 
            +
                  yield
         | 
| 13 | 
            +
                  tracking = @current_tracking
         | 
| 14 | 
            +
                  @current_tracking = nil
         | 
| 15 | 
            +
                  tracking
         | 
| 16 | 
            +
                end
         | 
| 17 17 |  | 
| 18 | 
            -
             | 
| 19 | 
            -
             | 
| 20 | 
            -
             | 
| 18 | 
            +
                def self.job_created(job)
         | 
| 19 | 
            +
                  @current_tracking.try(:job_created, job)
         | 
| 20 | 
            +
                end
         | 
| 21 21 |  | 
| 22 | 
            -
             | 
| 23 | 
            -
             | 
| 24 | 
            -
                @lock.synchronize { self.created << job }
         | 
| 25 | 
            -
              end
         | 
| 22 | 
            +
                def job_created(job)
         | 
| 23 | 
            +
                  return unless job
         | 
| 26 24 |  | 
| 27 | 
            -
             | 
| 28 | 
            -
                 | 
| 29 | 
            -
             | 
| 30 | 
            -
                 | 
| 25 | 
            +
                  @lock.synchronize { created << job }
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                def initialize
         | 
| 29 | 
            +
                  super
         | 
| 30 | 
            +
                  self.created = []
         | 
| 31 | 
            +
                  @lock = Mutex.new
         | 
| 32 | 
            +
                end
         | 
| 31 33 | 
             
              end
         | 
| 32 34 | 
             
            end
         | 
| 33 | 
            -
            end
         | 
    
        data/lib/delayed/lifecycle.rb
    CHANGED
    
    | @@ -1,28 +1,33 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 3 | 
             
            module Delayed
         | 
| 4 | 
            -
              class InvalidCallback <  | 
| 4 | 
            +
              class InvalidCallback < RuntimeError; end
         | 
| 5 5 |  | 
| 6 6 | 
             
              class Lifecycle
         | 
| 7 7 | 
             
                EVENTS = {
         | 
| 8 | 
            -
                  : | 
| 9 | 
            -
                  : | 
| 10 | 
            -
                  : | 
| 11 | 
            -
                  : | 
| 12 | 
            -
                  : | 
| 13 | 
            -
                  : | 
| 14 | 
            -
                  : | 
| 15 | 
            -
                  : | 
| 16 | 
            -
                  : | 
| 17 | 
            -
             | 
| 8 | 
            +
                  create: [:args],
         | 
| 9 | 
            +
                  error: %i[worker job exception],
         | 
| 10 | 
            +
                  exceptional_exit: %i[worker exception],
         | 
| 11 | 
            +
                  execute: [:worker],
         | 
| 12 | 
            +
                  invoke_job: [:job],
         | 
| 13 | 
            +
                  loop: [:worker],
         | 
| 14 | 
            +
                  perform: %i[worker job],
         | 
| 15 | 
            +
                  pop: [:worker],
         | 
| 16 | 
            +
                  retry: %i[worker job exception],
         | 
| 17 | 
            +
                  work_queue_pop: %i[work_queue worker_config],
         | 
| 18 | 
            +
                  check_for_work: [:work_queue]
         | 
| 19 | 
            +
                }.freeze
         | 
| 18 20 |  | 
| 19 21 | 
             
                def initialize
         | 
| 20 22 | 
             
                  reset!
         | 
| 21 23 | 
             
                end
         | 
| 22 24 |  | 
| 23 25 | 
             
                def reset!
         | 
| 24 | 
            -
                  @callbacks = EVENTS.keys. | 
| 25 | 
            -
             | 
| 26 | 
            +
                  @callbacks = EVENTS.keys.each_with_object({}) do |e, hash|
         | 
| 27 | 
            +
                    hash[e] = Callback.new
         | 
| 28 | 
            +
                    hash
         | 
| 29 | 
            +
                  end
         | 
| 30 | 
            +
                  Delayed::Worker.plugins.each(&:reset!)
         | 
| 26 31 | 
             
                end
         | 
| 27 32 |  | 
| 28 33 | 
             
                def before(event, &block)
         | 
| @@ -38,7 +43,7 @@ module Delayed | |
| 38 43 | 
             
                end
         | 
| 39 44 |  | 
| 40 45 | 
             
                def run_callbacks(event, *args, &block)
         | 
| 41 | 
            -
                  missing_callback(event) unless @callbacks. | 
| 46 | 
            +
                  missing_callback(event) unless @callbacks.key?(event)
         | 
| 42 47 |  | 
| 43 48 | 
             
                  unless EVENTS[event].size == args.size
         | 
| 44 49 | 
             
                    raise ArgumentError, "Callback #{event} expects #{EVENTS[event].size} parameter(s): #{EVENTS[event].join(', ')}"
         | 
| @@ -49,15 +54,15 @@ module Delayed | |
| 49 54 |  | 
| 50 55 | 
             
                private
         | 
| 51 56 |  | 
| 52 | 
            -
             | 
| 53 | 
            -
             | 
| 57 | 
            +
                def add(type, event, &block)
         | 
| 58 | 
            +
                  missing_callback(event) unless @callbacks.key?(event)
         | 
| 54 59 |  | 
| 55 | 
            -
             | 
| 56 | 
            -
             | 
| 60 | 
            +
                  @callbacks[event].add(type, &block)
         | 
| 61 | 
            +
                end
         | 
| 57 62 |  | 
| 58 | 
            -
             | 
| 59 | 
            -
             | 
| 60 | 
            -
             | 
| 63 | 
            +
                def missing_callback(event)
         | 
| 64 | 
            +
                  raise InvalidCallback, "Unknown callback event: #{event}"
         | 
| 65 | 
            +
                end
         | 
| 61 66 | 
             
              end
         | 
| 62 67 |  | 
| 63 68 | 
             
              class Callback
         | 
| @@ -66,7 +71,7 @@ module Delayed | |
| 66 71 | 
             
                  @after = []
         | 
| 67 72 |  | 
| 68 73 | 
             
                  # Identity proc. Avoids special cases when there is no existing around chain.
         | 
| 69 | 
            -
                  @around =  | 
| 74 | 
            +
                  @around = ->(*args, &block) { block.call(*args) }
         | 
| 70 75 | 
             
                end
         | 
| 71 76 |  | 
| 72 77 | 
             
                def execute(*args, &block)
         | 
| @@ -84,7 +89,7 @@ module Delayed | |
| 84 89 | 
             
                    @after << callback
         | 
| 85 90 | 
             
                  when :around
         | 
| 86 91 | 
             
                    chain = @around # use a local variable so that the current chain is closed over in the following lambda
         | 
| 87 | 
            -
                    @around =  | 
| 92 | 
            +
                    @around = ->(*a, &block) { chain.call(*a) { |*b| callback.call(*b, &block) } }
         | 
| 88 93 | 
             
                  else
         | 
| 89 94 | 
             
                    raise InvalidCallback, "Invalid callback type: #{type}"
         | 
| 90 95 | 
             
                  end
         | 
    
        data/lib/delayed/log_tailer.rb
    CHANGED
    
    | @@ -1,24 +1,24 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 3 | 
             
            module Delayed
         | 
| 4 | 
            -
            class LogTailer
         | 
| 5 | 
            -
             | 
| 6 | 
            -
             | 
| 7 | 
            -
             | 
| 8 | 
            -
             | 
| 9 | 
            -
             | 
| 10 | 
            -
             | 
| 11 | 
            -
             | 
| 12 | 
            -
             | 
| 13 | 
            -
             | 
| 14 | 
            -
             | 
| 15 | 
            -
             | 
| 16 | 
            -
             | 
| 17 | 
            -
             | 
| 18 | 
            -
             | 
| 19 | 
            -
             | 
| 4 | 
            +
              class LogTailer
         | 
| 5 | 
            +
                def run
         | 
| 6 | 
            +
                  if Rails.logger.respond_to?(:log_path)
         | 
| 7 | 
            +
                    log_path = Rails.logger.log_path
         | 
| 8 | 
            +
                  elsif Rails.logger.instance_variable_get("@logdev").try(:instance_variable_get, "@dev").try(:path)
         | 
| 9 | 
            +
                    log_path = Rails.logger.instance_variable_get("@logdev").instance_variable_get("@dev").path
         | 
| 10 | 
            +
                  else
         | 
| 11 | 
            +
                    return
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
                  Rails.logger.auto_flushing = true if Rails.logger.respond_to?(:auto_flushing=)
         | 
| 14 | 
            +
                  Thread.new do
         | 
| 15 | 
            +
                    f = File.open(log_path, "r")
         | 
| 16 | 
            +
                    f.seek(0, IO::SEEK_END)
         | 
| 17 | 
            +
                    loop do
         | 
| 18 | 
            +
                      content = f.read
         | 
| 19 | 
            +
                      content.present? ? $stdout.print(content) : sleep(0.5)
         | 
| 20 | 
            +
                    end
         | 
| 20 21 | 
             
                  end
         | 
| 21 22 | 
             
                end
         | 
| 22 23 | 
             
              end
         | 
| 23 24 | 
             
            end
         | 
| 24 | 
            -
            end
         | 
    
        data/lib/delayed/logging.rb
    CHANGED
    
    | @@ -1,30 +1,27 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            -
            require  | 
| 3 | 
            +
            require "date"
         | 
| 4 4 |  | 
| 5 5 | 
             
            module Delayed
         | 
| 6 6 | 
             
              module Logging
         | 
| 7 | 
            -
                TIMESTAMP_FORMAT =  | 
| 7 | 
            +
                TIMESTAMP_FORMAT = "%Y-%m-%dT%H:%M:%S.%6N"
         | 
| 8 8 | 
             
                private_constant :TIMESTAMP_FORMAT
         | 
| 9 9 |  | 
| 10 | 
            -
                FORMAT =  | 
| 10 | 
            +
                FORMAT = "%s - %s"
         | 
| 11 11 | 
             
                private_constant :FORMAT
         | 
| 12 12 |  | 
| 13 | 
            -
             | 
| 14 13 | 
             
                def self.logger
         | 
| 15 14 | 
             
                  return @logger if @logger
         | 
| 16 | 
            -
             | 
| 17 | 
            -
             | 
| 18 | 
            -
             | 
| 19 | 
            -
             | 
| 20 | 
            -
             | 
| 21 | 
            -
             | 
| 22 | 
            -
             | 
| 23 | 
            -
             | 
| 24 | 
            -
             | 
| 25 | 
            -
             | 
| 26 | 
            -
                    end
         | 
| 27 | 
            -
                  end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  @logger = if defined?(Rails.logger) && Rails.logger
         | 
| 17 | 
            +
                              Rails.logger
         | 
| 18 | 
            +
                            else
         | 
| 19 | 
            +
                              ::Logger.new($stdout).tap do |logger|
         | 
| 20 | 
            +
                                logger.formatter = lambda { |_, time, _, msg|
         | 
| 21 | 
            +
                                  format(FORMAT, time.strftime(TIMESTAMP_FORMAT), msg)
         | 
| 22 | 
            +
                                }
         | 
| 23 | 
            +
                              end
         | 
| 24 | 
            +
                            end
         | 
| 28 25 | 
             
                end
         | 
| 29 26 |  | 
| 30 27 | 
             
                def logger
         | 
| @@ -1,8 +1,6 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            -
            if ::Rails.env.test? || ::Rails.env.development?
         | 
| 4 | 
            -
              require 'debug_inspector'
         | 
| 5 | 
            -
            end
         | 
| 3 | 
            +
            require "debug_inspector" if ::Rails.env.test? || ::Rails.env.development?
         | 
| 6 4 |  | 
| 7 5 | 
             
            module Delayed
         | 
| 8 6 | 
             
              module MessageSending
         | 
| @@ -14,12 +12,12 @@ module Delayed | |
| 14 12 | 
             
                    @sender = sender
         | 
| 15 13 | 
             
                  end
         | 
| 16 14 |  | 
| 17 | 
            -
                  def method_missing(method, *args, **kwargs)
         | 
| 15 | 
            +
                  def method_missing(method, *args, **kwargs) # rubocop:disable Style/MissingRespondToMissing
         | 
| 18 16 | 
             
                    # method doesn't exist? must be method_missing; assume private access
         | 
| 19 17 | 
             
                    @sender = nil if !@sender.nil? &&
         | 
| 20 | 
            -
             | 
| 21 | 
            -
             | 
| 22 | 
            -
             | 
| 18 | 
            +
                                     @object.methods.exclude?(method) &&
         | 
| 19 | 
            +
                                     @object.protected_methods.exclude?(method) &&
         | 
| 20 | 
            +
                                     @object.private_methods.exclude?(method)
         | 
| 23 21 |  | 
| 24 22 | 
             
                    sender_is_object = @sender == @object
         | 
| 25 23 | 
             
                    sender_is_class = @sender.is_a?(@object.class)
         | 
| @@ -33,51 +31,47 @@ module Delayed | |
| 33 31 | 
             
                    end
         | 
| 34 32 |  | 
| 35 33 | 
             
                    if @synchronous
         | 
| 36 | 
            -
                      if @sender.nil? || sender_is_object || sender_is_class && @object.protected_methods.include?(method)
         | 
| 37 | 
            -
                        if kwargs.empty?
         | 
| 38 | 
            -
             | 
| 39 | 
            -
                         | 
| 40 | 
            -
                          return @object.send(method, *args, **kwargs)
         | 
| 41 | 
            -
                        end
         | 
| 42 | 
            -
                      end
         | 
| 43 | 
            -
                      
         | 
| 44 | 
            -
                      if kwargs.empty?
         | 
| 45 | 
            -
                        return @object.public_send(method, *args)
         | 
| 46 | 
            -
                      else
         | 
| 47 | 
            -
                        return @object.public_send(method, *args, **kwargs)
         | 
| 34 | 
            +
                      if @sender.nil? || sender_is_object || (sender_is_class && @object.protected_methods.include?(method))
         | 
| 35 | 
            +
                        return @object.send(method, *args) if kwargs.empty?
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                        return @object.send(method, *args, **kwargs)
         | 
| 48 38 | 
             
                      end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                      return @object.public_send(method, *args) if kwargs.empty?
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                      return @object.public_send(method, *args, **kwargs)
         | 
| 49 43 | 
             
                    end
         | 
| 50 44 |  | 
| 51 45 | 
             
                    ignore_transaction = @enqueue_args.delete(:ignore_transaction)
         | 
| 52 46 | 
             
                    on_failure = @enqueue_args.delete(:on_failure)
         | 
| 53 47 | 
             
                    on_permanent_failure = @enqueue_args.delete(:on_permanent_failure)
         | 
| 54 | 
            -
                     | 
| 48 | 
            +
                    unless ignore_transaction
         | 
| 55 49 | 
             
                      # delay queuing up the job in another database until the results of the current
         | 
| 56 50 | 
             
                      # transaction are visible
         | 
| 57 51 | 
             
                      connection = @object.class.connection if @object.class.respond_to?(:connection)
         | 
| 58 52 | 
             
                      connection ||= @object.connection if @object.respond_to?(:connection)
         | 
| 59 53 | 
             
                      connection ||= ::ActiveRecord::Base.connection
         | 
| 60 54 |  | 
| 61 | 
            -
                      if  | 
| 55 | 
            +
                      if ::Delayed::Job != ::Delayed::Backend::ActiveRecord::Job || connection != ::Delayed::Job.connection
         | 
| 62 56 | 
             
                        connection.after_transaction_commit do
         | 
| 63 57 | 
             
                          ::Delayed::Job.enqueue(::Delayed::PerformableMethod.new(@object, method,
         | 
| 64 | 
            -
             | 
| 65 | 
            -
             | 
| 66 | 
            -
             | 
| 67 | 
            -
             | 
| 68 | 
            -
             | 
| 58 | 
            +
                                                                                  args: args, kwargs: kwargs,
         | 
| 59 | 
            +
                                                                                  on_failure: on_failure,
         | 
| 60 | 
            +
                                                                                  on_permanent_failure: on_permanent_failure,
         | 
| 61 | 
            +
                                                                                  sender: @sender),
         | 
| 62 | 
            +
                                                 **@enqueue_args)
         | 
| 69 63 | 
             
                        end
         | 
| 70 64 | 
             
                        return nil
         | 
| 71 65 | 
             
                      end
         | 
| 72 66 | 
             
                    end
         | 
| 73 67 |  | 
| 74 68 | 
             
                    result = ::Delayed::Job.enqueue(::Delayed::PerformableMethod.new(@object, method,
         | 
| 75 | 
            -
             | 
| 76 | 
            -
             | 
| 77 | 
            -
             | 
| 78 | 
            -
             | 
| 79 | 
            -
             | 
| 80 | 
            -
             | 
| 69 | 
            +
                                                                                     args: args,
         | 
| 70 | 
            +
                                                                                     kwargs: kwargs,
         | 
| 71 | 
            +
                                                                                     on_failure: on_failure,
         | 
| 72 | 
            +
                                                                                     on_permanent_failure: on_permanent_failure,
         | 
| 73 | 
            +
                                                                                     sender: @sender),
         | 
| 74 | 
            +
                                                    **@enqueue_args)
         | 
| 81 75 | 
             
                    result = nil unless ignore_transaction
         | 
| 82 76 | 
             
                    result
         | 
| 83 77 | 
             
                  end
         | 
| @@ -85,10 +79,8 @@ module Delayed | |
| 85 79 |  | 
| 86 80 | 
             
                def delay(sender: nil, **enqueue_args)
         | 
| 87 81 | 
             
                  # support procs/methods as enqueue arguments
         | 
| 88 | 
            -
                  enqueue_args.each do |k,v|
         | 
| 89 | 
            -
                    if v.respond_to?(:call)
         | 
| 90 | 
            -
                      enqueue_args[k] = v.call(self)
         | 
| 91 | 
            -
                    end
         | 
| 82 | 
            +
                  enqueue_args.each do |k, v|
         | 
| 83 | 
            +
                    enqueue_args[k] = v.call(self) if v.respond_to?(:call)
         | 
| 92 84 | 
             
                  end
         | 
| 93 85 |  | 
| 94 86 | 
             
                  sender ||= __calculate_sender_for_delay
         | 
| @@ -103,33 +95,32 @@ module Delayed | |
| 103 95 | 
             
                end
         | 
| 104 96 |  | 
| 105 97 | 
             
                module ClassMethods
         | 
| 106 | 
            -
                  KWARG_ARG_TYPES = %i | 
| 98 | 
            +
                  KWARG_ARG_TYPES = %i[key keyreq keyrest].freeze
         | 
| 107 99 | 
             
                  private_constant :KWARG_ARG_TYPES
         | 
| 108 100 |  | 
| 109 101 | 
             
                  def handle_asynchronously(method_name, **enqueue_args)
         | 
| 110 | 
            -
                     | 
| 111 | 
            -
             | 
| 112 | 
            -
             | 
| 113 | 
            -
             | 
| 114 | 
            -
             | 
| 115 | 
            -
             | 
| 116 | 
            -
             | 
| 117 | 
            -
             | 
| 118 | 
            -
                     | 
| 119 | 
            -
             | 
| 120 | 
            -
                    if has_kwargs? method_name
         | 
| 102 | 
            +
                    visibility = if public_method_defined?(method_name)
         | 
| 103 | 
            +
                                   :public
         | 
| 104 | 
            +
                                 elsif private_method_defined?(method_name)
         | 
| 105 | 
            +
                                   :private
         | 
| 106 | 
            +
                                 else
         | 
| 107 | 
            +
                                   :protected
         | 
| 108 | 
            +
                                 end
         | 
| 109 | 
            +
             | 
| 110 | 
            +
                    if kwargs? method_name
         | 
| 121 111 | 
             
                      generated_delayed_methods.class_eval do
         | 
| 122 | 
            -
                        define_method(method_name,  | 
| 112 | 
            +
                        define_method(method_name, lambda do |*args, synchronous: false, **kwargs|
         | 
| 123 113 | 
             
                          if synchronous
         | 
| 124 114 | 
             
                            super(*args, **kwargs)
         | 
| 125 115 | 
             
                          else
         | 
| 126 | 
            -
                            delay(sender: __calculate_sender_for_delay, **enqueue_args) | 
| 116 | 
            +
                            delay(sender: __calculate_sender_for_delay, **enqueue_args)
         | 
| 117 | 
            +
                              .method_missing(method_name, *args, synchronous: true, **kwargs)
         | 
| 127 118 | 
             
                          end
         | 
| 128 119 | 
             
                        end)
         | 
| 129 120 | 
             
                      end
         | 
| 130 121 | 
             
                    else
         | 
| 131 122 | 
             
                      generated_delayed_methods.class_eval do
         | 
| 132 | 
            -
                        define_method(method_name,  | 
| 123 | 
            +
                        define_method(method_name, lambda do |*args, synchronous: false|
         | 
| 133 124 | 
             
                          if synchronous
         | 
| 134 125 | 
             
                            super(*args)
         | 
| 135 126 | 
             
                          else
         | 
| @@ -150,7 +141,7 @@ module Delayed | |
| 150 141 | 
             
                    end
         | 
| 151 142 | 
             
                  end
         | 
| 152 143 |  | 
| 153 | 
            -
                  def  | 
| 144 | 
            +
                  def kwargs?(method_name)
         | 
| 154 145 | 
             
                    original_arg_types = instance_method(method_name).parameters.map(&:first)
         | 
| 155 146 | 
             
                    original_arg_types.any? { |arg_type| KWARG_ARG_TYPES.include?(arg_type) }
         | 
| 156 147 | 
             
                  end
         | 
| @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 3 | 
             
            module Delayed
         | 
| 4 | 
            -
               | 
| 4 | 
            +
              PerformableMethod = Struct.new(:object, :method, :args, :kwargs, :fail_cb, :permanent_fail_cb, :sender) do # rubocop:disable Lint/StructNewOverride
         | 
| 5 5 | 
             
                def initialize(object, method, args: [], kwargs: {}, on_failure: nil, on_permanent_failure: nil, sender: nil)
         | 
| 6 6 | 
             
                  raise NoMethodError, "undefined method `#{method}' for #{object.inspect}" unless object.respond_to?(method, true)
         | 
| 7 7 |  | 
| @@ -35,18 +35,16 @@ module Delayed | |
| 35 35 | 
             
                  sender_is_object = sender == object
         | 
| 36 36 | 
             
                  sender_is_class = sender.is_a?(object.class)
         | 
| 37 37 |  | 
| 38 | 
            -
                  if sender.nil? || sender_is_object || sender_is_class && object.protected_methods.include?(method)
         | 
| 38 | 
            +
                  if sender.nil? || sender_is_object || (sender_is_class && object.protected_methods.include?(method))
         | 
| 39 39 | 
             
                    if kwargs.empty?
         | 
| 40 40 | 
             
                      object.send(method, *args)
         | 
| 41 41 | 
             
                    else
         | 
| 42 42 | 
             
                      object.send(method, *args, **kwargs)
         | 
| 43 43 | 
             
                    end
         | 
| 44 | 
            +
                  elsif kwargs.empty?
         | 
| 45 | 
            +
                    object.public_send(method, *args)
         | 
| 44 46 | 
             
                  else
         | 
| 45 | 
            -
                     | 
| 46 | 
            -
                      object.public_send(method, *args)
         | 
| 47 | 
            -
                    else
         | 
| 48 | 
            -
                      object.public_send(method, *args, **kwargs)
         | 
| 49 | 
            -
                    end
         | 
| 47 | 
            +
                    object.public_send(method, *args, **kwargs)
         | 
| 50 48 | 
             
                  end
         | 
| 51 49 | 
             
                end
         | 
| 52 50 |  | 
| @@ -74,7 +72,7 @@ module Delayed | |
| 74 72 | 
             
                def full_name
         | 
| 75 73 | 
             
                  obj_name = object.is_a?(ActiveRecord::Base) ? "#{object.class}.find(#{object.id}).#{method}" : display_name
         | 
| 76 74 | 
             
                  kgs = kwargs || {}
         | 
| 77 | 
            -
                  kwargs_str = kgs.map { |(k, v)| ", #{k}: #{deep_de_ar_ize(v)}"}.join | 
| 75 | 
            +
                  kwargs_str = kgs.map { |(k, v)| ", #{k}: #{deep_de_ar_ize(v)}" }.join
         | 
| 78 76 | 
             
                  "#{obj_name}(#{args.map { |a| deep_de_ar_ize(a) }.join(', ')}#{kwargs_str})"
         | 
| 79 77 | 
             
                end
         | 
| 80 78 | 
             
              end
         |