postjob 0.5.9 → 0.5.10

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e96734197915c9658e20b670186347fa9112a95a
4
- data.tar.gz: a607352a5f6675c9bb6ae80fd0f289f7142692d6
3
+ metadata.gz: 3a27daa3a8a98739c5b78fe5b74cab7fb9f8d16b
4
+ data.tar.gz: 41eab0fe1314594cbeaaa06b364e476855f7839c
5
5
  SHA512:
6
- metadata.gz: f1b8e20e7893ef1fcd3a1d53466714bcf5c106e1dec67a0745f25f29db04185c92bb7ac6e9cdf83dce299bea3f6f20cd3f6aac27c1c36551862157d902d4b1ba
7
- data.tar.gz: 0c0fe39302fa99ff9fd8fe03f70a2c81a950276cc0e6b4d86c95b96657e917da3289f176d71273d71736e2c47932aa265e9616a5b37e1df2a87d03d6fffe699d
6
+ metadata.gz: f89717293ad0920aef170e08a9fbca783e95d509c47153c2e217f9d13f445eb49725b84d349aa1e868858f4a53584f1247e3b0934ceec88ec63ff1e0e37c5f22
7
+ data.tar.gz: c600c26793d24e26f51626b0de1e7c741fe0cb11db3f85562f6308ae2184738cd82bdef7d9b8a0bdcb9841987f1b1186c37fddac89a7cc343de0adf5239f1688
@@ -6,7 +6,7 @@ module Postjob::CLI
6
6
  #
7
7
  # Note that the workflow will receive the arguments as strings and must be
8
8
  # prepared to handle these.
9
- def enqueue(workflow, *args, queue: "ruby", tags: nil)
9
+ def enqueue(workflow, *args, queue: nil, tags: nil)
10
10
  connect_to_database!
11
11
 
12
12
  Postjob.enqueue! workflow, *args, queue: queue, tags: parse_tags(tags)
@@ -6,13 +6,14 @@
6
6
  module Postjob::CLI
7
7
  private
8
8
 
9
- def ps_query(tags:, limit:)
9
+ def ps_query(tags:, limit:, queue:)
10
10
  limit = Integer(limit)
11
11
 
12
12
  sql = <<-SQL
13
13
  SELECT
14
14
  postjobs.id,
15
15
  full_id,
16
+ postjobs.queue,
16
17
  workflow
17
18
  || (CASE WHEN workflow_version != '' THEN '@' ELSE '' END)
18
19
  || workflow_version
@@ -27,7 +28,7 @@ module Postjob::CLI
27
28
  max_attempts,
28
29
  cron_interval AS cron,
29
30
  CASE
30
- WHEN is_sticky THEN COALESCE(sticky_host_id::varchar, 'yes')
31
+ WHEN is_sticky THEN COALESCE(substring(sticky_host_id::varchar for 6) || '...', 'yes')
31
32
  ELSE 'no'
32
33
  END AS sticky,
33
34
  next_run_at,
@@ -40,6 +41,7 @@ module Postjob::CLI
40
41
 
41
42
  scope = Simple::SQL::Scope.new(sql)
42
43
  scope = scope.where("tags @> ?", Postjob::Queue::Encoder.encode(parse_tags(tags))) if tags
44
+ scope = scope.where(queue: queue) if queue
43
45
 
44
46
  scope
45
47
  .paginate(per: limit, page: 1)
@@ -59,9 +61,10 @@ module Postjob::CLI
59
61
  #
60
62
  # For a listing of all jobs in the system use ps:full, see 'postjob help ps:full'
61
63
  # for details.
62
- def ps(*ids, limit: "100", tags: nil)
64
+ def ps(*ids, limit: "100", tags: nil, queue: nil)
63
65
  expect! limit => /\A\d+\z/
64
66
  limit = Integer(limit)
67
+ queue = queue.split(",") if queue
65
68
 
66
69
  connect_to_database!
67
70
 
@@ -73,16 +76,18 @@ module Postjob::CLI
73
76
  return
74
77
  end
75
78
 
76
- query = ps_query(tags: tags, limit: limit)
77
- query = query.where("root_id=id OR status NOT IN ('ready', 'sleep', 'ok') OR failed_attempts > 0")
79
+ query = ps_query(tags: tags, limit: limit, queue: queue)
80
+ query = query.where("root_id=id OR status NOT IN ('sleep', 'ok') OR failed_attempts > 0")
78
81
 
