que 1.3.0 → 2.0.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/.github/workflows/tests.yml +16 -8
- data/.ruby-version +1 -0
- data/CHANGELOG.md +433 -527
- data/Dockerfile +1 -1
- data/README.md +14 -10
- data/bin/command_line_interface.rb +4 -5
- data/docker-compose.yml +3 -2
- data/docs/README.md +127 -58
- data/lib/que/active_job/extensions.rb +46 -29
- data/lib/que/active_record/model.rb +2 -2
- data/lib/que/connection.rb +1 -1
- data/lib/que/job.rb +14 -32
- data/lib/que/job_buffer.rb +1 -10
- data/lib/que/job_methods.rb +6 -2
- data/lib/que/locker.rb +0 -4
- data/lib/que/migrations/6/down.sql +8 -0
- data/lib/que/migrations/6/up.sql +8 -0
- data/lib/que/migrations.rb +1 -1
- data/lib/que/poller.rb +8 -3
- data/lib/que/sequel/model.rb +5 -2
- data/lib/que/utils/ruby2_keywords.rb +19 -0
- data/lib/que/version.rb +2 -2
- data/lib/que/worker.rb +1 -1
- data/lib/que.rb +4 -1
- data/que.gemspec +2 -0
- metadata +8 -4
data/lib/que/job.rb
CHANGED
|
@@ -12,7 +12,7 @@ module Que
|
|
|
12
12
|
SQL[:insert_job] =
|
|
13
13
|
%{
|
|
14
14
|
INSERT INTO public.que_jobs
|
|
15
|
-
(queue, priority, run_at, job_class, args, data, job_schema_version)
|
|
15
|
+
(queue, priority, run_at, job_class, args, kwargs, data, job_schema_version)
|
|
16
16
|
VALUES
|
|
17
17
|
(
|
|
18
18
|
coalesce($1, 'default')::text,
|
|
@@ -21,6 +21,7 @@ module Que
|
|
|
21
21
|
$4::text,
|
|
22
22
|
coalesce($5, '[]')::jsonb,
|
|
23
23
|
coalesce($6, '{}')::jsonb,
|
|
24
|
+
coalesce($7, '{}')::jsonb,
|
|
24
25
|
#{Que.job_schema_version}
|
|
25
26
|
)
|
|
26
27
|
RETURNING *
|
|
@@ -56,13 +57,10 @@ module Que
|
|
|
56
57
|
:priority,
|
|
57
58
|
:run_at
|
|
58
59
|
|
|
59
|
-
def enqueue(
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
)
|
|
64
|
-
arg_opts, job_options = _extract_job_options(arg_opts, job_options.dup)
|
|
65
|
-
args << arg_opts if arg_opts.any?
|
|
60
|
+
def enqueue(*args)
|
|
61
|
+
args, kwargs = Que.split_out_ruby2_keywords(args)
|
|
62
|
+
|
|
63
|
+
job_options = kwargs.delete(:job_options) || {}
|
|
66
64
|
|
|
67
65
|
if job_options[:tags]
|
|
68
66
|
if job_options[:tags].length > MAXIMUM_TAGS_COUNT
|
|
@@ -81,6 +79,7 @@ module Que
|
|
|
81
79
|
priority: job_options[:priority] || resolve_que_setting(:priority),
|
|
82
80
|
run_at: job_options[:run_at] || resolve_que_setting(:run_at),
|
|
83
81
|
args: Que.serialize_json(args),
|
|
82
|
+
kwargs: Que.serialize_json(kwargs),
|
|
84
83
|
data: job_options[:tags] ? Que.serialize_json(tags: job_options[:tags]) : "{}",
|
|
85
84
|
job_class: \
|
|
86
85
|
job_options[:job_class] || name ||
|
|
@@ -89,27 +88,31 @@ module Que
|
|
|
89
88
|
|
|
90
89
|
if attrs[:run_at].nil? && resolve_que_setting(:run_synchronously)
|
|
91
90
|
attrs[:args] = Que.deserialize_json(attrs[:args])
|
|
91
|
+
attrs[:kwargs] = Que.deserialize_json(attrs[:kwargs])
|
|
92
92
|
attrs[:data] = Que.deserialize_json(attrs[:data])
|
|
93
93
|
_run_attrs(attrs)
|
|
94
94
|
else
|
|
95
95
|
values =
|
|
96
96
|
Que.execute(
|
|
97
97
|
:insert_job,
|
|
98
|
-
attrs.values_at(:queue, :priority, :run_at, :job_class, :args, :data),
|
|
98
|
+
attrs.values_at(:queue, :priority, :run_at, :job_class, :args, :kwargs, :data),
|
|
99
99
|
).first
|
|
100
|
-
|
|
101
100
|
new(values)
|
|
102
101
|
end
|
|
103
102
|
end
|
|
103
|
+
ruby2_keywords(:enqueue) if respond_to?(:ruby2_keywords, true)
|
|
104
104
|
|
|
105
105
|
def run(*args)
|
|
106
106
|
# Make sure things behave the same as they would have with a round-trip
|
|
107
107
|
# to the DB.
|
|
108
|
+
args, kwargs = Que.split_out_ruby2_keywords(args)
|
|
108
109
|
args = Que.deserialize_json(Que.serialize_json(args))
|
|
110
|
+
kwargs = Que.deserialize_json(Que.serialize_json(kwargs))
|
|
109
111
|
|
|
110
112
|
# Should not fail if there's no DB connection.
|
|
111
|
-
_run_attrs(args: args)
|
|
113
|
+
_run_attrs(args: args, kwargs: kwargs)
|
|
112
114
|
end
|
|
115
|
+
ruby2_keywords(:run) if respond_to?(:ruby2_keywords, true)
|
|
113
116
|
|
|
114
117
|
def resolve_que_setting(setting, *args)
|
|
115
118
|
value = send(setting) if respond_to?(setting)
|
|
@@ -136,27 +139,6 @@ module Que
|
|
|
136
139
|
end
|
|
137
140
|
end
|
|
138
141
|
end
|
|
139
|
-
|
|
140
|
-
def _extract_job_options(arg_opts, job_options)
|
|
141
|
-
deprecated_job_option_names = []
|
|
142
|
-
|
|
143
|
-
%i[queue priority run_at job_class tags].each do |option_name|
|
|
144
|
-
next unless arg_opts.key?(option_name) && job_options[option_name].nil?
|
|
145
|
-
|
|
146
|
-
job_options[option_name] = arg_opts.delete(option_name)
|
|
147
|
-
deprecated_job_option_names << option_name
|
|
148
|
-
end
|
|
149
|
-
|
|
150
|
-
_log_job_options_deprecation(deprecated_job_option_names)
|
|
151
|
-
|
|
152
|
-
[arg_opts, job_options]
|
|
153
|
-
end
|
|
154
|
-
|
|
155
|
-
def _log_job_options_deprecation(deprecated_job_option_names)
|
|
156
|
-
return unless deprecated_job_option_names.any?
|
|
157
|
-
|
|
158
|
-
warn "Passing job options like (#{deprecated_job_option_names.join(', ')}) to `JobClass.enqueue` as top level keyword args has been deprecated and will be removed in version 2.0. Please wrap job options in an explicit `job_options` keyword arg instead."
|
|
159
|
-
end
|
|
160
142
|
end
|
|
161
143
|
|
|
162
144
|
# Set up some defaults.
|
data/lib/que/job_buffer.rb
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
module Que
|
|
8
8
|
class JobBuffer
|
|
9
|
-
attr_reader :maximum_size, :
|
|
9
|
+
attr_reader :maximum_size, :priority_queues
|
|
10
10
|
|
|
11
11
|
# Since we use a mutex, which is not reentrant, we have to be a little
|
|
12
12
|
# careful to not call a method that locks the mutex when we've already
|
|
@@ -17,20 +17,11 @@ module Que
|
|
|
17
17
|
|
|
18
18
|
def initialize(
|
|
19
19
|
maximum_size:,
|
|
20
|
-
minimum_size:,
|
|
21
20
|
priorities:
|
|
22
21
|
)
|
|
23
22
|
@maximum_size = Que.assert(Integer, maximum_size)
|
|
24
23
|
Que.assert(maximum_size >= 0) { "maximum_size for a JobBuffer must be at least zero!" }
|
|
25
24
|
|
|
26
|
-
@minimum_size = Que.assert(Integer, minimum_size)
|
|
27
|
-
Que.assert(minimum_size >= 0) { "minimum_size for a JobBuffer must be at least zero!" }
|
|
28
|
-
|
|
29
|
-
Que.assert(minimum_size <= maximum_size) do
|
|
30
|
-
"minimum buffer size (#{minimum_size}) is " \
|
|
31
|
-
"greater than the maximum buffer size (#{maximum_size})!"
|
|
32
|
-
end
|
|
33
|
-
|
|
34
25
|
@stop = false
|
|
35
26
|
@array = []
|
|
36
27
|
@mutex = Mutex.new
|
data/lib/que/job_methods.rb
CHANGED
|
@@ -39,12 +39,16 @@ module Que
|
|
|
39
39
|
# Run the job with error handling and cleanup logic. Optionally support
|
|
40
40
|
# overriding the args, because it's necessary when jobs are invoked from
|
|
41
41
|
# ActiveJob.
|
|
42
|
-
def _run(args: nil, reraise_errors: false)
|
|
42
|
+
def _run(args: nil, kwargs: nil, reraise_errors: false)
|
|
43
43
|
if args.nil? && que_target
|
|
44
44
|
args = que_target.que_attrs.fetch(:args)
|
|
45
45
|
end
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
if kwargs.nil? && que_target
|
|
48
|
+
kwargs = que_target.que_attrs.fetch(:kwargs)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
run(*args, **kwargs)
|
|
48
52
|
default_resolve_action if que_target && !que_target.que_resolved
|
|
49
53
|
rescue => error
|
|
50
54
|
raise error unless que_target
|
data/lib/que/locker.rb
CHANGED
|
@@ -45,7 +45,6 @@ module Que
|
|
|
45
45
|
|
|
46
46
|
DEFAULT_POLL_INTERVAL = 5.0
|
|
47
47
|
DEFAULT_WAIT_PERIOD = 50
|
|
48
|
-
DEFAULT_MINIMUM_BUFFER_SIZE = 2
|
|
49
48
|
DEFAULT_MAXIMUM_BUFFER_SIZE = 8
|
|
50
49
|
DEFAULT_WORKER_PRIORITIES = [10, 30, 50, nil, nil, nil].freeze
|
|
51
50
|
|
|
@@ -57,7 +56,6 @@ module Que
|
|
|
57
56
|
poll_interval: DEFAULT_POLL_INTERVAL,
|
|
58
57
|
wait_period: DEFAULT_WAIT_PERIOD,
|
|
59
58
|
maximum_buffer_size: DEFAULT_MAXIMUM_BUFFER_SIZE,
|
|
60
|
-
minimum_buffer_size: DEFAULT_MINIMUM_BUFFER_SIZE,
|
|
61
59
|
worker_priorities: DEFAULT_WORKER_PRIORITIES,
|
|
62
60
|
on_worker_start: nil
|
|
63
61
|
)
|
|
@@ -77,7 +75,6 @@ module Que
|
|
|
77
75
|
# ResultQueue to receive messages from workers.
|
|
78
76
|
@job_buffer = JobBuffer.new(
|
|
79
77
|
maximum_size: maximum_buffer_size,
|
|
80
|
-
minimum_size: minimum_buffer_size,
|
|
81
78
|
priorities: worker_priorities.uniq,
|
|
82
79
|
)
|
|
83
80
|
|
|
@@ -93,7 +90,6 @@ module Que
|
|
|
93
90
|
poll_interval: poll_interval,
|
|
94
91
|
wait_period: wait_period,
|
|
95
92
|
maximum_buffer_size: maximum_buffer_size,
|
|
96
|
-
minimum_buffer_size: minimum_buffer_size,
|
|
97
93
|
worker_priorities: worker_priorities,
|
|
98
94
|
}
|
|
99
95
|
end
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
DROP INDEX que_jobs_kwargs_gin_idx;
|
|
2
|
+
ALTER TABLE que_jobs DROP COLUMN kwargs;
|
|
3
|
+
|
|
4
|
+
ALTER INDEX que_poll_idx RENAME TO que_poll_idx_with_job_schema_version;
|
|
5
|
+
CREATE INDEX que_poll_idx ON que_jobs (queue, priority, run_at, id) WHERE (finished_at IS NULL AND expired_at IS NULL);
|
|
6
|
+
|
|
7
|
+
ALTER TABLE que_jobs ALTER COLUMN job_schema_version SET DEFAULT 1;
|
|
8
|
+
ALTER TABLE que_jobs ALTER COLUMN job_schema_version DROP NOT NULL;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
ALTER TABLE que_jobs ADD COLUMN kwargs JSONB NOT NULL DEFAULT '{}';
|
|
2
|
+
CREATE INDEX que_jobs_kwargs_gin_idx ON que_jobs USING gin (kwargs jsonb_path_ops);
|
|
3
|
+
|
|
4
|
+
DROP INDEX que_poll_idx;
|
|
5
|
+
ALTER INDEX que_poll_idx_with_job_schema_version RENAME TO que_poll_idx;
|
|
6
|
+
|
|
7
|
+
ALTER TABLE que_jobs ALTER COLUMN job_schema_version DROP DEFAULT;
|
|
8
|
+
ALTER TABLE que_jobs ALTER COLUMN job_schema_version SET NOT NULL;
|
data/lib/que/migrations.rb
CHANGED
data/lib/que/poller.rb
CHANGED
|
@@ -146,8 +146,6 @@ module Que
|
|
|
146
146
|
|
|
147
147
|
return unless should_poll?
|
|
148
148
|
|
|
149
|
-
expected_count = priorities.inject(0){|s,(_,c)| s + c}
|
|
150
|
-
|
|
151
149
|
jobs =
|
|
152
150
|
connection.execute_prepared(
|
|
153
151
|
:poll_jobs,
|
|
@@ -159,7 +157,7 @@ module Que
|
|
|
159
157
|
)
|
|
160
158
|
|
|
161
159
|
@last_polled_at = Time.now
|
|
162
|
-
@last_poll_satisfied =
|
|
160
|
+
@last_poll_satisfied = poll_satisfied?(priorities, jobs)
|
|
163
161
|
|
|
164
162
|
Que.internal_log :poller_polled, self do
|
|
165
163
|
{
|
|
@@ -265,5 +263,12 @@ module Que
|
|
|
265
263
|
SQL
|
|
266
264
|
end
|
|
267
265
|
end
|
|
266
|
+
|
|
267
|
+
private
|
|
268
|
+
|
|
269
|
+
def poll_satisfied?(priorities, jobs)
|
|
270
|
+
lowest_priority = priorities.keys.max
|
|
271
|
+
jobs.count >= priorities[lowest_priority]
|
|
272
|
+
end
|
|
268
273
|
end
|
|
269
274
|
end
|
data/lib/que/sequel/model.rb
CHANGED
|
@@ -40,8 +40,11 @@ module Que
|
|
|
40
40
|
where(QUALIFIED_TABLE[:data].pg_jsonb.contains(JSON.dump(tags: [tag])))
|
|
41
41
|
end
|
|
42
42
|
|
|
43
|
-
def by_args(*args)
|
|
44
|
-
where(
|
|
43
|
+
def by_args(*args, **kwargs)
|
|
44
|
+
where(
|
|
45
|
+
QUALIFIED_TABLE[:args].pg_jsonb.contains(JSON.dump(args)) &
|
|
46
|
+
QUALIFIED_TABLE[:kwargs].pg_jsonb.contains(JSON.dump(kwargs))
|
|
47
|
+
)
|
|
45
48
|
end
|
|
46
49
|
end
|
|
47
50
|
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Temporary module allowing ruby2 keyword args to be extracted from an *args splat
|
|
4
|
+
# Allows us to ensure consistent behaviour when running on ruby 2 vs ruby 3
|
|
5
|
+
# We can remove this if/when we drop support for ruby 2
|
|
6
|
+
|
|
7
|
+
require 'json'
|
|
8
|
+
|
|
9
|
+
module Que
|
|
10
|
+
module Utils
|
|
11
|
+
module Ruby2Keywords
|
|
12
|
+
def split_out_ruby2_keywords(args)
|
|
13
|
+
return [args, {}] unless args.last&.is_a?(Hash) && Hash.ruby2_keywords_hash?(args.last)
|
|
14
|
+
|
|
15
|
+
[args[0..-2], args.last]
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
data/lib/que/version.rb
CHANGED
data/lib/que/worker.rb
CHANGED
data/lib/que.rb
CHANGED
|
@@ -29,8 +29,11 @@ module Que
|
|
|
29
29
|
require_relative 'que/utils/logging'
|
|
30
30
|
require_relative 'que/utils/middleware'
|
|
31
31
|
require_relative 'que/utils/queue_management'
|
|
32
|
+
require_relative 'que/utils/ruby2_keywords'
|
|
32
33
|
require_relative 'que/utils/transactions'
|
|
33
34
|
|
|
35
|
+
require_relative 'que/version'
|
|
36
|
+
|
|
34
37
|
require_relative 'que/connection'
|
|
35
38
|
require_relative 'que/connection_pool'
|
|
36
39
|
require_relative 'que/job_methods'
|
|
@@ -41,7 +44,6 @@ module Que
|
|
|
41
44
|
require_relative 'que/migrations'
|
|
42
45
|
require_relative 'que/poller'
|
|
43
46
|
require_relative 'que/result_queue'
|
|
44
|
-
require_relative 'que/version'
|
|
45
47
|
require_relative 'que/worker'
|
|
46
48
|
|
|
47
49
|
class << self
|
|
@@ -60,6 +62,7 @@ module Que
|
|
|
60
62
|
include Utils::Logging
|
|
61
63
|
include Utils::Middleware
|
|
62
64
|
include Utils::QueueManagement
|
|
65
|
+
include Utils::Ruby2Keywords
|
|
63
66
|
include Utils::Transactions
|
|
64
67
|
|
|
65
68
|
extend Forwardable
|
data/que.gemspec
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: que
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 2.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Chris Hanks
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2022-
|
|
11
|
+
date: 2022-08-25 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
@@ -34,6 +34,7 @@ extra_rdoc_files: []
|
|
|
34
34
|
files:
|
|
35
35
|
- ".github/workflows/tests.yml"
|
|
36
36
|
- ".gitignore"
|
|
37
|
+
- ".ruby-version"
|
|
37
38
|
- CHANGELOG.md
|
|
38
39
|
- Dockerfile
|
|
39
40
|
- LICENSE.txt
|
|
@@ -71,6 +72,8 @@ files:
|
|
|
71
72
|
- lib/que/migrations/4/up.sql
|
|
72
73
|
- lib/que/migrations/5/down.sql
|
|
73
74
|
- lib/que/migrations/5/up.sql
|
|
75
|
+
- lib/que/migrations/6/down.sql
|
|
76
|
+
- lib/que/migrations/6/up.sql
|
|
74
77
|
- lib/que/poller.rb
|
|
75
78
|
- lib/que/rails/railtie.rb
|
|
76
79
|
- lib/que/result_queue.rb
|
|
@@ -84,6 +87,7 @@ files:
|
|
|
84
87
|
- lib/que/utils/logging.rb
|
|
85
88
|
- lib/que/utils/middleware.rb
|
|
86
89
|
- lib/que/utils/queue_management.rb
|
|
90
|
+
- lib/que/utils/ruby2_keywords.rb
|
|
87
91
|
- lib/que/utils/transactions.rb
|
|
88
92
|
- lib/que/version.rb
|
|
89
93
|
- lib/que/worker.rb
|
|
@@ -102,14 +106,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
102
106
|
requirements:
|
|
103
107
|
- - ">="
|
|
104
108
|
- !ruby/object:Gem::Version
|
|
105
|
-
version:
|
|
109
|
+
version: 2.7.0
|
|
106
110
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
107
111
|
requirements:
|
|
108
112
|
- - ">="
|
|
109
113
|
- !ruby/object:Gem::Version
|
|
110
114
|
version: '0'
|
|
111
115
|
requirements: []
|
|
112
|
-
rubygems_version: 3.3.
|
|
116
|
+
rubygems_version: 3.3.7
|
|
113
117
|
signing_key:
|
|
114
118
|
specification_version: 4
|
|
115
119
|
summary: A PostgreSQL-based Job Queue
|