que 0.11.3 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.github/workflows/tests.yml +51 -0
- data/.gitignore +2 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +502 -97
- data/Dockerfile +20 -0
- data/LICENSE.txt +1 -1
- data/README.md +205 -59
- data/auto/dev +21 -0
- data/auto/pre-push-hook +30 -0
- data/auto/psql +9 -0
- data/auto/test +5 -0
- data/auto/test-postgres-14 +17 -0
- data/bin/que +8 -81
- data/docker-compose.yml +47 -0
- data/docs/README.md +881 -0
- data/lib/que/active_job/extensions.rb +114 -0
- data/lib/que/active_record/connection.rb +51 -0
- data/lib/que/active_record/model.rb +48 -0
- data/lib/que/command_line_interface.rb +259 -0
- data/lib/que/connection.rb +198 -0
- data/lib/que/connection_pool.rb +78 -0
- data/lib/que/job.rb +210 -103
- data/lib/que/job_buffer.rb +255 -0
- data/lib/que/job_methods.rb +176 -0
- data/lib/que/listener.rb +176 -0
- data/lib/que/locker.rb +507 -0
- data/lib/que/metajob.rb +47 -0
- data/lib/que/migrations/4/down.sql +48 -0
- data/lib/que/migrations/4/up.sql +267 -0
- data/lib/que/migrations/5/down.sql +73 -0
- data/lib/que/migrations/5/up.sql +76 -0
- data/lib/que/migrations/6/down.sql +8 -0
- data/lib/que/migrations/6/up.sql +8 -0
- data/lib/que/migrations/7/down.sql +5 -0
- data/lib/que/migrations/7/up.sql +13 -0
- data/lib/que/migrations.rb +37 -18
- data/lib/que/poller.rb +274 -0
- data/lib/que/rails/railtie.rb +12 -0
- data/lib/que/result_queue.rb +35 -0
- data/lib/que/sequel/model.rb +52 -0
- data/lib/que/utils/assertions.rb +62 -0
- data/lib/que/utils/constantization.rb +19 -0
- data/lib/que/utils/error_notification.rb +68 -0
- data/lib/que/utils/freeze.rb +20 -0
- data/lib/que/utils/introspection.rb +50 -0
- data/lib/que/utils/json_serialization.rb +21 -0
- data/lib/que/utils/logging.rb +79 -0
- data/lib/que/utils/middleware.rb +46 -0
- data/lib/que/utils/queue_management.rb +18 -0
- data/lib/que/utils/ruby2_keywords.rb +19 -0
- data/lib/que/utils/transactions.rb +34 -0
- data/lib/que/version.rb +5 -1
- data/lib/que/worker.rb +145 -149
- data/lib/que.rb +103 -159
- data/que.gemspec +17 -4
- data/scripts/docker-entrypoint +14 -0
- data/scripts/test +6 -0
- metadata +59 -95
- data/.rspec +0 -2
- data/.travis.yml +0 -17
- data/Gemfile +0 -24
- data/docs/advanced_setup.md +0 -106
- data/docs/customizing_que.md +0 -200
- data/docs/error_handling.md +0 -47
- data/docs/inspecting_the_queue.md +0 -114
- data/docs/logging.md +0 -50
- data/docs/managing_workers.md +0 -80
- data/docs/migrating.md +0 -30
- data/docs/multiple_queues.md +0 -27
- data/docs/shutting_down_safely.md +0 -7
- data/docs/using_plain_connections.md +0 -41
- data/docs/using_sequel.md +0 -31
- data/docs/writing_reliable_jobs.md +0 -117
- data/lib/generators/que/install_generator.rb +0 -24
- data/lib/generators/que/templates/add_que.rb +0 -13
- data/lib/que/adapters/active_record.rb +0 -54
- data/lib/que/adapters/base.rb +0 -127
- data/lib/que/adapters/connection_pool.rb +0 -16
- data/lib/que/adapters/pg.rb +0 -21
- data/lib/que/adapters/pond.rb +0 -16
- data/lib/que/adapters/sequel.rb +0 -20
- data/lib/que/railtie.rb +0 -16
- data/lib/que/rake_tasks.rb +0 -59
- data/lib/que/sql.rb +0 -152
- data/spec/adapters/active_record_spec.rb +0 -152
- data/spec/adapters/connection_pool_spec.rb +0 -22
- data/spec/adapters/pg_spec.rb +0 -41
- data/spec/adapters/pond_spec.rb +0 -22
- data/spec/adapters/sequel_spec.rb +0 -57
- data/spec/gemfiles/Gemfile1 +0 -18
- data/spec/gemfiles/Gemfile2 +0 -18
- data/spec/spec_helper.rb +0 -118
- data/spec/support/helpers.rb +0 -19
- data/spec/support/jobs.rb +0 -35
- data/spec/support/shared_examples/adapter.rb +0 -37
- data/spec/support/shared_examples/multi_threaded_adapter.rb +0 -46
- data/spec/travis.rb +0 -23
- data/spec/unit/connection_spec.rb +0 -14
- data/spec/unit/customization_spec.rb +0 -251
- data/spec/unit/enqueue_spec.rb +0 -245
- data/spec/unit/helper_spec.rb +0 -12
- data/spec/unit/logging_spec.rb +0 -101
- data/spec/unit/migrations_spec.rb +0 -84
- data/spec/unit/pool_spec.rb +0 -365
- data/spec/unit/run_spec.rb +0 -14
- data/spec/unit/states_spec.rb +0 -50
- data/spec/unit/stats_spec.rb +0 -46
- data/spec/unit/transaction_spec.rb +0 -36
- data/spec/unit/work_spec.rb +0 -407
- data/spec/unit/worker_spec.rb +0 -167
- data/tasks/benchmark.rb +0 -3
- data/tasks/rspec.rb +0 -14
- data/tasks/safe_shutdown.rb +0 -67
@@ -1,41 +0,0 @@
|
|
1
|
-
## Using Plain Postgres Connections
|
2
|
-
|
3
|
-
If you're not using an ORM like ActiveRecord or Sequel, you can use one of two gems to manage a connection pool for your PG connections. The first is the ConnectionPool gem (be sure to add `gem 'connection_pool'` to your Gemfile):
|
4
|
-
|
5
|
-
```ruby
|
6
|
-
require 'uri'
|
7
|
-
require 'pg'
|
8
|
-
require 'connection_pool'
|
9
|
-
|
10
|
-
uri = URI.parse(ENV['DATABASE_URL'])
|
11
|
-
|
12
|
-
Que.connection = ConnectionPool.new :size => 10 do
|
13
|
-
PG::Connection.open :host => uri.host,
|
14
|
-
:user => uri.user,
|
15
|
-
:password => uri.password,
|
16
|
-
:port => uri.port || 5432,
|
17
|
-
:dbname => uri.path[1..-1]
|
18
|
-
end
|
19
|
-
```
|
20
|
-
|
21
|
-
Be sure to pick your pool size carefully - if you use 10 for the size, you'll incur the overhead of having 10 connections open to Postgres even if you never use more than a couple of them.
|
22
|
-
|
23
|
-
The Pond gem doesn't have this drawback - it is very similar to ConnectionPool, but establishes connections lazily (add `gem 'pond'` to your Gemfile):
|
24
|
-
|
25
|
-
```ruby
|
26
|
-
require 'uri'
|
27
|
-
require 'pg'
|
28
|
-
require 'pond'
|
29
|
-
|
30
|
-
uri = URI.parse(ENV['DATABASE_URL'])
|
31
|
-
|
32
|
-
Que.connection = Pond.new :maximum_size => 10 do
|
33
|
-
PG::Connection.open :host => uri.host,
|
34
|
-
:user => uri.user,
|
35
|
-
:password => uri.password,
|
36
|
-
:port => uri.port || 5432,
|
37
|
-
:dbname => uri.path[1..-1]
|
38
|
-
end
|
39
|
-
```
|
40
|
-
|
41
|
-
Please be aware that if you're using ActiveRecord or Sequel to manage your data, there's no reason for you to be using any of these methods - it's less efficient (unnecessary connections will waste memory on your database server) and you lose the reliability benefits of wrapping jobs in the same transactions as the rest of your data. In general, your app should probably be using a connection pool, and Que should probably hook into whatever connection pool you're already using.
|
data/docs/using_sequel.md
DELETED
@@ -1,31 +0,0 @@
|
|
1
|
-
## Using Sequel
|
2
|
-
|
3
|
-
If you're using Sequel, with or without Rails, you'll need to give Que a specific database instance to use:
|
4
|
-
|
5
|
-
```ruby
|
6
|
-
DB = Sequel.connect(ENV['DATABASE_URL'])
|
7
|
-
Que.connection = DB
|
8
|
-
```
|
9
|
-
|
10
|
-
Then you can safely use the same database object to transactionally protect your jobs:
|
11
|
-
|
12
|
-
```ruby
|
13
|
-
class MyJob < Que::Job
|
14
|
-
def run
|
15
|
-
# Do stuff.
|
16
|
-
|
17
|
-
DB.transaction do
|
18
|
-
# Make changes to the database.
|
19
|
-
|
20
|
-
# Destroying this job will be protected by the same transaction.
|
21
|
-
destroy
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
# In your controller action:
|
27
|
-
DB.transaction do
|
28
|
-
@user = User.create(params[:user])
|
29
|
-
MyJob.enqueue :user_id => @user.id
|
30
|
-
end
|
31
|
-
```
|
@@ -1,117 +0,0 @@
|
|
1
|
-
## Writing Reliable Jobs
|
2
|
-
|
3
|
-
Que does everything it can to ensure that jobs are worked exactly once, but if something bad happens when a job is halfway completed, there's no way around it - the job will need be repeated over again from the beginning, probably by a different worker. When you're writing jobs, you need to be prepared for this to happen.
|
4
|
-
|
5
|
-
The safest type of job is one that reads in data, either from the database or from external APIs, then does some number crunching and writes the results to the database. These jobs are easy to make safe - simply write the results to the database inside a transaction, and also have the job destroy itself inside that transaction, like so:
|
6
|
-
|
7
|
-
```ruby
|
8
|
-
class UpdateWidgetPrice < Que::Job
|
9
|
-
def run(widget_id)
|
10
|
-
widget = Widget[widget_id]
|
11
|
-
price = ExternalService.get_widget_price(widget_id)
|
12
|
-
|
13
|
-
ActiveRecord::Base.transaction do
|
14
|
-
# Make changes to the database.
|
15
|
-
widget.update :price => price
|
16
|
-
|
17
|
-
# Destroy the job.
|
18
|
-
destroy
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
```
|
23
|
-
|
24
|
-
Here, you're taking advantage of the guarantees of an [ACID](https://en.wikipedia.org/wiki/ACID) database. The job is destroyed along with the other changes, so either the write will succeed and the job will be run only once, or it will fail and the database will be left untouched. But even if it fails, the job can simply be retried, and there are no lingering effects from the first attempt, so no big deal.
|
25
|
-
|
26
|
-
The more difficult type of job is one that makes changes that can't be controlled transactionally. For example, writing to an external service:
|
27
|
-
|
28
|
-
```ruby
|
29
|
-
class ChargeCreditCard < Que::Job
|
30
|
-
def run(user_id, credit_card_id)
|
31
|
-
CreditCardService.charge(credit_card_id, :amount => "$10.00")
|
32
|
-
|
33
|
-
ActiveRecord::Base.transaction do
|
34
|
-
User.where(:id => user_id).update_all :charged_at => Time.now
|
35
|
-
destroy
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
```
|
40
|
-
|
41
|
-
What if the process abruptly dies after we tell the provider to charge the credit card, but before we finish the transaction? Que will retry the job, but there's no way to tell where (or even if) it failed the first time. The credit card will be charged a second time, and then you've got an angry customer. The ideal solution in this case is to make the job [idempotent](https://en.wikipedia.org/wiki/Idempotence), meaning that it will have the same effect no matter how many times it is run:
|
42
|
-
|
43
|
-
```ruby
|
44
|
-
class ChargeCreditCard < Que::Job
|
45
|
-
def run(user_id, credit_card_id)
|
46
|
-
unless CreditCardService.check_for_previous_charge(credit_card_id)
|
47
|
-
CreditCardService.charge(credit_card_id, :amount => "$10.00")
|
48
|
-
end
|
49
|
-
|
50
|
-
ActiveRecord::Base.transaction do
|
51
|
-
User.where(:id => user_id).update_all :charged_at => Time.now
|
52
|
-
destroy
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
```
|
57
|
-
|
58
|
-
This makes the job slightly more complex, but reliable (or, at least, as reliable as your credit card service).
|
59
|
-
|
60
|
-
Finally, there are some jobs where you won't want to write to the database at all:
|
61
|
-
|
62
|
-
```ruby
|
63
|
-
class SendVerificationEmail < Que::Job
|
64
|
-
def run(email_address)
|
65
|
-
Mailer.verification_email(email_address).deliver
|
66
|
-
end
|
67
|
-
end
|
68
|
-
```
|
69
|
-
|
70
|
-
In this case, we don't have any no way to prevent the occasional double-sending of an email. But, for ease of use, you can leave out the transaction and the `destroy` call entirely - Que will recognize that the job wasn't destroyed and will clean it up for you.
|
71
|
-
|
72
|
-
### Timeouts
|
73
|
-
|
74
|
-
Long-running jobs aren't necessarily a problem in Que, since the overhead of an individual job isn't that big (just an open PG connection and an advisory lock held in memory). But jobs that hang indefinitely can tie up a worker and [block the Ruby process from exiting gracefully](https://github.com/chanks/que/blob/master/docs/shutting_down_safely.md), which is a pain.
|
75
|
-
|
76
|
-
Que doesn't offer a general way to kill jobs that have been running too long, because that currently can't be done safely in Ruby. Typically, one would use Ruby's Timeout module for this sort of thing, but wrapping a database transaction inside a timeout introduces a risk of premature commits, which can corrupt your data. See [here](http://blog.headius.com/2008/02/ruby-threadraise-threadkill-timeoutrb.html) and [here](http://coderrr.wordpress.com/2011/05/03/beware-of-threadkill-or-your-activerecord-transactions-are-in-danger-of-being-partially-committed/) for detail on why this is.
|
77
|
-
|
78
|
-
However, if there's part of your job that is prone to hang (due to an API call or other HTTP request that never returns, for example), you can timeout those individual parts of your job relatively safely. For example, consider a job that needs to make an HTTP request and then write to the database:
|
79
|
-
|
80
|
-
```ruby
|
81
|
-
require 'net/http'
|
82
|
-
|
83
|
-
class ScrapeStuff < Que::Job
|
84
|
-
def run(domain_to_scrape, path_to_scrape)
|
85
|
-
result = Net::HTTP.get(domain_to_scrape, path_to_scrape)
|
86
|
-
|
87
|
-
ActiveRecord::Base.transaction do
|
88
|
-
# Insert result...
|
89
|
-
|
90
|
-
destroy
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|
94
|
-
```
|
95
|
-
|
96
|
-
That request could take a very long time, or never return at all. Let's wrap it in a five-second timeout:
|
97
|
-
|
98
|
-
```ruby
|
99
|
-
require 'net/http'
|
100
|
-
require 'timeout'
|
101
|
-
|
102
|
-
class ScrapeStuff < Que::Job
|
103
|
-
def run(domain_to_scrape, path_to_scrape)
|
104
|
-
result = Timeout.timeout(5){Net::HTTP.get(domain_to_scrape, path_to_scrape)}
|
105
|
-
|
106
|
-
ActiveRecord::Base.transaction do
|
107
|
-
# Insert result...
|
108
|
-
|
109
|
-
destroy
|
110
|
-
end
|
111
|
-
end
|
112
|
-
end
|
113
|
-
```
|
114
|
-
|
115
|
-
Now, if the request takes more than five seconds, a `Timeout::Error` will be raised and Que will just retry the job later. This solution isn't perfect, since Timeout uses Thread#kill under the hood, which can lead to unpredictable behavior. But it's separate from our transaction, so there's no risk of losing data - even a catastrophic error that left Net::HTTP in a bad state would be fixable by restarting the process.
|
116
|
-
|
117
|
-
Finally, remember that if you're using a library that offers its own timeout functionality, that's usually preferable to using the Timeout module.
|
@@ -1,24 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'rails/generators'
|
4
|
-
require 'rails/generators/migration'
|
5
|
-
require 'active_record'
|
6
|
-
|
7
|
-
module Que
|
8
|
-
class InstallGenerator < Rails::Generators::Base
|
9
|
-
include Rails::Generators::Migration
|
10
|
-
|
11
|
-
namespace 'que:install'
|
12
|
-
self.source_paths << File.join(File.dirname(__FILE__), 'templates')
|
13
|
-
desc "Generates a migration to add Que's job table."
|
14
|
-
|
15
|
-
def self.next_migration_number(dirname)
|
16
|
-
next_migration_number = current_migration_number(dirname) + 1
|
17
|
-
ActiveRecord::Migration.next_migration_number(next_migration_number)
|
18
|
-
end
|
19
|
-
|
20
|
-
def create_migration_file
|
21
|
-
migration_template 'add_que.rb', 'db/migrate/add_que.rb'
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
@@ -1,13 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class AddQue < ActiveRecord::Migration
|
4
|
-
def self.up
|
5
|
-
# The current version as of this migration's creation.
|
6
|
-
Que.migrate! :version => 3
|
7
|
-
end
|
8
|
-
|
9
|
-
def self.down
|
10
|
-
# Completely removes Que's job queue.
|
11
|
-
Que.migrate! :version => 0
|
12
|
-
end
|
13
|
-
end
|
@@ -1,54 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Que
|
4
|
-
module Adapters
|
5
|
-
class ActiveRecord < Base
|
6
|
-
def checkout
|
7
|
-
checkout_activerecord_adapter { |conn| yield conn.raw_connection }
|
8
|
-
end
|
9
|
-
|
10
|
-
def wake_worker_after_commit
|
11
|
-
# Works with ActiveRecord 3.2 and 4 (possibly earlier, didn't check)
|
12
|
-
if in_transaction?
|
13
|
-
checkout_activerecord_adapter { |adapter| adapter.add_transaction_record(TransactionCallback.new) }
|
14
|
-
else
|
15
|
-
Que.wake!
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
def cleanup!
|
20
|
-
# ActiveRecord will check out connections to the current thread when
|
21
|
-
# queries are executed and not return them to the pool until
|
22
|
-
# explicitly requested to. The wisdom of this API is questionable, and
|
23
|
-
# it doesn't pose a problem for the typical case of workers using a
|
24
|
-
# single PG connection (since we ensure that connection is checked in
|
25
|
-
# and checked out responsibly), but since ActiveRecord supports
|
26
|
-
# connections to multiple databases, it's easy for people using that
|
27
|
-
# feature to unknowingly leak connections to other databases. So, take
|
28
|
-
# the additional step of telling ActiveRecord to check in all of the
|
29
|
-
# current thread's connections between jobs.
|
30
|
-
::ActiveRecord::Base.clear_active_connections!
|
31
|
-
end
|
32
|
-
|
33
|
-
class TransactionCallback
|
34
|
-
def has_transactional_callbacks?
|
35
|
-
true
|
36
|
-
end
|
37
|
-
|
38
|
-
def rolledback!(force_restore_state = false, should_run_callbacks = true)
|
39
|
-
# no-op
|
40
|
-
end
|
41
|
-
|
42
|
-
def committed!(should_run_callbacks = true)
|
43
|
-
Que.wake!
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
private
|
48
|
-
|
49
|
-
def checkout_activerecord_adapter(&block)
|
50
|
-
::ActiveRecord::Base.connection_pool.with_connection(&block)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
data/lib/que/adapters/base.rb
DELETED
@@ -1,127 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'time' # For Time.parse.
|
4
|
-
|
5
|
-
module Que
|
6
|
-
module Adapters
|
7
|
-
autoload :ActiveRecord, 'que/adapters/active_record'
|
8
|
-
autoload :ConnectionPool, 'que/adapters/connection_pool'
|
9
|
-
autoload :PG, 'que/adapters/pg'
|
10
|
-
autoload :Pond, 'que/adapters/pond'
|
11
|
-
autoload :Sequel, 'que/adapters/sequel'
|
12
|
-
|
13
|
-
class Base
|
14
|
-
def initialize(thing = nil)
|
15
|
-
@prepared_statements = {}
|
16
|
-
end
|
17
|
-
|
18
|
-
# The only method that adapters really need to implement. Should lock a
|
19
|
-
# PG::Connection (or something that acts like a PG::Connection) so that
|
20
|
-
# no other threads are using it and yield it to the block. Should also
|
21
|
-
# be re-entrant.
|
22
|
-
def checkout(&block)
|
23
|
-
raise NotImplementedError
|
24
|
-
end
|
25
|
-
|
26
|
-
# Called after Que has returned its connection to whatever pool it's
|
27
|
-
# using.
|
28
|
-
def cleanup!
|
29
|
-
end
|
30
|
-
|
31
|
-
# Called after a job is queued in async mode, to prompt a worker to
|
32
|
-
# wake up after the current transaction commits. Not all adapters will
|
33
|
-
# implement this.
|
34
|
-
def wake_worker_after_commit
|
35
|
-
false
|
36
|
-
end
|
37
|
-
|
38
|
-
def execute(command, params = [])
|
39
|
-
params = params.map do |param|
|
40
|
-
case param
|
41
|
-
# The pg gem unfortunately doesn't convert fractions of time instances, so cast them to a string.
|
42
|
-
when Time then param.strftime("%Y-%m-%d %H:%M:%S.%6N %z")
|
43
|
-
when Array, Hash then JSON_MODULE.dump(param)
|
44
|
-
else param
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
cast_result \
|
49
|
-
case command
|
50
|
-
when Symbol then execute_prepared(command, params)
|
51
|
-
when String then execute_sql(command, params)
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
def in_transaction?
|
56
|
-
checkout { |conn| conn.transaction_status != ::PG::PQTRANS_IDLE }
|
57
|
-
end
|
58
|
-
|
59
|
-
private
|
60
|
-
|
61
|
-
def execute_sql(sql, params)
|
62
|
-
args = params.empty? ? [sql] : [sql, params]
|
63
|
-
checkout { |conn| conn.async_exec(*args) }
|
64
|
-
end
|
65
|
-
|
66
|
-
def execute_prepared(name, params)
|
67
|
-
checkout do |conn|
|
68
|
-
# Prepared statement errors have the potential to foul up the entire
|
69
|
-
# transaction, so if we're in one, err on the side of safety.
|
70
|
-
return execute_sql(SQL[name], params) if Que.disable_prepared_statements || in_transaction?
|
71
|
-
|
72
|
-
statements = @prepared_statements[conn] ||= {}
|
73
|
-
|
74
|
-
begin
|
75
|
-
unless statements[name]
|
76
|
-
conn.prepare("que_#{name}", SQL[name])
|
77
|
-
prepared_just_now = statements[name] = true
|
78
|
-
end
|
79
|
-
|
80
|
-
conn.exec_prepared("que_#{name}", params)
|
81
|
-
rescue ::PG::InvalidSqlStatementName => error
|
82
|
-
# Reconnections on ActiveRecord can cause the same connection
|
83
|
-
# objects to refer to new backends, so recover as well as we can.
|
84
|
-
|
85
|
-
unless prepared_just_now
|
86
|
-
Que.log :level => 'warn', :event => "reprepare_statement", :name => name
|
87
|
-
statements[name] = false
|
88
|
-
retry
|
89
|
-
end
|
90
|
-
|
91
|
-
raise error
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
CAST_PROCS = {}
|
97
|
-
|
98
|
-
# Integer, bigint, smallint:
|
99
|
-
CAST_PROCS[23] = CAST_PROCS[20] = CAST_PROCS[21] = proc(&:to_i)
|
100
|
-
|
101
|
-
# Timestamp with time zone.
|
102
|
-
CAST_PROCS[1184] = Time.method(:parse)
|
103
|
-
|
104
|
-
# JSON.
|
105
|
-
CAST_PROCS[114] = JSON_MODULE.method(:load)
|
106
|
-
|
107
|
-
# Boolean:
|
108
|
-
CAST_PROCS[16] = 't'.method(:==)
|
109
|
-
|
110
|
-
def cast_result(result)
|
111
|
-
output = result.to_a
|
112
|
-
|
113
|
-
result.fields.each_with_index do |field, index|
|
114
|
-
if converter = CAST_PROCS[result.ftype(index)]
|
115
|
-
output.each do |hash|
|
116
|
-
unless (value = hash[field]).nil?
|
117
|
-
hash[field] = converter.call(value)
|
118
|
-
end
|
119
|
-
end
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
output.map!(&Que.json_converter)
|
124
|
-
end
|
125
|
-
end
|
126
|
-
end
|
127
|
-
end
|
data/lib/que/adapters/pg.rb
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'monitor'
|
4
|
-
|
5
|
-
module Que
|
6
|
-
module Adapters
|
7
|
-
class PG < Base
|
8
|
-
attr_reader :lock
|
9
|
-
|
10
|
-
def initialize(pg)
|
11
|
-
@pg = pg
|
12
|
-
@lock = Monitor.new # Must be re-entrant.
|
13
|
-
super
|
14
|
-
end
|
15
|
-
|
16
|
-
def checkout
|
17
|
-
@lock.synchronize { yield @pg }
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
data/lib/que/adapters/pond.rb
DELETED
data/lib/que/adapters/sequel.rb
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Que
|
4
|
-
module Adapters
|
5
|
-
class Sequel < Base
|
6
|
-
def initialize(db)
|
7
|
-
@db = db
|
8
|
-
super
|
9
|
-
end
|
10
|
-
|
11
|
-
def checkout(&block)
|
12
|
-
@db.synchronize(&block)
|
13
|
-
end
|
14
|
-
|
15
|
-
def wake_worker_after_commit
|
16
|
-
@db.after_commit { Que.wake! }
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
data/lib/que/railtie.rb
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Que
|
4
|
-
class Railtie < Rails::Railtie
|
5
|
-
config.que = Que
|
6
|
-
|
7
|
-
Que.logger = proc { Rails.logger }
|
8
|
-
Que.mode = :sync if Rails.env.test?
|
9
|
-
Que.connection = ::ActiveRecord if defined? ::ActiveRecord
|
10
|
-
Que.json_converter = :with_indifferent_access.to_proc
|
11
|
-
|
12
|
-
rake_tasks do
|
13
|
-
load 'que/rake_tasks.rb'
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
data/lib/que/rake_tasks.rb
DELETED
@@ -1,59 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
namespace :que do
|
4
|
-
desc "Process Que's jobs using a worker pool"
|
5
|
-
task :work => :environment do
|
6
|
-
$stdout.sync = true
|
7
|
-
|
8
|
-
$stdout.puts "The que:work rake task has been deprecated and will be removed in Que 1.0. Please transition to the que command line interface instead."
|
9
|
-
|
10
|
-
if defined?(::Rails) && Rails.respond_to?(:application)
|
11
|
-
# ActiveSupport's dependency autoloading isn't threadsafe, and Que uses
|
12
|
-
# multiple threads, which means that eager loading is necessary. Rails
|
13
|
-
# explicitly prevents eager loading when the environment task is invoked,
|
14
|
-
# so we need to manually eager load the app here.
|
15
|
-
Rails.application.eager_load!
|
16
|
-
end
|
17
|
-
|
18
|
-
Que.logger.level = Logger.const_get((ENV['QUE_LOG_LEVEL'] || 'INFO').upcase)
|
19
|
-
Que.worker_count = (ENV['QUE_WORKER_COUNT'] || 4).to_i
|
20
|
-
Que.wake_interval = (ENV['QUE_WAKE_INTERVAL'] || 0.1).to_f
|
21
|
-
Que.queue_name = ENV['QUE_QUEUE'] if ENV['QUE_QUEUE']
|
22
|
-
Que.mode = :async
|
23
|
-
|
24
|
-
# When changing how signals are caught, be sure to test the behavior with
|
25
|
-
# the rake task in tasks/safe_shutdown.rb.
|
26
|
-
|
27
|
-
stop = false
|
28
|
-
%w( INT TERM ).each do |signal|
|
29
|
-
trap(signal) {stop = true}
|
30
|
-
end
|
31
|
-
|
32
|
-
at_exit do
|
33
|
-
$stdout.puts "Finishing Que's current jobs before exiting..."
|
34
|
-
Que.worker_count = 0
|
35
|
-
Que.mode = :off
|
36
|
-
$stdout.puts "Que's jobs finished, exiting..."
|
37
|
-
end
|
38
|
-
|
39
|
-
loop do
|
40
|
-
sleep 0.01
|
41
|
-
break if stop
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
desc "Migrate Que's job table to the most recent version (creating it if it doesn't exist)"
|
46
|
-
task :migrate => :environment do
|
47
|
-
Que.migrate!
|
48
|
-
end
|
49
|
-
|
50
|
-
desc "Drop Que's job table"
|
51
|
-
task :drop => :environment do
|
52
|
-
Que.drop!
|
53
|
-
end
|
54
|
-
|
55
|
-
desc "Clear Que's job table"
|
56
|
-
task :clear => :environment do
|
57
|
-
Que.clear!
|
58
|
-
end
|
59
|
-
end
|