79
82
  print_results query: query
80
83
  end
81
84
 
82
- def ps_full(*ids, limit: "100", tags: nil)
85
+ def ps_full(*ids, limit: "100", tags: nil, queue: nil)
86
+ queue = queue.split(",") if queue
87
+
83
88
  connect_to_database!
84
89
 
85
- query = ps_query(tags: tags, limit: limit)
90
+ query = ps_query(tags: tags, limit: limit, queue: queue)
86
91
 
87
92
  unless ids.empty?
88
93
  parsed_ids = parse_ids(*ids)
@@ -93,13 +98,13 @@ module Postjob::CLI
93
98
  end
94
99
 
95
100
  # Show up-to-date information once per second
96
- def ps_top(*ids, limit: "100", tags: nil, full: false)
101
+ def ps_top(*ids, limit: "100", tags: nil, full: false, queue: nil)
97
102
  loop do
98
103
  system "clear"
99
104
  if full
100
- ps_full(*ids, limit: limit, tags: tags)
105
+ ps_full(*ids, limit: limit, tags: tags, queue: queue)
101
106
  else
102
- ps(*ids, limit: limit, tags: tags)
107
+ ps(*ids, limit: limit, tags: tags, queue: queue)
103
108
  end
104
109
  sleep 1
105
110
  end
@@ -11,16 +11,18 @@ module Postjob::CLI
11
11
  # Parameters:
12
12
  #
13
13
  # - count=<count> maximum number of jobs to process. Default: unlimited.
14
+ # - queue run only the specified queue.
14
15
  # - quiet don't show progress.
15
16
  #
16
- def run(count: nil, quiet: false)
17
+ def run(count: nil, queue: nil, quiet: false)
17
18
  count = Integer(count) if count
19
+ queue = queue.split(",") if queue
18
20
 
19
21
  connect_to_database!
20
22
 
21
23
  logger.success "Starting runner with pid #{$$}"
22
24
 
23
- processed = Postjob.run(count: count) do |job_id|
25
+ processed = Postjob.run(count: count, queue: queue) do |job_id|
24
26
  logger.info "Processed job w/id #{job_id}" if job_id
25
27
  STDERR.print "." unless quiet
26
28
  end
data/lib/postjob/cli.rb CHANGED
@@ -5,6 +5,8 @@ Dir.glob("#{File.dirname(__FILE__)}/cli/**/*.rb").sort.each do |path|
5
5
  load(path)
6
6
  end
7
7
 
8
+ load "config/postjob_cli.rb" if File.exist?("config/postjob_cli.rb")
9
+
8
10
  module Postjob::CLI
9
11
  include ::Simple::CLI
10
12
 
data/lib/postjob/job.rb CHANGED
@@ -32,6 +32,8 @@ class Postjob::Job < Postjob::Record
32
32
  attr_reader :timed_out
33
33
  attr_reader :tags
34
34
  attr_reader :last_worker_session_id
35
+ attr_reader :is_sticky
36
+ attr_reader :sticky_host_id
35
37
 
36
38
  STATUSES = %w(ok ready processing sleep err failed timeout)
37
39
 
@@ -1,5 +1,6 @@
1
1
  DROP FUNCTION IF EXISTS {SCHEMA_NAME}.time_to_next_job(workflows_with_versions varchar[]); -- removed in 0.5.0
2
- CREATE OR REPLACE FUNCTION {SCHEMA_NAME}.time_to_next_job(p_worker_session_id UUID)
2
+ DROP FUNCTION IF EXISTS {SCHEMA_NAME}.time_to_next_job(p_worker_session_id UUID); -- removed in 0.5.7
3
+ CREATE OR REPLACE FUNCTION {SCHEMA_NAME}.time_to_next_job(p_worker_session_id UUID, p_queue varchar[])
3
4
  RETURNS float
4
5
  AS $$
5
6
  DECLARE
@@ -17,6 +18,7 @@ BEGIN
17
18
  SELECT MIN(next_run_at) AS processable_at
18
19
  FROM {SCHEMA_NAME}.postjobs
19
20
  WHERE status IN ('ready', 'err')
