solid_queue 1.0.1 → 1.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/README.md +78 -5
 - data/app/models/solid_queue/claimed_execution.rb +1 -0
 - data/app/models/solid_queue/queue.rb +13 -0
 - data/app/models/solid_queue/queue_selector.rb +35 -5
 - data/lib/generators/solid_queue/install/install_generator.rb +5 -3
 - data/lib/solid_queue/processes/interruptible.rb +10 -18
 - data/lib/solid_queue/scheduler/recurring_schedule.rb +1 -0
 - data/lib/solid_queue/version.rb +1 -1
 - metadata +35 -7
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA256:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: e843e842397e1d8141e0457b5b278026b71effe6ebf83d8300d2c4098db56adf
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: a5db37bdea8dacec796f2dcb912ab8f2a69c929487dff081d8a53fe10c20086c
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: a6831f7114c24d68ae8ed7b5aebfd4d3df0cc2c7b4e0046e6275a5bf5e46f8da8f5b79e9a303ae908e3581e8b96a132776f4c1a3f55bbf550dd008541e679665
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: e51b90234b3a60355a96c9163bfc7d95a1f5eb95fcf7a2dc1faf553f04a7c242da2d48493ba5b6574c2dbf4b0d259cb69af1dda576475f1510a31f8325be5f8b
         
     | 
    
        data/README.md
    CHANGED
    
    | 
         @@ -149,6 +149,9 @@ Here's an overview of the different options: 
     | 
|
| 
       149 
149 
     | 
    
         
             
              This will create a worker fetching jobs from all queues starting with `staging`. The wildcard `*` is only allowed on its own or at the end of a queue name; you can't specify queue names such as `*_some_queue`. These will be ignored.
         
     | 
| 
       150 
150 
     | 
    
         | 
| 
       151 
151 
     | 
    
         
             
              Finally, you can combine prefixes with exact names, like `[ staging*, background ]`, and the behaviour with respect to order will be the same as with only exact names.
         
     | 
| 
      
 152 
     | 
    
         
            +
             
     | 
