postjob 0.4.2 → 0.4.3

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: 79193eb5de0de5ad5a9de485fd40378c66907c22
4
- data.tar.gz: 252abc25bfdb766849168de4bef806c5938d9983
3
+ metadata.gz: 0be2321073faba782e89878c47c6c6770b97e7ff
4
+ data.tar.gz: c9d3cf35e02a4105587d5888535e4297d4abb9af
5
5
  SHA512:
6
- metadata.gz: 458b190937d133249530d48d6cc16d96f94c8ced9af36d944e1c71144112045849ea04fdd348346b9dd419106eae4a189a3acd1b6c966fea5c543d7474261d8f
7
- data.tar.gz: 6d7e015d27c697b26bd8aa39d045e1efaada633fcd1b2db11a0acdb83c48a69e8e77ab7313bd98e26a1db3412a9107b3f3ca36e4e17a091fae68d0cd2d103579
6
+ metadata.gz: 208afca0daf608d1ada39ad4fac5539e2ad10388d73e469bc4164eee2f49c4615a0e845578dd1aad5db6fe33f0decdef62c0329b198fa4f44f2e9941363eb2e7
7
+ data.tar.gz: 11a854fb585336169a6b218884d8b02503c5e52503efac95609b937dc18dd51703868f93a569f3fb66b557c411215bf9ecf797f5ddd33a4781a750092676855f
@@ -18,20 +18,27 @@ module Postjob::CLI
18
18
  || workflow_version
19
19
  || (CASE WHEN workflow_method != 'run' THEN '.' || workflow_method ELSE '' END)
20
20
  || args AS job,
21
- workflow_status AS status,
22
- status,
21
+ CASE
22
+ WHEN (status = 'err') THEN 'err(' || failed_attempts || '/' || max_attempts || ')'
23
+ ELSE status::varchar
24
+ END AS status,
23
25
  error,
24
26
  COALESCE((results->0)::varchar, error_message) AS result,
25
27
  next_run_at,
26
28
  next_run_at - (now() at time zone 'utc') AS next_run_in,
27
29
  to_char(EXTRACT(EPOCH FROM (now() at time zone 'utc') - postjobs.created_at), '999999999.99') AS age,
28
- CASE WHEN processing_started_at IS NOT NULL THEN
29
- format(
30
- '%s/%s',
31
- to_char(EXTRACT(EPOCH FROM (now() at time zone 'utc') - processing_started_at), '999999999.99'),
32
- processing_max_duration
33
- )
30
+
31
+ CASE
32
+ WHEN processing_started_at IS NOT NULL THEN
33
+ format(
34
+ '%s/%s',
35
+ to_char(EXTRACT(EPOCH FROM (now() at time zone 'utc') - processing_started_at), '999999999.99'),
36
+ processing_max_duration
37
+ )
38
+ WHEN status IN ('failed', 'err', 'ok') THEN
39
+ format('%s', to_char(EXTRACT(EPOCH FROM (updated_at - created_at)), '999999999.99'))
34
40
  END AS processing,
41
+
35
42
  COALESCE(processing_client, '') || COALESCE('/' || processing_client_identifier, '') AS worker,
36
43
  tags
37
44
  FROM postjob.postjobs AS postjobs
@@ -11,12 +11,10 @@ module Postjob::CLI
11
11
  # Parameters:
12
12
  #
13
13
  # - count=<count> maximum number of jobs to process. Default: unlimited.
14
- # - fast=<count> reduce waiting time after error (for development only!)
15
14
  # - quiet don't show progress.
16
15
  #
17
- def run(count: nil, fast: false, quiet: false)
16
+ def run(count: nil, quiet: false)
18
17
  count = Integer(count) if count
19
- Postjob.fast_mode = fast
20
18
 
21
19
  connect_to_database!
22
20
 
data/lib/postjob/error.rb CHANGED
@@ -1,16 +1,31 @@
1
1
  module Postjob
2
2
  class Error < RuntimeError
3
- def initialize(job)
4
- @job = job
3
+ attr_reader :message
4
+
5
+ def initialize(err)
6
+ case err
7
+ when ::Postjob::Job then @message = job_error_msg(err)
8
+ when nil, false then @message = self.class.name
9
+ else @message = err.to_s
10
+ end
11
+ end
12
+
13
+ def to_s
14
+ message
5
15
  end
