exekutor 0.1.0 → 0.1.1
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
 - checksums.yaml.gz.sig +0 -0
 - data/exe/exekutor +2 -2
 - data/lib/active_job/queue_adapters/exekutor_adapter.rb +2 -1
 - data/lib/exekutor/asynchronous.rb +143 -75
 - data/lib/exekutor/cleanup.rb +27 -28
 - data/lib/exekutor/configuration.rb +48 -25
 - data/lib/exekutor/hook.rb +15 -11
 - data/lib/exekutor/info/worker.rb +3 -3
 - data/lib/exekutor/internal/base_record.rb +2 -1
 - data/lib/exekutor/internal/callbacks.rb +55 -35
 - data/lib/exekutor/internal/cli/app.rb +31 -23
 - data/lib/exekutor/internal/cli/application_loader.rb +17 -6
 - data/lib/exekutor/internal/cli/cleanup.rb +54 -40
 - data/lib/exekutor/internal/cli/daemon.rb +9 -11
 - data/lib/exekutor/internal/cli/default_option_value.rb +3 -1
 - data/lib/exekutor/internal/cli/info.rb +117 -84
 - data/lib/exekutor/internal/cli/manager.rb +190 -123
 - data/lib/exekutor/internal/configuration_builder.rb +40 -27
 - data/lib/exekutor/internal/database_connection.rb +6 -0
 - data/lib/exekutor/internal/executable.rb +12 -7
 - data/lib/exekutor/internal/executor.rb +50 -21
 - data/lib/exekutor/internal/hooks.rb +11 -8
 - data/lib/exekutor/internal/listener.rb +66 -39
 - data/lib/exekutor/internal/logger.rb +28 -10
 - data/lib/exekutor/internal/provider.rb +93 -74
 - data/lib/exekutor/internal/reserver.rb +27 -12
 - data/lib/exekutor/internal/status_server.rb +81 -49
 - data/lib/exekutor/job.rb +1 -1
 - data/lib/exekutor/job_error.rb +1 -1
 - data/lib/exekutor/job_options.rb +22 -13
 - data/lib/exekutor/plugins/appsignal.rb +7 -5
 - data/lib/exekutor/plugins.rb +8 -4
 - data/lib/exekutor/queue.rb +40 -22
 - data/lib/exekutor/version.rb +1 -1
 - data/lib/exekutor/worker.rb +88 -47
 - data/lib/exekutor.rb +2 -2
 - data/lib/generators/exekutor/configuration_generator.rb +9 -5
 - data/lib/generators/exekutor/install_generator.rb +26 -15
 - data/lib/generators/exekutor/templates/install/migrations/create_exekutor_schema.rb.erb +11 -10
 - data.tar.gz.sig +0 -0
 - metadata +63 -19
 - metadata.gz.sig +0 -0
 
| 
         @@ -1,3 +1,5 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
       1 
3 
     | 
    
         
             
            raise Exekutor::Plugins::LoadError, "Appsignal not found, is the gem loaded?" unless defined? Appsignal
         
     | 
| 
       2 
4 
     | 
    
         | 
| 
       3 
5 
     | 
    
         
             
            module Exekutor
         
     | 
| 
         @@ -21,14 +23,14 @@ module Exekutor 
     | 
|
| 
       21 
23 
     | 
    
         | 
| 
       22 
