postjob 0.5.9 → 0.5.10

Sign up to get free protection for your applications and to get access to all the features.
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