21
+ AND (p_queue IS NULL OR queue = ANY (p_queue))
20
22
  AND (workflow || workflow_version) = ANY (session.workflows)
21
23
  AND COALESCE(sticky_host_id, {SCHEMA_NAME}._null_uuid()) IN (session.host_id, {SCHEMA_NAME}._null_uuid())
22
24
  ) sq;
@@ -26,7 +28,12 @@ END;
26
28
  $$ LANGUAGE plpgsql;
27
29
 
28
30
  DROP FUNCTION IF EXISTS {SCHEMA_NAME}.checkout(workflows_with_versions varchar[], p_fast_mode BOOLEAN); -- removed in 0.5.0
29
- CREATE OR REPLACE FUNCTION {SCHEMA_NAME}.checkout(p_worker_session_id UUID, p_fast_mode BOOLEAN)
31
+ DROP FUNCTION IF EXISTS {SCHEMA_NAME}.checkout(p_worker_session_id UUID, p_fast_mode BOOLEAN); -- removed in 0.5.8
32
+
33
+ CREATE OR REPLACE FUNCTION {SCHEMA_NAME}.checkout(
34
+ p_worker_session_id UUID,
35
+ p_fast_mode BOOLEAN,
36
+ p_queue varchar[])
30
37
  RETURNS SETOF {SCHEMA_NAME}.postjobs
31
38
  AS $$
32
39
  DECLARE
@@ -52,8 +59,9 @@ BEGIN
52
59
  AND s.next_run_at <= (now() at time zone 'utc')
53
60
  AND (s.workflow || s.workflow_version) = ANY (session.workflows)
54
61
  AND COALESCE(s.sticky_host_id, {SCHEMA_NAME}._null_uuid()) IN (session.host_id, {SCHEMA_NAME}._null_uuid())
62
+ AND (p_queue IS NULL OR queue = ANY (p_queue))
55
63
  )
56
- ORDER BY (LEAST(s.next_run_at, s.timing_out_at))
64
+ ORDER BY (LEAST(CASE WHEN s.sticky_host_id IS NOT NULL THEN s.next_run_at - interval '180 seconds' ELSE s.next_run_at END, s.timing_out_at))
57
65
  FOR UPDATE SKIP LOCKED
58
66
  LIMIT 1;
59
67
 
@@ -8,14 +8,14 @@ module Postjob::Queue::Notifications
8
8
  SCHEMA_NAME = ::Postjob::Queue::SCHEMA_NAME
9
9
  MAX_WAIT_TIME = 120
10
10
 
11
- def wait_for_new_job(worker_session_id)
11
+ def wait_for_new_job(worker_session_id, queue:)
12
12
  started_at = Time.now
13
13
 
14
14
  start_listening
15
15
 
16
16
  # Determine when the next job is up. If we don't have a next job within MAX_WAIT_TIME
17
17
  # we wake up regardless.
18
- wait_time = time_to_next_job(worker_session_id)
18
+ wait_time = time_to_next_job(worker_session_id, queue: queue)
19
19
  return if wait_time && wait_time <= 0
20
20
 
21
21
  wait_time = MAX_WAIT_TIME if !wait_time || wait_time > MAX_WAIT_TIME
@@ -43,8 +43,11 @@ module Postjob::Queue::Notifications
43
43
 
44
44
  # returns the maximum number of seconds to wait until the
45
45
  # next runnable or timeoutable job comes up.
46
- def time_to_next_job(worker_session_id)
46
+ def time_to_next_job(worker_session_id, queue:)
47
47
  expect! worker_session_id => /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/i
48
- Simple::SQL.ask "SELECT * FROM #{SCHEMA_NAME}.time_to_next_job($1::uuid)", worker_session_id
48
+ expect! queue => [ String, Array, nil ]
49
+
50
+ queue = Array(queue)
51
+ Simple::SQL.ask "SELECT * FROM #{SCHEMA_NAME}.time_to_next_job($1::uuid, $2)", worker_session_id, queue
49
52
  end
50
53
  end
data/lib/postjob/queue.rb CHANGED
@@ -157,9 +157,14 @@ module Postjob::Queue
157
157
 
158
158
  UUID_REGEXP = /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/i
159
159
 
160
- def checkout(worker_session_id)
160
+ def checkout(worker_session_id, queue:)
161
161
  expect! worker_session_id => UUID_REGEXP