6
16
 
7
- def message
8
- msg = "Failing child job"
9
- msg += " [#{@job.result}]" if @job.result
10
- msg
17
+ private
18
+
19
+ def job_error_msg(job)
20
+ error_msg = "Failing child job"
21
+ error_msg += " [#{job.result}]" if job.result
22
+ error_msg
11
23
  end
12
24
  end
13
25
 
14
26
  class Error::Nonrecoverable < Error
15
27
  end
28
+
29
+ class Error::Encoding < Error::Nonrecoverable
30
+ end
16
31
  end
@@ -2,7 +2,7 @@ DO $$
2
2
  BEGIN
3
3
  ALTER TABLE {SCHEMA_NAME}.postjobs ADD COLUMN processing_client varchar;
4
4
  EXCEPTION
5
- WHEN duplicate_column THEN RAISE NOTICE 'column {SCHEMA_NAME}.postjobs.processing_client already exists';
5
+ WHEN duplicate_column THEN RAISE DEBUG 'column {SCHEMA_NAME}.postjobs.processing_client already exists';
6
6
  END;
7
7
  $$;
8
8
 
@@ -10,7 +10,7 @@ DO $$
10
10
  BEGIN
11
11
  ALTER TABLE {SCHEMA_NAME}.postjobs ADD COLUMN processing_client_identifier varchar;
12
12
  EXCEPTION
13
- WHEN duplicate_column THEN RAISE NOTICE 'column {SCHEMA_NAME}.postjobs.processing_client_identifier already exists';
13
+ WHEN duplicate_column THEN RAISE DEBUG 'column {SCHEMA_NAME}.postjobs.processing_client_identifier already exists';
14
14
  END;
15
15
  $$;
16
16
 
@@ -18,7 +18,7 @@ DO $$
18
18
  BEGIN
19
19
  ALTER TABLE {SCHEMA_NAME}.postjobs ADD COLUMN processing_started_at timestamp;
20
20
  EXCEPTION
21
- WHEN duplicate_column THEN RAISE NOTICE 'column {SCHEMA_NAME}.postjobs.processing_started_at already exists';
21
+ WHEN duplicate_column THEN RAISE DEBUG 'column {SCHEMA_NAME}.postjobs.processing_started_at already exists';
22
22
  END;
23
23
  $$;
24
24
 
@@ -26,6 +26,6 @@ DO $$
26
26
  BEGIN
27
27
  ALTER TABLE {SCHEMA_NAME}.postjobs ADD COLUMN processing_max_duration float;
28
28
  EXCEPTION
29
- WHEN duplicate_column THEN RAISE NOTICE 'column {SCHEMA_NAME}.postjobs.processing_max_duration already exists';
29
+ WHEN duplicate_column THEN RAISE DEBUG 'column {SCHEMA_NAME}.postjobs.processing_max_duration already exists';
30
30
  END;
31
31
  $$;
@@ -14,6 +14,11 @@ AS $$
14
14
  job_id BIGINT;
15
15
  BEGIN
16
16
  -- set defaults ---------------------------------------------------
17
+ IF workflow = '__manual__' AND COALESCE(max_attempts, 1) != 1 THEN
18
+ RAISE NOTICE 'Adjusting max_attempts of __manual__ job to 1';
19
+ max_attempts := 1;
20
+ END IF;
21
+
17
22
  workflow_version := COALESCE(workflow_version, '');
18
23
  queue := COALESCE(queue, 'q');
19
24
  max_attempts := COALESCE(max_attempts, 5);
@@ -3,5 +3,14 @@ CREATE TABLE IF NOT EXISTS {SCHEMA_NAME}.settings (
3
3
  value VARCHAR
4
4
  );
5
5
 