24 
     | 
    
         
             
                    ::Appsignal.monitor_transaction(
         
     | 
| 
       23 
25 
     | 
    
         
             
                      "perform_job.exekutor",
         
     | 
| 
       24 
     | 
    
         
            -
                      class: payload[ 
     | 
| 
      
 26 
     | 
    
         
            +
                      class: payload["job_class"],
         
     | 
| 
       25 
27 
     | 
    
         
             
                      method: "perform",
         
     | 
| 
       26 
28 
     | 
    
         
             
                      params: params,
         
     | 
| 
       27 
29 
     | 
    
         
             
                      metadata: {
         
     | 
| 
       28 
     | 
    
         
            -
                        id: payload[ 
     | 
| 
       29 
     | 
    
         
            -
                        queue: payload[ 
     | 
| 
       30 
     | 
    
         
            -
                        priority: payload.fetch( 
     | 
| 
       31 
     | 
    
         
            -
                        attempts: payload.fetch( 
     | 
| 
      
 30 
     | 
    
         
            +
                        id: payload["job_id"],
         
     | 
| 
      
 31 
     | 
    
         
            +
                        queue: payload["queue_name"],
         
     | 
| 
      
 32 
     | 
    
         
            +
                        priority: payload.fetch("priority", Exekutor.config.default_queue_priority),
         
     | 
| 
      
 33 
     | 
    
         
            +
                        attempts: payload.fetch("attempts", 0)
         
     | 
| 
       32 
34 
     | 
    
         
             
                      },
         
     | 
| 
       33 
35 
     | 
    
         
             
                      queue_start: job[:scheduled_at]
         
     | 
| 
       34 
36 
     | 
    
         
             
                    ) do
         
     | 
    
        data/lib/exekutor/plugins.rb
    CHANGED
    
    | 
         @@ -1,13 +1,17 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            # The Exekutor namespace
         
     | 
| 
       1 
4 
     | 
    
         
             
            module Exekutor
         
     | 
| 
       2 
5 
     | 
    
         
             
              module Plugins
         
     | 
| 
      
 6 
     | 
    
         
            +
                # Raised when a plugin cannot be loaded
         
     | 
| 
       3 
7 
     | 
    
         
             
                class LoadError < ::LoadError; end
         
     | 
| 
       4 
8 
     | 
    
         
             
              end
         
     | 
| 
       5 
9 
     | 
    
         | 
| 
       6 
10 
     | 
    
         
             
              def self.load_plugin(name)
         
     | 
| 
       7 
     | 
    
         
            -
                 
     | 
| 
       8 
     | 
    
         
            -
                  require_relative "plugins/#{name}"
         
     | 
| 
       9 
     | 
    
         
            -
                else
         
     | 
| 
      
 11 
     | 
    
         
            +
                unless File.exist? File.join(__dir__, "plugins/#{name}.rb")
         
     | 
| 
       10 
12 
     | 
    
         
             
                  raise Plugins::LoadError, "The #{name} plugin does not exist. Have you spelled it correctly?"
         
     | 
| 
       11 
13 
     | 
    
         
             
                end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                require_relative "plugins/#{name}"
         
     | 
| 
       12 
16 
     | 
    
         
             
              end
         
     | 
| 
       13 
     | 
    
         
            -
            end
         
     | 
| 
      
 17 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/exekutor/queue.rb
    CHANGED
    
    | 
         @@ -6,7 +6,7 @@ module Exekutor 
     | 
|
| 
       6 
6 
     | 
    
         
             
                # Used when logging the SQL queries
         
     | 
| 
       7 
7 
     | 
    
         
             
                # @private
         
     | 
| 
       8 
8 
     | 
    
         
             
                ACTION_NAME = "Exekutor::Enqueue"
         
     | 
| 
       9 
     | 
    
         
            -
                private_constant  
     | 
| 
      
 9 
     | 
    
         
            +
                private_constant :ACTION_NAME
         
     | 
| 
       10 
10 
     | 
    
         | 
| 
       11 
11 
     | 
    
         
             
                # Valid range for job priority
         
     | 
| 
       12 
12 
     | 
    
         
             
                # @private
         
     | 
| 
         @@ -38,42 +38,59 @@ module Exekutor 
     | 
|
| 
       38 
38 
     | 
    
         
             
                # @param scheduled_at [Time,Date,Integer,Float] when the job should be performed
         
     | 
| 
       39 
39 
     | 
    
         
             
                # @return [void]
         
     | 
| 
       40 
40 
     | 
    
         
             
                def create_records(jobs, scheduled_at: nil)
         
     | 
| 
       41 
     | 
    
         
            -
                  unless jobs.is_a?(Array) && jobs.all? 
     | 
| 
      
 41 
     | 
    
         
            +
                  unless jobs.is_a?(Array) && jobs.all?(ActiveJob::Base)
         
     | 
| 
       42 
42 
     | 
    
         
             
                    raise ArgumentError, "jobs must be an array with ActiveJob items"
         
     | 
| 
       43 
43 
     | 
    
         
             
                  end
         
     | 
| 
       44 
44 
     | 
    
         | 
| 
      
 45 
     | 
    
         
            +
                  scheduled_at = parse_scheduled_at(scheduled_at)
         
     | 
| 
      
 46 
     | 
    
         
            +
                  json_serializer = Exekutor.config.load_json_serializer
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                  Internal::Hooks.run :enqueue, jobs do
         
     | 
| 
      
 49 
     | 
    
         
            +
                    insert_job_records(jobs, scheduled_at, json_serializer)
         
     | 
| 
      
 50 
     | 
    
         
            +
                  end
         
     | 
| 
      
 51 
     | 
    
         
            +
                end
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                # Converts the given value to an epoch timestamp. Returns the current epoch timestamp if the given value is nil
         
     | 
| 
      
 54 
     | 
    
         
            +
                # @param scheduled_at [nil,Numeric,Time,Date] The timestamp to convert to an epoch timestamp
         
     | 
| 
      
 55 
     | 
    
         
            +
                # @return [Float,Integer] The epoch equivalent of +scheduled_at+
         
     | 
| 
      
 56 
     | 
    
         
            +
                def parse_scheduled_at(scheduled_at)
         
     | 
| 
       45 
57 
     | 
    
         
             
                  if scheduled_at.nil?
         
     | 
| 
       46 
     | 
    
         
            -
                     
     | 
| 
      
 58 
     | 
    
         
            +
                    Time.now.to_i
         
     | 
| 
       47 
59 
     | 
    
         
             
                  else
         
     | 
| 
       48 
60 
     | 
    
         
             
                    case scheduled_at
         
     | 
| 
       49 
61 
     | 
    
         
             
                    when Integer, Float
         
     | 
| 
       50 
62 
     | 
    
         
             
                      raise ArgumentError, "scheduled_at must be a valid epoch" unless scheduled_at.positive?
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                      scheduled_at
         
     | 
| 
       51 
65 
     | 
    
         
             
                    when Time
         
     | 
| 
       52 
     | 
    
         
            -
                      scheduled_at 
     | 
| 
      
 66 
     | 
    
         
            +
                      scheduled_at.to_f
         
     | 
| 
       53 
67 
     | 
    
         
             
                    when Date
         
     | 
| 
       54 
     | 
    
         
            -
                      scheduled_at 
     | 
| 
      
 68 
     | 
    
         
            +
                      scheduled_at.at_beginning_of_day.to_f
         
     | 
| 
       55 
69 
     | 
    
         
             
                    else
         
     | 
| 
       56 
70 
     | 
    
         
             
                      raise ArgumentError, "scheduled_at must be an epoch, time, or date"
         
     | 
| 
       57 
71 
     | 
    
         
             
                    end
         
     | 
| 
       58 
72 
     | 
    
         
             
                  end
         
     | 
| 
      
 73 
     | 
    
         
            +
                end
         
     | 
| 
       59 
74 
     | 
    
         | 
| 
       60 
     | 
    
         
            -
             
     | 
| 
       61 
     | 
    
         
            -
             
     | 
| 
       62 
     | 
    
         
            -
             
     | 
| 
       63 
     | 
    
         
            -
             
     | 
| 
       64 
     | 
    
         
            -
             
     | 
| 
       65 
     | 
    
         
            -
             
     | 
| 
       66 
     | 
    
         
            -
             
     | 
| 
       67 
     | 
    
         
            -
                     
     | 
| 
       68 
     | 
    
         
            -
                       
     | 
| 
       69 
     | 
    
         
            -
             
     | 
| 
       70 
     | 
    
         
            -
             
     | 
| 
       71 
     | 
    
         
            -
             
     | 
| 
       72 
     | 
    
         
            -
                       
     | 
| 
       73 
     | 
    
         
            -
             
     | 
| 
       74 
     | 
    
         
            -
             
     | 
| 
       75 
     | 
    
         
            -
                      SQL
         
     | 
| 
      
 75 
     | 
    
         
            +
                # Fires off an INSERT INTO query for the given jobs
         
     | 
| 
      
 76 
     | 
    
         
            +
                # @param jobs [Array<ActiveJob::Base>] the jobs to insert
         
     | 
| 
      
 77 
     | 
    
         
            +
                # @param scheduled_at [Integer,Float] the scheduled execution time for the jobs as an epoch timestamp
         
     | 
| 
      
 78 
     | 
    
         
            +
                # @param json_serializer [#dump] the serializer to use to convert hashes into JSON
         
     | 
| 
      
 79 
     | 
    
         
            +
                def insert_job_records(jobs, scheduled_at, json_serializer)
         
     | 
| 
      
 80 
     | 
    
         
            +
                  if jobs.one?
         
     | 
| 
      
 81 
     | 
    
         
            +
                    sql_binds = job_sql_binds(jobs.first, scheduled_at, json_serializer)
         
     | 
| 
      
 82 
     | 
    
         
            +
                    Exekutor::Job.connection.exec_query <<~SQL, ACTION_NAME, sql_binds, prepare: true
         
     | 
| 
      
 83 
     | 
    
         
            +
                      INSERT INTO exekutor_jobs ("queue", "priority", "scheduled_at", "active_job_id", "payload", "options") VALUES ($1, $2, to_timestamp($3), $4, $5, $6) RETURNING id;
         
     | 
| 
      
 84 
     | 
    
         
            +
                    SQL
         
     | 
| 
      
 85 
     | 
    
         
            +
                  else
         
     | 
| 
      
 86 
     | 
    
         
            +
                    insert_statements = jobs.map do |job|
         
     | 
| 
      
 87 
     | 
    
         
            +
                      Exekutor::Job.sanitize_sql_for_assignment(
         
     | 
| 
      
 88 
     | 
    
         
            +
                        ["(?, ?, to_timestamp(?), ?, ?::jsonb, ?::jsonb)", *job_sql_binds(job, scheduled_at, json_serializer)]
         
     | 
| 
      
 89 
     | 
    
         
            +
                      )
         
     | 
| 
       76 
90 
     | 
    
         
             
                    end
         
     | 
| 
      
 91 
     | 
    
         
            +
                    Exekutor::Job.connection.insert <<~SQL, ACTION_NAME
         
     | 
| 
      
 92 
     | 
    
         
            +
                      INSERT INTO exekutor_jobs ("queue", "priority", "scheduled_at", "active_job_id", "payload", "options") VALUES #{insert_statements.join(",")}
         
     | 
| 
      
 93 
     | 
    
         
            +
                    SQL
         
     | 
| 
       77 
94 
     | 
    
         
             
                  end
         
     | 
| 
       78 
95 
     | 
    
         
             
                end
         
     | 
| 
       79 
96 
     | 
    
         | 
| 
         @@ -86,7 +103,8 @@ module Exekutor 
     | 
|
| 
       86 
103 
     | 
    
         
             
                  if job.queue_name.blank?
         
     | 
| 
       87 
104 
     | 
    
         
             
                    raise Error, "The queue must be set"
         
     | 
| 
       88 
105 
     | 
    
         
             
                  elsif job.queue_name && job.queue_name.length > Queue::MAX_NAME_LENGTH
         
     | 
| 
       89 
     | 
    
         
            -
                    raise Error, 
     | 
| 
      
 106 
     | 
    
         
            +
                    raise Error,
         
     | 
| 
      
 107 
     | 
    
         
            +
                          "The queue name \"#{job.queue_name}\" is too long, the limit is #{Queue::MAX_NAME_LENGTH} characters"
         
     | 
| 
       90 
108 
     | 
    
         
             
                  end
         
     | 
| 
       91 
109 
     | 
    
         | 
| 
       92 
110 
     | 
    
         
             
                  options = exekutor_options job
         
     | 
    
        data/lib/exekutor/version.rb
    CHANGED
    
    
    
        data/lib/exekutor/worker.rb
    CHANGED
    
    | 
         @@ -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 
     | 
| 
      
 26 
     | 
    
         
            +
                # @option config [Integer] :max_thread_idletime the maximum number of seconds a thread may be idle before being
         
     | 
| 
      
 27 
     | 
    
         
            +
                #   stopped
         
     | 
| 
       27 
28 
     | 
    
         
             
                # @option config [Integer] :polling_interval the polling interval in seconds
         
     | 
| 
       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 
     | 
| 
      
 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 
     | 
| 
      
 35 
     | 
    
         
            +
                # @option config [Integer] :healthcheck_timeout The timeout of a worker in minutes before the healthcheck server
         
     | 
| 
      
 36 
     | 
    
         
            +
                #   deems it as down
         
     | 
| 
       34 
37 
     | 
    
         
             
                def initialize(config = {})
         
     | 
| 
       35 
38 
     | 
    
         
             
                  super()
         
     | 
| 
       36 
39 
     | 
    
         
             
                  @config = config
         
     | 
| 
       37 
40 
     | 
    
         
             
                  @record = create_record!
         
     | 
| 
       38 
41 
     | 
    
         | 
| 
       39 
     | 
    
         
            -
                   
     | 
| 
       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 
     | 
    
         
            -
                   
     | 
| 
       45 
     | 
    
         
            -
                   
     | 
| 
       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 
     | 
    
         
            -
             
     | 
| 
       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 
     | 
    
         
            -
                     
     | 
| 
      
 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:  
     | 
| 
       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[:queues]
         
     | 
| 
      
 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  
     | 
| 
      
 48 
     | 
    
         
            +
            Exekutor.private_constant :Internal
         
     | 
| 
       49 
49 
     | 
    
         
             
            ActiveSupport.run_load_hooks(:exekutor, Exekutor)
         
     | 
| 
         @@ -1,18 +1,22 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
      
 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  
     | 
| 
      
 8 
     | 
    
         
            +
                desc "Create YAML configuration for Exekutor"
         
     | 
| 
       7 
9 
     | 
    
         | 
| 
       8 
     | 
    
         
            -
                class_option :identifier, type: :string, aliases: %i 
     | 
| 
      
 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 
15 
     | 
    
         
             
                  config[:status_port] = 8765
         
     | 
| 
       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", 
     | 
| 
      
 18 
     | 
    
         
            +
                  create_file "config/exekutor#{".#{options[:identifier]}" if options[:identifier]}.yml",
         
     | 
| 
      
 19 
     | 
    
         
            +
                              { "exekutor" => config.stringify_keys }.to_yaml
         
     | 
| 
       16 
20 
     | 
    
         
             
                end
         
     | 
| 
       17 
21 
     | 
    
         
             
              end
         
     | 
| 
       18 
     | 
    
         
            -
            end
         
     | 
| 
      
 22 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -1,29 +1,27 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
            require  
     | 
| 
      
 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  
     | 
| 
      
 10 
     | 
    
         
            +
                desc "Create migrations for Exekutor"
         
     | 
| 
       9 
11 
     | 
    
         | 
| 
       10 
     | 
    
         
            -
                TEMPLATE_DIR = File.join(__dir__,  
     | 
| 
      
 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  
     | 
| 
      
 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  
     | 
| 
       19 
     | 
    
         
            -
             
     | 
| 
       20 
     | 
    
         
            -
             
     | 
| 
       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,18 @@ 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[job_notifier requeue_orphaned_jobs].each do |function|
         
     | 
| 
      
 47 
     | 
    
         
            +
                    copy_file "functions/#{function}.sql", Fx::Definition.new(name: function, version: 1).full_path
         
     | 
| 
      
 48 
     | 
    
         
            +
                  end
         
     | 
| 
      
 49 
     | 
    
         
            +
                  %w[notify_workers requeue_orphaned_jobs].each do |trigger|
         
     | 
| 
      
 50 
     | 
    
         
            +
                    copy_file "triggers/#{trigger}.sql", Fx::Definition.new(name: trigger, version: 1, type: "trigger").full_path
         
     | 
| 
      
 51 
     | 
    
         
            +
                  end
         
     | 
| 
      
 52 
     | 
    
         
            +
                end
         
     | 
| 
       42 
53 
     | 
    
         
             
              end
         
     | 
| 
       43 
     | 
    
         
            -
            end
         
     | 
| 
      
 54 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -7,20 +7,20 @@ class CreateExekutorSchema < ActiveRecord::Migration[<%= migration_version %>] 
     | 
|
| 
       7 
7 
     | 
    
         | 
| 
       8 
8 
     | 
    
         
             
                  t.jsonb :info, null: false
         
     | 
| 
       9 
9 
     | 
    
         | 
| 
       10 
     | 
    
         
            -
                  t.datetime : 
     | 
| 
       11 
     | 
    
         
            -
                  t.datetime :last_heartbeat_at, null: false, default: -> {  
     | 
| 
      
 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:  
     | 
| 
      
 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:  
     | 
| 
       21 
     | 
    
         
            -
                  t.integer :priority, null: false, default:  
     | 
| 
       22 
     | 
    
         
            -
                  t.datetime :enqueued_at, null: false, default: -> {  
     | 
| 
       23 
     | 
    
         
            -
                  t.datetime :scheduled_at, null: false, default: -> {  
     | 
| 
      
 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,16 +28,17 @@ 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:  
     | 
| 
      
 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: % 
     | 
| 
      
 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: -> {  
     | 
| 
      
 41 
     | 
    
         
            +
                  t.datetime :created_at, null: false, default: -> { "now()" }
         
     | 
| 
       41 
42 
     | 
    
         
             
                  t.jsonb :error, null: false
         
     | 
| 
       42 
43 
     | 
    
         
             
                end
         
     | 
| 
       43 
44 
     | 
    
         
             
                  <% if defined? Fx %>
         
     | 
    
        data.tar.gz.sig
    CHANGED
    
    | 
         Binary file 
     |