| 
      
 153 
     | 
    
         
            +
              Check the sections below on [how queue order behaves combined with priorities](#queue-order-and-priorities), and [how the way you specify the queues per worker might affect performance](#queues-specification-and-performance).
         
     | 
| 
      
 154 
     | 
    
         
            +
             
     | 
| 
       152 
155 
     | 
    
         
             
            - `threads`: this is the max size of the thread pool that each worker will have to run jobs. Each worker will fetch this number of jobs from their queue(s), at most and will post them to the thread pool to be run. By default, this is `3`. Only workers have this setting.
         
     | 
| 
       153 
156 
     | 
    
         
             
            - `processes`: this is the number of worker processes that will be forked by the supervisor with the settings given. By default, this is `1`, just a single process. This setting is useful if you want to dedicate more than one CPU core to a queue or queues with the same configuration. Only workers have this setting.
         
     | 
| 
       154 
157 
     | 
    
         
             
            - `concurrency_maintenance`: whether the dispatcher will perform the concurrency maintenance work. This is `true` by default, and it's useful if you don't use any [concurrency controls](#concurrency-controls) and want to disable it or if you run multiple dispatchers and want some of them to just dispatch jobs without doing anything else.
         
     | 
| 
         @@ -164,6 +167,67 @@ This is useful when you run jobs with different importance or urgency in the sam 
     | 
|
| 
       164 
167 
     | 
    
         | 
| 
       165 
168 
     | 
    
         
             
            We recommend not mixing queue order with priorities but either choosing one or the other, as that will make job execution order more straightforward for you.
         
     | 
| 
       166 
169 
     | 
    
         | 
| 
      
 170 
     | 
    
         
            +
            ### Queues specification and performance
         
     | 
| 
      
 171 
     | 
    
         
            +
             
     | 
| 
      
 172 
     | 
    
         
            +
            To keep polling performant and ensure a covering index is always used, Solid Queue only does two types of polling queries:
         
     | 
| 
      
 173 
     | 
    
         
            +
            ```sql
         
     | 
| 
      
 174 
     | 
    
         
            +
            -- No filtering by queue
         
     | 
| 
      
 175 
     | 
    
         
            +
            SELECT job_id
         
     | 
| 
      
 176 
     | 
    
         
            +
            FROM solid_queue_ready_executions
         
     | 
| 
      
 177 
     | 
    
         
            +
            ORDER BY priority ASC, job_id ASC
         
     | 
| 
      
 178 
     | 
    
         
            +
            LIMIT ?
         
     | 
| 
      
 179 
     | 
    
         
            +
            FOR UPDATE SKIP LOCKED;
         
     | 
| 
      
 180 
     | 
    
         
            +
             
     | 
| 
      
 181 
     | 
    
         
            +
            -- Filtering by a single queue
         
     | 
| 
      
 182 
     | 
    
         
            +
            SELECT job_id
         
     | 
| 
      
 183 
     | 
    
         
            +
            FROM solid_queue_ready_executions
         
     | 
| 
      
 184 
     | 
    
         
            +
            WHERE queue_name = ?
         
     | 
| 
      
 185 
     | 
    
         
            +
            ORDER BY priority ASC, job_id ASC
         
     | 
| 
      
 186 
     | 
    
         
            +
            LIMIT ?
         
     | 
| 
      
 187 
     | 
    
         
            +
            FOR UPDATE SKIP LOCKED;
         
     | 
| 
      
 188 
     | 
    
         
            +
            ```
         
     | 
| 
      
 189 
     | 
    
         
            +
             
     | 
| 
      
 190 
     | 
    
         
            +
            The first one (no filtering by queue) is used when you specify
         
     | 
| 
      
 191 
     | 
    
         
            +
            ```yml
         
     | 
| 
      
 192 
     | 
    
         
            +
            queues: *
         
     | 
| 
      
 193 
     | 
    
         
            +
            ```
         
     | 
| 
      
 194 
     | 
    
         
            +
            and there aren't any queues paused, as we want to target all queues.
         
     | 
| 
      
 195 
     | 
    
         
            +
             
     | 
| 
      
 196 
     | 
    
         
            +
            In other cases, we need to have a list of queues to filter by, in order, because we can only filter by a single queue at a time to ensure we use an index to sort. This means that if you specify your queues as:
         
     | 
| 
      
 197 
     | 
    
         
            +
            ```yml
         
     | 
| 
      
 198 
     | 
    
         
            +
            queues: beta*
         
     | 
| 
      
 199 
     | 
    
         
            +
            ```
         
     | 
| 
      
 200 
     | 
    
         
            +
             
     | 
| 
      
 201 
     | 
    
         
            +
            we'll need to get a list of all existing queues matching that prefix first, with a query that would look like this:
         
     | 
| 
      
 202 
     | 
    
         
            +
            ```sql
         
     | 
| 
      
 203 
     | 
    
         
            +
            SELECT DISTINCT(queue_name)
         
     | 
| 
      
 204 
     | 
    
         
            +
            FROM solid_queue_ready_executions
         
     | 
| 
      
 205 
     | 
    
         
            +
            WHERE queue_name LIKE 'beta%';
         
     | 
| 
      
 206 
     | 
    
         
            +
            ```
         
     | 
| 
      
 207 
     | 
    
         
            +
             
     | 
| 
      
 208 
     | 
    
         
            +
            This type of `DISTINCT` query on a column that's the leftmost column in an index can be performed very fast in MySQL thanks to a technique called [Loose Index Scan](https://dev.mysql.com/doc/refman/8.0/en/group-by-optimization.html#loose-index-scan). PostgreSQL and SQLite, however, don't implement this technique, which means that if your `solid_queue_ready_executions` table is very big because your queues get very deep, this query will get slow. Normally your `solid_queue_ready_executions` table will be small, but it can happen.
         
     | 
| 
      
 209 
     | 
    
         
            +
             
     | 
| 
      
 210 
     | 
    
         
            +
            Similarly to using prefixes, the same will happen if you have paused queues, because we need to get a list of all queues with a query like
         
     | 
| 
      
 211 
     | 
    
         
            +
            ```sql
         
     | 
| 
      
 212 
     | 
    
         
            +
            SELECT DISTINCT(queue_name)
         
     | 
| 
      
 213 
     | 
    
         
            +
            FROM solid_queue_ready_executions
         
     | 
| 
      
 214 
     | 
    
         
            +
            ```
         
     | 
| 
      
 215 
     | 
    
         
            +
             
     | 
| 
      
 216 
     | 
    
         
            +
            and then remove the paused ones. Pausing in general should be something rare, used in special circumstances, and for a short period of time. If you don't want to process jobs from a queue anymore, the best way to do that is to remove it from your list of queues.
         
     | 
| 
      
 217 
     | 
    
         
            +
             
     | 
| 
      
 218 
     | 
    
         
            +
            💡 To sum up, **if you want to ensure optimal performance on polling**, the best way to do that is to always specify exact names for them, and not have any queues paused.
         
     | 
| 
      
 219 
     | 
    
         
            +
             
     | 
| 
      
 220 
     | 
    
         
            +
            Do this:
         
     | 
| 
      
 221 
     | 
    
         
            +
             
     | 
| 
      
 222 
     | 
    
         
            +
            ```yml
         
     | 
| 
      
 223 
     | 
    
         
            +
            queues: background, backend
         
     | 
| 
      
 224 
     | 
    
         
            +
            ```
         
     | 
| 
      
 225 
     | 
    
         
            +
             
     | 
| 
      
 226 
     | 
    
         
            +
            instead of this:
         
     | 
| 
      
 227 
     | 
    
         
            +
            ```yml
         
     | 
| 
      
 228 
     | 
    
         
            +
            queues: back*
         
     | 
| 
      
 229 
     | 
    
         
            +
            ```
         
     | 
| 
      
 230 
     | 
    
         
            +
             
     | 
| 
       167 
231 
     | 
    
         | 
| 
       168 
232 
     | 
    
         
             
            ### Threads, processes and signals
         
     | 
| 
       169 
233 
     | 
    
         | 
| 
         @@ -175,7 +239,9 @@ The supervisor is in charge of managing these processes, and it responds to the 
     | 
|
| 
       175 
239 
     | 
    
         | 
| 
       176 
240 
     | 
    
         
             
            When receiving a `QUIT` signal, if workers still have jobs in-flight, these will be returned to the queue when the processes are deregistered.
         
     | 
| 
       177 
241 
     | 
    
         | 
| 
       178 
     | 
    
         
            -
            If processes have no chance of cleaning up before exiting (e.g. if someone pulls a cable somewhere), in-flight jobs might remain claimed by the processes executing them. Processes send heartbeats, and the supervisor checks and prunes processes with expired heartbeats 
     | 
| 
      
 242 
     | 
    
         
            +
            If processes have no chance of cleaning up before exiting (e.g. if someone pulls a cable somewhere), in-flight jobs might remain claimed by the processes executing them. Processes send heartbeats, and the supervisor checks and prunes processes with expired heartbeats. Jobs that were claimed by processes with an expired heartbeat will be marked as failed with a `SolidQueue::Processes::ProcessPrunedError`. You can configure both the frequency of heartbeats and the threshold to consider a process dead. See the section below for this.
         
     | 
| 
      
 243 
     | 
    
         
            +
             
     | 
| 
      
 244 
     | 
    
         
            +
            In a similar way, if a worker is terminated in any other way not initiated by the above signals (e.g. a worker is sent a `KILL` signal), jobs in progress will be marked as failed so that they can be inspected, with a `SolidQueue::Processes::Process::ProcessExitError`. Sometimes a job in particular is responsible for this, for example, if it has a memory leak and you have a mechanism to kill processes over a certain memory threshold, so this will help identifying this kind of situation.
         
     | 
| 
       179 
245 
     | 
    
         | 
| 
       180 
246 
     | 
    
         | 
| 
       181 
247 
     | 
    
         
             
            ### Database configuration
         
     | 
| 
         @@ -348,13 +414,19 @@ to your `puma.rb` configuration. 
     | 
|
| 
       348 
414 
     | 
    
         | 
| 
       349 
415 
     | 
    
         | 
| 
       350 
416 
     | 
    
         
             
            ## Jobs and transactional integrity
         
     | 
| 
       351 
     | 
    
         
            -
            :warning: Having your jobs in the same ACID-compliant database as your application data enables a powerful yet sharp tool: taking advantage of transactional integrity to ensure some action in your app is not committed unless your job is also committed and  
     | 
| 
      
 417 
     | 
    
         
            +
            :warning: Having your jobs in the same ACID-compliant database as your application data enables a powerful yet sharp tool: taking advantage of transactional integrity to ensure some action in your app is not committed unless your job is also committed and vice versa, and ensuring that your job won't be enqueued until the transaction within which you're enqueuing it is committed. This can be very powerful and useful, but it can also backfire if you base some of your logic on this behaviour, and in the future, you move to another active job backend, or if you simply move Solid Queue to its own database, and suddenly the behaviour changes under you. Because this can be quite tricky and many people shouldn't need to worry about it, by default Solid Queue is configured in a different database as the main app.
         
     | 
| 
       352 
418 
     | 
    
         | 
| 
       353 
     | 
    
         
            -
             
     | 
| 
      
 419 
     | 
    
         
            +
            Starting from Rails 8, an option which doesn't rely on this transactional integrity and which Active Job provides is to defer the enqueueing of a job inside an Active Record transaction until that transaction successfully commits. This option can be set via the [`enqueue_after_transaction_commit`](https://edgeapi.rubyonrails.org/classes/ActiveJob/Enqueuing.html#method-c-enqueue_after_transaction_commit) class method on the job level and is by default disabled. Either it can be enabled for individual jobs or for all jobs through `ApplicationJob`:
         
     | 
| 
       354 
420 
     | 
    
         | 
| 
       355 
     | 
    
         
            -
             
     | 
| 
      
 421 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 422 
     | 
    
         
            +
            class ApplicationJob < ActiveJob::Base
         
     | 
| 
      
 423 
     | 
    
         
            +
              self.enqueue_after_transaction_commit = true
         
     | 
| 
      
 424 
     | 
    
         
            +
            end
         
     | 
| 
      
 425 
     | 
    
         
            +
            ```
         
     | 
| 
      
 426 
     | 
    
         
            +
             
     | 
| 
      
 427 
     | 
    
         
            +
            Using this option, you can also use Solid Queue in the same database as your app but not rely on transactional integrity.
         
     | 
| 
       356 
428 
     | 
    
         | 
| 
       357 
     | 
    
         
            -
            If you set  
     | 
| 
      
 429 
     | 
    
         
            +
            If you don't set this option but still want to make sure you're not inadvertently on transactional integrity, you can make sure that:
         
     | 
| 
       358 
430 
     | 
    
         
             
            - Your jobs relying on specific data are always enqueued on [`after_commit` callbacks](https://guides.rubyonrails.org/active_record_callbacks.html#after-commit-and-after-rollback) or otherwise from a place where you're certain that whatever data the job will use has been committed to the database before the job is enqueued.
         
     | 
| 
       359 
431 
     | 
    
         
             
            - Or, you configure a different database for Solid Queue, even if it's the same as your app, ensuring that a different connection on the thread handling requests or running jobs for your app will be used to enqueue jobs. For example:
         
     | 
| 
       360 
432 
     | 
    
         | 
| 
         @@ -369,6 +441,7 @@ If you set that to `never` but still want to make sure you're not inadvertently 
     | 
|
| 
       369 
441 
     | 
    
         
             
              config.solid_queue.connects_to = { database: { writing: :primary, reading: :replica } }
         
     | 
| 
       370 
442 
     | 
    
         
             
              ```
         
     | 
| 
       371 
443 
     | 
    
         | 
| 
      
 444 
     | 
    
         
            +
             
     | 
| 
       372 
445 
     | 
    
         
             
            ## Recurring tasks
         
     | 
| 
       373 
446 
     | 
    
         | 
| 
       374 
447 
     | 
    
         
             
            Solid Queue supports defining recurring tasks that run at specific times in the future, on a regular basis like cron jobs. These are managed by the scheduler process and are defined in their own configuration file. By default, the file is located in `config/recurring.yml`, but you can set a different path using the environment variable `SOLID_QUEUE_RECURRING_SCHEDULE` or by using the `--recurring_schedule_file` option with `bin/jobs`, like this:
         
     | 
| 
         @@ -40,6 +40,19 @@ module SolidQueue 
     | 
|
| 
       40 
40 
     | 
    
         
             
                  @size ||= ReadyExecution.queued_as(name).count
         
     | 
| 
       41 
41 
     | 
    
         
             
                end
         
     | 
| 
       42 
42 
     | 
    
         | 
| 
      
 43 
     | 
    
         
            +
                def latency
         
     | 
| 
      
 44 
     | 
    
         
            +
                  @latency ||= begin
         
     | 
| 
      
 45 
     | 
    
         
            +
                    now = Time.current
         
     | 
| 
      
 46 
     | 
    
         
            +
                    oldest_enqueued_at = ReadyExecution.queued_as(name).minimum(:created_at) || now
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                    (now - oldest_enqueued_at).to_i
         
     | 
| 
      
 49 
     | 
    
         
            +
                  end
         
     | 
| 
      
 50 
     | 
    
         
            +
                end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                def human_latency
         
     | 
| 
      
 53 
     | 
    
         
            +
                  ActiveSupport::Duration.build(latency).inspect
         
     | 
| 
      
 54 
     | 
    
         
            +
                end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
       43 
56 
     | 
    
         
             
                def ==(queue)
         
     | 
| 
       44 
57 
     | 
    
         
             
                  name == queue.name
         
     | 
| 
       45 
58 
     | 
    
         
             
                end
         
     | 
| 
         @@ -34,7 +34,7 @@ module SolidQueue 
     | 
|
| 
       34 
34 
     | 
    
         
             
                  def eligible_queues
         
     | 
| 
       35 
35 
     | 
    
         
             
                    if include_all_queues? then all_queues
         
     | 
| 
       36 
36 
     | 
    
         
             
                    else
         
     | 
| 
       37 
     | 
    
         
            -
                      exact_names + prefixed_names
         
     | 
| 
      
 37 
     | 
    
         
            +
                      in_raw_order(exact_names + prefixed_names)
         
     | 
| 
       38 
38 
     | 
    
         
             
                    end
         
     | 
| 
       39 
39 
     | 
    
         
             
                  end
         
     | 
| 
       40 
40 
     | 
    
         | 
| 
         @@ -42,8 +42,12 @@ module SolidQueue 
     | 
|
| 
       42 
42 
     | 
    
         
             
                    "*".in? raw_queues
         
     | 
| 
       43 
43 
     | 
    
         
             
                  end
         
     | 
| 
       44 
44 
     | 
    
         | 
| 
      
 45 
     | 
    
         
            +
                  def all_queues
         
     | 
| 
      
 46 
     | 
    
         
            +
                    relation.distinct(:queue_name).pluck(:queue_name)
         
     | 
| 
      
 47 
     | 
    
         
            +
                  end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
       45 
49 
     | 
    
         
             
                  def exact_names
         
     | 
| 
       46 
     | 
    
         
            -
                    raw_queues.select { |queue|  
     | 
| 
      
 50 
     | 
    
         
            +
                    raw_queues.select { |queue| exact_name?(queue) }
         
     | 
| 
       47 
51 
     | 
    
         
             
                  end
         
     | 
| 
       48 
52 
     | 
    
         | 
| 
       49 
53 
     | 
    
         
             
                  def prefixed_names
         
     | 
| 
         @@ -54,15 +58,41 @@ module SolidQueue 
     | 
|
| 
       54 
58 
     | 
    
         
             
                  end
         
     | 
| 
       55 
59 
     | 
    
         | 
| 
       56 
60 
     | 
    
         
             
                  def prefixes
         
     | 
| 
       57 
     | 
    
         
            -
                    @prefixes ||= raw_queues.select { |queue|  
     | 
| 
      
 61 
     | 
    
         
            +
                    @prefixes ||= raw_queues.select { |queue| prefixed_name?(queue) }.map { |queue| queue.tr("*", "%") }
         
     | 
| 
       58 
62 
     | 
    
         
             
                  end
         
     | 
| 
       59 
63 
     | 
    
         | 
| 
       60 
     | 
    
         
            -
                  def  
     | 
| 
       61 
     | 
    
         
            -
                     
     | 
| 
      
 64 
     | 
    
         
            +
                  def exact_name?(queue)
         
     | 
| 
      
 65 
     | 
    
         
            +
                    !queue.include?("*")
         
     | 
| 
      
 66 
     | 
    
         
            +
                  end
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
                  def prefixed_name?(queue)
         
     | 
| 
      
 69 
     | 
    
         
            +
                    queue.ends_with?("*")
         
     | 
| 
       62 
70 
     | 
    
         
             
                  end
         
     | 
| 
       63 
71 
     | 
    
         | 
| 
       64 
72 
     | 
    
         
             
                  def paused_queues
         
     | 
| 
       65 
73 
     | 
    
         
             
                    @paused_queues ||= Pause.all.pluck(:queue_name)
         
     | 
| 
       66 
74 
     | 
    
         
             
                  end
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
                  def in_raw_order(queues)
         
     | 
| 
      
 77 
     | 
    
         
            +
                    # Only need to sort if we have prefixes and more than one queue name.
         
     | 
| 
      
 78 
     | 
    
         
            +
                    # Exact names are selected in the same order as they're found
         
     | 
| 
      
 79 
     | 
    
         
            +
                    if queues.one? || prefixes.empty?
         
     | 
| 
      
 80 
     | 
    
         
            +
                      queues
         
     | 
| 
      
 81 
     | 
    
         
            +
                    else
         
     | 
| 
      
 82 
     | 
    
         
            +
                      queues = queues.dup
         
     | 
| 
      
 83 
     | 
    
         
            +
                      raw_queues.flat_map { |raw_queue| delete_in_order(raw_queue, queues) }.compact
         
     | 
| 
      
 84 
     | 
    
         
            +
                    end
         
     | 
| 
      
 85 
     | 
    
         
            +
                  end
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
                  def delete_in_order(raw_queue, queues)
         
     | 
| 
      
 88 
     | 
    
         
            +
                    if exact_name?(raw_queue)
         
     | 
| 
      
 89 
     | 
    
         
            +
                      queues.delete(raw_queue)
         
     | 
| 
      
 90 
     | 
    
         
            +
                    elsif prefixed_name?(raw_queue)
         
     | 
| 
      
 91 
     | 
    
         
            +
                      prefix = raw_queue.tr("*", "")
         
     | 
| 
      
 92 
     | 
    
         
            +
                      queues.select { |queue| queue.start_with?(prefix) }.tap do |matches|
         
     | 
| 
      
 93 
     | 
    
         
            +
                        queues -= matches
         
     | 
| 
      
 94 
     | 
    
         
            +
                      end
         
     | 
| 
      
 95 
     | 
    
         
            +
                    end
         
     | 
| 
      
 96 
     | 
    
         
            +
                  end
         
     | 
| 
       67 
97 
     | 
    
         
             
              end
         
     | 
| 
       68 
98 
     | 
    
         
             
            end
         
     | 
| 
         @@ -11,9 +11,11 @@ class SolidQueue::InstallGenerator < Rails::Generators::Base 
     | 
|
| 
       11 
11 
     | 
    
         
             
                chmod "bin/jobs", 0755 & ~File.umask, verbose: false
         
     | 
| 
       12 
12 
     | 
    
         
             
              end
         
     | 
| 
       13 
13 
     | 
    
         | 
| 
       14 
     | 
    
         
            -
              def  
     | 
| 
       15 
     | 
    
         
            -
                 
     | 
| 
       16 
     | 
    
         
            -
             
     | 
| 
      
 14 
     | 
    
         
            +
              def configure_adapter_and_database
         
     | 
| 
      
 15 
     | 
    
         
            +
                pathname = Pathname(destination_root).join("config/environments/production.rb")
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                gsub_file pathname, /\n\s*config\.solid_queue\.connects_to\s+=.*\n/, "\n", verbose: false
         
     | 
| 
      
 18 
     | 
    
         
            +
                gsub_file pathname, /(# )?config\.active_job\.queue_adapter\s+=.*\n/,
         
     | 
| 
       17 
19 
     | 
    
         
             
                  "config.active_job.queue_adapter = :solid_queue\n" +
         
     | 
| 
       18 
20 
     | 
    
         
             
                  "  config.solid_queue.connects_to = { database: { writing: :queue } }\n"
         
     | 
| 
       19 
21 
     | 
    
         
             
              end
         
     | 
| 
         @@ -7,31 +7,23 @@ module SolidQueue::Processes 
     | 
|
| 
       7 
7 
     | 
    
         
             
                end
         
     | 
| 
       8 
8 
     | 
    
         | 
| 
       9 
9 
     | 
    
         
             
                private
         
     | 
| 
       10 
     | 
    
         
            -
                  SELF_PIPE_BLOCK_SIZE = 11
         
     | 
| 
       11 
10 
     | 
    
         | 
| 
       12 
11 
     | 
    
         
             
                  def interrupt
         
     | 
| 
       13 
     | 
    
         
            -
                     
     | 
| 
       14 
     | 
    
         
            -
                  rescue Errno::EAGAIN, Errno::EINTR
         
     | 
| 
       15 
     | 
    
         
            -
                    # Ignore writes that would block and retry
         
     | 
| 
       16 
     | 
    
         
            -
                    # if another signal arrived while writing
         
     | 
| 
       17 
     | 
    
         
            -
                    retry
         
     | 
| 
      
 12 
     | 
    
         
            +
                    queue << true
         
     | 
| 
       18 
13 
     | 
    
         
             
                  end
         
     | 
| 
       19 
14 
     | 
    
         | 
| 
       20 
15 
     | 
    
         
             
                  def interruptible_sleep(time)
         
     | 
| 
       21 
     | 
    
         
            -
                     
     | 
| 
       22 
     | 
    
         
            -
             
     | 
| 
       23 
     | 
    
         
            -
                     
     | 
| 
       24 
     | 
    
         
            -
             
     | 
| 
      
 16 
     | 
    
         
            +
                    # Invoking from the main thread can result in a 35% slowdown (at least when running the test suite).
         
     | 
| 
      
 17 
     | 
    
         
            +
                    # Using some form of Async (Futures) addresses this performance issue.
         
     | 
| 
      
 18 
     | 
    
         
            +
                    Concurrent::Promises.future(time) do |timeout|
         
     | 
| 
      
 19 
     | 
    
         
            +
                      if timeout > 0 && queue.pop(timeout:)
         
     | 
| 
      
 20 
     | 
    
         
            +
                        queue.clear
         
     | 
| 
      
 21 
     | 
    
         
            +
                      end
         
     | 
| 
      
 22 
     | 
    
         
            +
                    end.value
         
     | 
| 
       25 
23 
     | 
    
         
             
                  end
         
     | 
| 
       26 
24 
     | 
    
         | 
| 
       27 
     | 
    
         
            -
                   
     | 
| 
       28 
     | 
    
         
            -
             
     | 
| 
       29 
     | 
    
         
            -
                    @self_pipe ||= create_self_pipe
         
     | 
| 
       30 
     | 
    
         
            -
                  end
         
     | 
| 
       31 
     | 
    
         
            -
             
     | 
| 
       32 
     | 
    
         
            -
                  def create_self_pipe
         
     | 
| 
       33 
     | 
    
         
            -
                    reader, writer = IO.pipe
         
     | 
| 
       34 
     | 
    
         
            -
                    { reader: reader, writer: writer }
         
     | 
| 
      
 25 
     | 
    
         
            +
                  def queue
         
     | 
| 
      
 26 
     | 
    
         
            +
                    @queue ||= Queue.new
         
     | 
| 
       35 
27 
     | 
    
         
             
                  end
         
     | 
| 
       36 
28 
     | 
    
         
             
              end
         
     | 
| 
       37 
29 
     | 
    
         
             
            end
         
     | 
    
        data/lib/solid_queue/version.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | 
         @@ -1,14 +1,14 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            --- !ruby/object:Gem::Specification
         
     | 
| 
       2 
2 
     | 
    
         
             
            name: solid_queue
         
     | 
| 
       3 
3 
     | 
    
         
             
            version: !ruby/object:Gem::Version
         
     | 
| 
       4 
     | 
    
         
            -
              version: 1.0 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 1.1.0
         
     | 
| 
       5 
5 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       6 
6 
     | 
    
         
             
            authors:
         
     | 
| 
       7 
7 
     | 
    
         
             
            - Rosa Gutierrez
         
     | 
| 
       8 
8 
     | 
    
         
             
            autorequire:
         
     | 
| 
       9 
9 
     | 
    
         
             
            bindir: bin
         
     | 
| 
       10 
10 
     | 
    
         
             
            cert_chain: []
         
     | 
| 
       11 
     | 
    
         
            -
            date: 2024- 
     | 
| 
      
 11 
     | 
    
         
            +
            date: 2024-12-05 00:00:00.000000000 Z
         
     | 
| 
       12 
12 
     | 
    
         
             
            dependencies:
         
     | 
| 
       13 
13 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       14 
14 
     | 
    
         
             
              name: activerecord
         
     | 
| 
         @@ -98,16 +98,16 @@ dependencies: 
     | 
|
| 
       98 
98 
     | 
    
         
             
              name: debug
         
     | 
| 
       99 
99 
     | 
    
         
             
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
       100 
100 
     | 
    
         
             
                requirements:
         
     | 
| 
       101 
     | 
    
         
            -
                - - " 
     | 
| 
      
 101 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
       102 
102 
     | 
    
         
             
                  - !ruby/object:Gem::Version
         
     | 
| 
       103 
     | 
    
         
            -
                    version: ' 
     | 
| 
      
 103 
     | 
    
         
            +
                    version: '1.9'
         
     | 
| 
       104 
104 
     | 
    
         
             
              type: :development
         
     | 
| 
       105 
105 
     | 
    
         
             
              prerelease: false
         
     | 
| 
       106 
106 
     | 
    
         
             
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
       107 
107 
     | 
    
         
             
                requirements:
         
     | 
| 
       108 
     | 
    
         
            -
                - - " 
     | 
| 
      
 108 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
       109 
109 
     | 
    
         
             
                  - !ruby/object:Gem::Version
         
     | 
| 
       110 
     | 
    
         
            -
                    version: ' 
     | 
| 
      
 110 
     | 
    
         
            +
                    version: '1.9'
         
     | 
| 
       111 
111 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       112 
112 
     | 
    
         
             
              name: mocha
         
     | 
| 
       113 
113 
     | 
    
         
             
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
         @@ -192,6 +192,34 @@ dependencies: 
     | 
|
| 
       192 
192 
     | 
    
         
             
                - - ">="
         
     | 
| 
       193 
193 
     | 
    
         
             
                  - !ruby/object:Gem::Version
         
     | 
| 
       194 
194 
     | 
    
         
             
                    version: '0'
         
     | 
| 
      
 195 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 196 
     | 
    
         
            +
              name: rdoc
         
     | 
| 
      
 197 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 198 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 199 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 200 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 201 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 202 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 203 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 204 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 205 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 206 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 207 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 208 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 209 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 210 
     | 
    
         
            +
              name: logger
         
     | 
| 
      
 211 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 212 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 213 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 214 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 215 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 216 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 217 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 218 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 219 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 220 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 221 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 222 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
       195 
223 
     | 
    
         
             
            description: Database-backed Active Job backend.
         
     | 
| 
       196 
224 
     | 
    
         
             
            email:
         
     | 
| 
       197 
225 
     | 
    
         
             
            - rosa@37signals.com
         
     | 
| 
         @@ -302,7 +330,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement 
     | 
|
| 
       302 
330 
     | 
    
         
             
                - !ruby/object:Gem::Version
         
     | 
| 
       303 
331 
     | 
    
         
             
                  version: '0'
         
     | 
| 
       304 
332 
     | 
    
         
             
            requirements: []
         
     | 
| 
       305 
     | 
    
         
            -
            rubygems_version: 3.5. 
     | 
| 
      
 333 
     | 
    
         
            +
            rubygems_version: 3.5.16
         
     | 
| 
       306 
334 
     | 
    
         
             
            signing_key:
         
     | 
| 
       307 
335 
     | 
    
         
             
            specification_version: 4
         
     | 
| 
       308 
336 
     | 
    
         
             
            summary: Database-backed Active Job backend.
         
     |