6
- INSERT INTO {SCHEMA_NAME}.settings (name, value) VALUES('version', '0.4.0') ON CONFLICT DO NOTHING;
7
- INSERT INTO {SCHEMA_NAME}.settings (name, value) VALUES('client_version', '{CLIENT_VERSION}') ON CONFLICT DO NOTHING;
6
+ CREATE OR REPLACE FUNCTION {SCHEMA_NAME}.update_settings(p_name VARCHAR, p_value VARCHAR)
7
+ RETURNS VOID
8
+ AS $$
9
+ BEGIN
10
+ INSERT INTO {SCHEMA_NAME}.settings (name, value) VALUES(p_name, p_value)
11
+ ON CONFLICT(name) DO UPDATE SET value = p_value;
12
+ END;
13
+ $$ LANGUAGE plpgsql;
14
+
15
+ SELECT {SCHEMA_NAME}.update_settings('version', '0.4.2');
16
+ SELECT {SCHEMA_NAME}.update_settings('client_version', '{CLIENT_VERSION}');
@@ -16,6 +16,7 @@ module Postjob
16
16
  expect! SCHEMA_NAME != "public"
17
17
 
18
18
  def unmigrate!
19
+ SQL.exec "SET client_min_messages TO WARNING"
19
20
  SQL.exec "DROP SCHEMA IF EXISTS #{SCHEMA_NAME} CASCADE"
20
21
  end
21
22
 
@@ -30,7 +31,7 @@ module Postjob
30
31
  private
31
32
 
32
33
  def run_migration(file)
33
- STDERR.puts "[postjob] Running migration in #{file}"
34
+ Postjob.logger.debug "[postjob] Running migration in #{file}"
34
35
 
35
36
  case file
36
37
  when /\.rb$/ then run_migration_ruby(file)
@@ -16,11 +16,17 @@ require "json"
16
16
  module Postjob::Queue::Encoder
17
17
  extend self
18
18
 
19
+ def check_encodable!(data)
20
+ encode(data)
21
+ end
22
+
19
23
  def encode(data)
20
24
  return nil if data.nil?
21
25
 
22
26
  verify_encodable!(data)
23
- JSON.generate(data)
27
+ ::JSON.generate(data)
28
+ rescue ::JSON::JSONError, ::EncodingError
29
+ raise ::Postjob::Error::Encoding, $!.to_s
24
30
  end
25
31
 
26
32
  private
@@ -35,7 +41,7 @@ module Postjob::Queue::Encoder
35
41
  when Array then obj.each { |entry| verify_encodable!(entry) }
36
42
  else
37
43
  msg = "Unencodable #{obj.class.name} object: #{obj.inspect}"
38
- raise ArgumentError, msg
44
+ raise ::Postjob::Error::Encoding, msg
39
45
  end
40
46
  end
41
47
  end
data/lib/postjob/queue.rb CHANGED
@@ -89,7 +89,14 @@ module Postjob::Queue
89
89
  end
90
90
 
91
91
  def find_or_create_childjob(parent, workflow, args, timeout:, max_attempts:, queue: nil)
92
- expect! parent => Job, workflow => String, args => Array
92
+ expect! parent => Job
93
+ expect! workflow => String
94
+ expect! args => Array
95
+
96
+ if workflow == "__manual__" && max_attempts != 1
97
+ Postjob.logger.info "Job ##{parent.id} adjusting max_attempts of '__manual__' child job"
98
+ max_attempts = 1
99
+ end
93
100
 
94
101
  workflow, workflow_method = parse_workflow(workflow)
95
102
 
@@ -1,6 +1,7 @@
1
1
  # rubocop:disable Metrics/ModuleLength
2
2
  # rubocop:disable Style/BlockDelimiters
3
3
  # rubocop:disable Lint/RescueException
4
+ # rubocop:disable Metrics/MethodLength
4
5
 
5
6
  module Postjob::Runner
6
7
  extend self
@@ -119,13 +120,22 @@ module Postjob::Runner
119
120
  workflow.public_send workflow_method, *args
120
121
  }
121
122
 
122
- case value
123
- when :pending then [ :pending, nil, nil ]
124
- else [ :ok, value, nil ]
123
+ if value == :pending
124
+ [ :pending, nil, nil ]
125
+ else
126
+ # Check that we can encode the value. If we can't the job returned something invalid
127
+ # i.e. something we cannot encode as JSON. This will raise a Postjob::Queue::Encoder::Error.
128
+ #
129
+ # Usually this points to a non-UTF8 string.
130
+ # This is a fix for https://github.com/mediapeers/postjob/issues/35
131
+ Postjob::Queue::Encoder.check_encodable!([value])
132
+ [ :ok, value, nil ]
125
133
  end