162
- SQL.ask "SELECT * FROM #{SCHEMA_NAME}.checkout($1::uuid, $2::boolean)", worker_session_id, Postjob.fast_mode, into: Job
162
+ expect! queue => [ nil, Array, String ]
163
+
164
+ queue = Array(queue) if queue
165
+
166
+ SQL.ask "SELECT * FROM #{SCHEMA_NAME}.checkout($1::uuid, $2::boolean, $3)",
167
+ worker_session_id, Postjob.fast_mode, queue, into: Job
163
168
  end
164
169
 
165
170
  def find_or_create_token(job)
@@ -42,7 +42,7 @@ class Postjob::Registry
42
42
  timeout: 15 * 60,
43
43
  sticky: false,
44
44
  cron_interval: nil,
45
- queue: "q"
45
+ queue: "ruby"
46
46
  }
47
47
 
48
48
  attr_reader :version
@@ -35,9 +35,11 @@ module Postjob::Runner
35
35
 
36
36
  # returns a subjob within the current job, for a +runner+
37
37
  # description and +args+.
38
- def async(workflow, *args, timeout: nil, max_attempts:)
38
+ def async(workflow, *args, timeout: nil, max_attempts: nil, queue: nil)
39
39
  worker_session_id = Postjob.current_worker_session.id
40
40
 
41
+ queue = current_job.queue if queue.nil?
42
+
41
43
  # if the workflow is a symbol, then we change it into "__manual__"
42
44
  # - there should never be a workflow with that name - or into
43
45
  # "CurrentWorkshop.#{workflow}", denoting the \a workflow method of the
@@ -52,12 +54,13 @@ module Postjob::Runner
52
54
  end
53
55
 
54
56
  ::Postjob::Queue.find_or_create_childjob(worker_session_id, self.current_job, workflow, args,
57
+ queue: queue,
55
58
  timeout: timeout,
56
59
  max_attempts: max_attempts)
57
60
  end
58
61
 
59
62
  # tries to resolve a job.
60
- def await(job, *args, timeout: nil, max_attempts: nil)
63
+ def await(job, *args, timeout: nil, max_attempts: nil, queue: nil)
61
64
  case job
62
65
  when :all
63
66
  unresolved_childjobs = Postjob::Queue.unresolved_childjobs(current_job)
@@ -75,7 +78,7 @@ module Postjob::Runner
75
78
  throw :pending, :pending if r == :pending
76
79
  r
77
80
  else
78
- job = async(job, *args, timeout: timeout, max_attempts: max_attempts)
81
+ job = async(job, *args, timeout: timeout, max_attempts: max_attempts, queue: queue)
79
82
  await(job)
80
83
  end
81
84
  end
@@ -15,8 +15,8 @@ module Postjob::Workflow
15
15
  # we cannot run such a test.
16
16
 
17
17
  # see Postjob::Runner.async
18
- def async(runner, *args, timeout: nil, max_attempts: nil)
19
- ::Postjob::Runner.async(runner, *args, timeout: timeout, max_attempts: max_attempts)
18
+ def async(runner, *args, timeout: nil, max_attempts: nil, queue: nil)
19
+ ::Postjob::Runner.async(runner, *args, timeout: timeout, max_attempts: max_attempts, queue: queue)
20
20
  end
21
21
 
22
22
  # see Postjob::Runner.await
data/lib/postjob.rb CHANGED
@@ -49,6 +49,8 @@ module Postjob
49
49
  # - cron_interval
50
50
  # - queue
51
51
  #
52
+ #
53
+ # Returns a job id
52
54
  def enqueue!(workflow, *args, queue: nil,
53
55
  parent_id: nil,
54
56
  max_attempts: nil,
@@ -156,7 +158,7 @@ module Postjob
156
158
  # b) the block yielded into returns false.
157
159
  #
158
160
  # This method returns the number of processed jobs.
159
- def run(count: nil, &block)
161
+ def run(count: nil, queue: nil, &block)
160
162
  # to run 10^12 jobs that would take 1 msecs each we would need, at least,
161
163
  # 760 years - so this default should be fine. Also, someone should update
162
164
  # the machine in the meantime :)
@@ -165,7 +167,7 @@ module Postjob
165
167
  processed_jobs_count = 0
166
168
 
167
169
  loop do
168
- processed_job_id, shutdown = Postjob.step
170
+ processed_job_id, shutdown = Postjob.step(queue: queue)
169
171
  processed_jobs_count += 1 if processed_job_id
170
172
 
171
173
  break if processed_jobs_count >= count
@@ -173,7 +175,7 @@ module Postjob
173
175
  break if shutdown == :shutdown
174
176
 
175
177
  next if processed_job_id
176
- Queue::Notifications.wait_for_new_job(current_worker_session.id)
178
+ Queue::Notifications.wait_for_new_job(current_worker_session.id, queue: queue)
177
179
  end
178
180
 
179
181
  processed_jobs_count
@@ -191,8 +193,9 @@ module Postjob
191
193
  # self.run to terminate the run loop.
192
194
  #
193
195
  # or nil, when no job could be checked out.
194
- def step
195
- job = Postjob::Queue.checkout(current_worker_session.id)
196
+ def step(queue: nil)
197
+ job = Postjob::Queue.checkout(current_worker_session.id, queue: queue)
198
+
196
199
  [ job.id, process_job(job) ] if job
197
200
  end
198
201
 
@@ -251,6 +254,7 @@ module Postjob
251
254
  def process_job(job) # :nodoc:
252
255
  expect! job => Job
253
256
 
257
+ # ap job
254
258
  version, status, value, shutdown = Runner.process_job(job)
255
259
 
256
260
  expect! version => String
@@ -268,6 +272,23 @@ module Postjob
268
272
  else raise ArgumentError, "Invalid status #{status.inspect}"
269
273
  end
270
274
 
275
+ if (status == :ok || status == :failed) && job.workflow_method == "run"
276
+ Simple::SQL.transaction do
277
+ job_id = enqueue! "#{job.workflow}.cleanup", *job.args, queue: job.queue,
278
+ parent_id: nil,
279
+ max_attempts: nil,
280
+ timeout: nil,
281
+ version: version,
282
+ tags: job.tags,
283
+ cron_interval: nil,
284
+ sticky: job.is_sticky
285
+
286
+ if job.is_sticky
287
+ Simple::SQL.ask "UPDATE postjob.postjobs SET sticky_host_id=$1 WHERE id=$2", job.sticky_host_id, job_id
288
+ end
289
+ end
290
+ end
291
+
271
292
  shutdown
272
293
  end
273
294
  end
@@ -53,10 +53,10 @@ describe "Postjob.enqueue!" do
53
53
  expect(job2.args).to eq([])
54
54
  end
55
55
 
56
- it "sets queue" do
56
+ it "sets the queue to the default queue name ('ruby')" do
57
57
  id1 = Postjob.enqueue! workflow_name
58
58
  job1 = load_job id1
59
- expect(job1.queue).to eq("q")
59
+ expect(job1.queue).to eq("ruby")
60
60
 
61
61
  id1 = Postjob.enqueue! workflow_name, queue: "bla"
62
62
  job1 = load_job id1
@@ -82,8 +82,8 @@ describe "Postjob.enqueue!" do
82
82
 
83
83
  context "with invalid arguments" do
84
84
  it "raises an error with missing args" do
85
- expect { Postjob.enqueue! queue: "q" }.to raise_error(ArgumentError)
86
- expect { Postjob.enqueue! workflow: "q" }.to raise_error(ArgumentError)
85
+ expect { Postjob.enqueue! queue: "ruby" }.to raise_error(ArgumentError)
86
+ expect { Postjob.enqueue! workflow: "ruby" }.to raise_error(ArgumentError)
87
87
  end
88
88
 
89
89
  it "raises an error with invalid args" do
@@ -23,7 +23,7 @@ describe "Postjob.process_all" do
23
23
  let!(:id) { Postjob.enqueue! "TwoLevelWorkflow" }
24
24
 
25
25
  it "runs the job returning the result" do
26
- expect(Postjob.process_all).to eq(3)
26
+ expect(Postjob.process_all).to eq(5)
27
27
  processed_job = load_job(id)
28
28
  expect(processed_job.status).to eq("ok")
29
29
  expect(processed_job.resolve).to eq("my string")
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: postjob
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.9
4
+ version: 0.5.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - radiospiel