126
134
  rescue ArgumentError, LocalJumpError, NameError, RegexpError, ScriptError, TypeError
127
135
  Postjob.logger.error "#{$!}, from\n\t#{$!.backtrace[0, 10].join("\n\t")}"
128
136
  return_exception :failed, $!
137
+ rescue Postjob::Error::Nonrecoverable
138
+ return_exception :failed, $!
129
139
  rescue Exception
130
140
  return_exception :err, $!
131
141
  end
data/lib/postjob.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  # rubocop:disable Metrics/ParameterLists
2
+ # rubocop:disable Metrics/MethodLength
2
3
 
3
4
  require "expectation"
4
5
  require "simple/sql"
@@ -40,6 +41,16 @@ module Postjob
40
41
  expect! timeout => [nil, Numeric]
41
42
  expect! tags => [nil, Hash]
42
43
 
44
+ if workflow == "__manual__" && max_attempts != 1
45
+ if parent_id
46
+ Postjob.logger.info "Job ##{parent_id} adjusting max_attempts of '__manual__' child job"
47
+ else
48
+ Postjob.logger.info "Adjusting max_attempts of '__manual__' root job"
49
+ end
50
+
51
+ max_attempts = 1
52
+ end
53
+
43
54
  tags = stringify_hash(tags) if tags
44
55
  job = Queue.enqueue_job workflow, *args, queue: queue,
45
56
  parent_id: parent_id,
@@ -1,8 +1,8 @@
1
1
  require "spec_helper"
2
2
 
3
3
  module ManualWorkflow
4
- def self.run
5
- job = async :manual, timeout: 10
4
+ def self.run(max_attempts)
5
+ job = async :manual, timeout: 10, max_attempts: max_attempts
6
6
  _token = workflow_token job
7
7
  manual_result = await job
8
8
  "manual-result:#{manual_result}"
@@ -12,7 +12,7 @@ module ManualWorkflow
12
12
  end
13
13
 
14
14
  describe "manual processing" do
15
- let!(:id) { Postjob.enqueue! "ManualWorkflow" }
15
+ let!(:id) { Postjob.enqueue! "ManualWorkflow", 3 }
16
16
 
17
17
  include TestHelper
18
18
 
@@ -24,6 +24,10 @@ describe "manual processing" do
24
24
  TestHelper.load_job "SELECT * FROM postjobs WHERE parent_id=$1", id
25
25
  end
26
26
 
27
+ it "sets max_attempts to 1" do
28
+ expect(load_child_job[:max_attempts]).to eq(1)
29
+ end
30
+
27
31
  it "creates a UUID token" do
28
32
  token = load_token(load_child_job)
29
33
  expect! token => /[A-F0-9]{8}-[A-F0-9]{4}-[A-F0-9]{4}-[a-fA-F0-9]{4}-[A-F0-9]{12}/i
@@ -37,14 +37,27 @@ describe "Postjob::Queue::Encoder" do
37
37
  end
38
38
 
39
39
  describe "invalid input" do
40
- it "cannot encode Symbols on input" do
41
- expect do
42
- run_workflow input: :foo
43
- end.to raise_error(ArgumentError)
44
-
45
- expect do
46
- run_workflow output: :foo
47
- end.to raise_error(ArgumentError)
40
+ def self.check_value(value)
41
+ it "cannot encode input" do
42
+ expect do
43
+ run_workflow input: value
44
+ end.to raise_error(::Postjob::Error::Encoding)
45
+ end
46
+
47
+ it "cannot encode output" do
48
+ expect do
49
+ run_workflow output: value
50
+ end.to raise_error(::Postjob::Error::Encoding)
51
+ end
52
+ end
53
+
54
+ context "when encoding symbols" do
55
+ check_value :foo
56
+ end
57
+
58
+ context "when encoding invalid utf8 strings" do
59
+ check_value 255.chr.force_encoding("utf-8")
60
+ check_value 255.chr
48
61
  end
49
62
  end
50
63
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: postjob
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ version: 0.4.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - radiospiel
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-06-04 00:00:00.000000000 Z
11
+ date: 2018-06-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec