postjob 0.5.5 → 0.5.6

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.
Files changed (36) hide show
  1. checksums.yaml +5 -5
  2. data/lib/postjob/cli/cron.rb +16 -0
  3. data/lib/postjob/cli/enqueue.rb +14 -0
  4. data/lib/postjob/cli/job.rb +15 -19
  5. data/lib/postjob/cli/ps.rb +8 -2
  6. data/lib/postjob/host.rb +41 -0
  7. data/lib/postjob/job.rb +23 -23
  8. data/lib/postjob/migrations/006_enqueue.sql +48 -4
  9. data/lib/postjob/migrations/006a_processing.sql +5 -2
  10. data/lib/postjob/migrations/007_job_results.sql +6 -5
  11. data/lib/postjob/migrations/008a_childjobs.sql +33 -38
  12. data/lib/postjob/migrations/010_settings.sql +1 -1
  13. data/lib/postjob/migrations/{008_checkout_runnable.sql → 013a_checkout_runnable.sql} +11 -7
  14. data/lib/postjob/migrations/017_zombie_check.sql +11 -6
  15. data/lib/postjob/migrations/021_cron_jobs.sql +65 -0
  16. data/lib/postjob/migrations/023_sticky_jobs.sql +16 -0
  17. data/lib/postjob/migrations.rb +3 -1
  18. data/lib/postjob/queue.rb +23 -4
  19. data/lib/postjob/record.rb +4 -10
  20. data/lib/postjob/registry.rb +117 -20
  21. data/lib/postjob/runner.rb +169 -166
  22. data/lib/postjob/worker_session.rb +9 -25
  23. data/lib/postjob/workflow.rb +26 -50
  24. data/lib/postjob.rb +97 -23
  25. data/lib/tools/heartbeat.rb +2 -2
  26. data/lib/tools/history.rb +1 -1
  27. data/spec/postjob/enqueue_spec.rb +3 -0
  28. data/spec/postjob/events/heartbeat_event_spec.rb +5 -67
  29. data/spec/postjob/events/zombie_event_spec.rb +61 -0
  30. data/spec/postjob/worker_session_spec.rb +1 -24
  31. data/spec/spec_helper.rb +1 -1
  32. data/spec/support/configure_active_record.rb +7 -16
  33. data/spec/support/configure_database.rb +11 -0
  34. data/spec/support/configure_simple_sql.rb +0 -16
  35. metadata +10 -5
  36. data/lib/tools/atomic_store.rb +0 -17
data/lib/postjob/queue.rb CHANGED
@@ -2,10 +2,11 @@
2
2
  # rubocop:disable Metrics/MethodLength
3
3
  # rubocop:disable Metrics/ParameterLists
4
4
  # rubocop:disable Metrics/LineLength
5
+ # rubocop:disable Metrics/ModuleLength
5
6
 
6
7
  require "securerandom"
7
8
 
8
- # The Postjob::Queue manages enqueueing and fetching jobs from a job queue.
9
+ # The Postjob::Queue module manages enqueueing and fetching jobs from a job queue.
9
10
  module Postjob::Queue
10
11
  extend self
11
12
 
@@ -20,7 +21,7 @@ require_relative "queue/associations"
20
21
  require_relative "queue/settings"
21
22
 
22
23
  module Postjob::Queue
23
- Job = ::Postjob::Job
24
+ Job = ::Postjob::Job # :nodoc:
24
25
 
25
26
  # enqueues a new job with the given arguments
26
27
  #
@@ -41,7 +42,8 @@ module Postjob::Queue
41
42
  parent_id: [Integer, nil],
42
43
  tags: [Hash, nil],
43
44
  timeout: [Numeric, nil],
44
- max_attempts: [Integer, nil]
45
+ max_attempts: [Integer, nil],
46
+ sticky: [true, false, nil]
45
47
  }
46
48
 
47
49
  workflow, workflow_method = parse_workflow(workflow)
@@ -51,7 +53,7 @@ module Postjob::Queue
51
53
  # a) a limitation in Simple::SQL which would not be able to unpack a
52
54
  # "SELECT function()" usefully when the return value is a record;
53
55
  # b) and/or my inability to write better SQL functions;
54
- SQL.ask "SELECT * FROM #{SCHEMA_NAME}.enqueue($1::uuid, $2, $3, $4, $5, $6, $7, $8, $9, $10)",
56
+ SQL.ask "SELECT * FROM #{SCHEMA_NAME}.enqueue($1::uuid, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)",
55
57
  worker_session_id,
56
58
  options[:queue],
57
59
  workflow,
@@ -62,9 +64,26 @@ module Postjob::Queue
62
64
  Encoder.encode(options[:tags]),
63
65
  options[:max_attempts],
64
66
  options[:timeout],
67
+ options[:cron_interval],
68
+ options[:sticky],
65
69
  into: Job
66
70
  end
67
71
 
72
+ # Disable cron'ness for workflow + args combination
73
+ def disable_cron_jobs(workflow, args)
74
+ sql = <<~SQL
75
+ UPDATE postjob.postjobs
76
+ SET cron_interval = NULL
77
+ WHERE cron_interval IS NOT NULL
78
+ AND workflow=$1
79
+ AND args=$2
80
+ AND parent_id IS NULL
81
+ AND status NOT IN ('ok', 'failed', 'timeout')
82
+ SQL
83
+
84
+ Simple::SQL.ask sql, workflow, Encoder.encode(args)
85
+ end
86
+
68
87
  def set_job_result(worker_session_id, job, value, version:)
69
88
  value = Encoder.encode([value]) unless value.nil?
70
89
  SQL.ask "SELECT #{SCHEMA_NAME}.set_job_result($1::uuid, $2, $3, $4)", worker_session_id, job.id, value, version
@@ -1,17 +1,11 @@
1
- # rubocop:disable Style/EvalWithLocation
2
- # rubocop:disable Security/Eval
3
-
4
1
  #
5
2
  # A job class in-memory representation.
6
3
  #
7
- class Postjob::Record < Hash
4
+ class Postjob::Record < Hash # :nodoc:
8
5
  def initialize(hsh)
9
6
  replace hsh.dup
10
- end
11
-
12
- def self.attribute(sym)
13
- eval <<~RUBY
14
- define_method(:#{sym}) { self[:#{sym}] }
15
- RUBY
7
+ each do |key, value|
8
+ instance_variable_set "@#{key}", value
9
+ end
16
10
  end
17
11
  end
@@ -1,37 +1,134 @@
1
1
  # The registry holds a list of all available workflows
2
- module Postjob::Registry
3
- extend self
2
+ class Postjob::Registry
3
+ def self.instance
4
+ @instance ||= new
5
+ end
4
6
 
5
- def workflows
6
- instance.values.uniq
7
+ # Used for tests
8
+ def self.reset! # :nodoc:
9
+ @instance = nil
7
10
  end
8
11
 
9
- def workflows_with_versions
10
- @workflows_with_versions ||= []
12
+ def self.workflows
13
+ instance.workflows
11
14
  end
12
15
 
13
- # Used for tests
14
- def reset! # :nodoc:
15
- @instance = @workflows_with_versions = nil
16
+ def self.workflow_names
17
+ instance.workflows.keys.map(&:first).uniq
16
18
  end
17
19
 
18
- def register(workflow, _options = {})
19
- instance[[workflow.name, ""]] = workflow
20
- instance[[workflow.name, workflow.workflow_version]] = workflow
20
+ def self.runnable_workflows_with_versions
21
+ workflows
22
+ .select { |_, spec| spec.runnable? }
23
+ .inject([]) do |ary, (name_and_version, _spec)|
24
+ name, version = *name_and_version
25
+ ary << name << "#{name}#{version}"
26
+ end
27
+ end
21
28
 
22
- workflows_with_versions << workflow.name << "#{workflow.name}#{workflow.workflow_version}"
29
+ def self.workflows_with_versions
30
+ instance.workflows_with_versions
23
31
  end
24
32
 
25
- def lookup!(name:, version:)
26
- expect! name => String
27
- expect! version => String
33
+ def self.register(workflow, options = {})
34
+ instance.register(workflow, options)
35
+ end
36
+
37
+ class WorkflowSpec
38
+ class Options
39
+ DEFAULTS = {
40
+ version: "0.0",
41
+ max_attempts: 5,
42
+ timeout: 15 * 60,
43
+ sticky: false,
44
+ cron_interval: nil,
45
+ queue: "q"
46
+ }
47
+
48
+ attr_reader :version
49
+ attr_reader :max_attempts
50
+ attr_reader :timeout
51
+ attr_reader :sticky
52
+ attr_reader :cron_interval
53
+ attr_reader :queue
54
+
55
+ def initialize(options)
56
+ expect! options => {
57
+ version: [ nil, /^\d+(\.\d+)*/ ],
58
+ max_attempts: [ nil, Integer ],
59
+ timeout: [ nil, Integer ],
60
+ sticky: [ nil, true, false ],
61
+ cron_interval: [ nil, Integer ],
62
+ queue: [ nil, String ]
63
+ }
64
+
65
+ options = DEFAULTS.merge(options)
66
+
67
+ @version = options[:version]
68
+ @max_attempts = options[:max_attempts]
69
+ @timeout = options[:timeout]
70
+ @sticky = options[:sticky]
71
+ @cron_interval = options[:cron_interval]
72
+ @queue = options[:queue]
73
+ end
74
+ end
75
+
76
+ attr_reader :workflow
77
+ attr_reader :options
78
+
79
+ def runnable?
80
+ workflow.is_a?(Module)
81
+ end
28
82
 
29
- instance.fetch([name, version])
83
+ def name
84
+ case workflow
85
+ when Module then workflow.name
86
+ when String then workflow
87
+ end
88
+ end
89
+
90
+ def initialize(workflow, options)
91
+ expect! workflow => [ Module, String ]
92
+ @workflow = workflow
93
+ @options = Options.new(options)
94
+ end
95
+ end
96
+
97
+ # looks up a specific version of a specific workflow. Returns a WorkflowSpec
98
+ # object.
99
+ def self.lookup!(name:, version:)
100
+ instance.lookup! name: name, version: version
101
+ end
102
+
103
+ def self.[](name)
104
+ lookup! name: name, version: ""
105
+ rescue KeyError
106
+ nil
107
+ end
108
+
109
+ attr_reader :workflows
110
+ attr_reader :workflows_with_versions
111
+
112
+ def initialize
113
+ @workflows = {}
114
+ @workflows_with_versions = []
30
115
  end
31
116
 
32
- private
117
+ def register(workflow, options)
118
+ spec = WorkflowSpec.new(workflow, options)
119
+
120
+ @workflows_with_versions << spec.name << "#{spec.name}#{spec.options.version}"
121
+
122
+ @workflows[[spec.name, ""]] = spec
123
+ @workflows[[spec.name, spec.options.version]] = spec
124
+ end
125
+
126
+ # looks up a specific version of a specific workflow. Returns the workflow
127
+ # module itself
128
+ def lookup!(name:, version:)
129
+ expect! name => String
130
+ expect! version => String
33
131
 
34
- def instance
35
- @instance ||= {}
132
+ @workflows.fetch([name, version])
36
133
  end
37
134
  end
@@ -3,194 +3,197 @@
3
3
  # rubocop:disable Lint/RescueException
4
4
  # rubocop:disable Metrics/MethodLength
5
5
 
6
+ # Base implementations for Runners
7
+ #
8
+ # This module contains methods for runners.
6
9
  module Postjob::Runner
7
- extend self
10
+ class << self
11
+ extend Forwardable
12
+ delegate [:logger] => Postjob
13
+
14
+ Job = Postjob::Job
15
+
16
+ # returns the job that is currently running.
17
+ #
18
+ # This value is set by +process_job+ (via +with_current_job+), and
19
+ # currently only used from <tt>Postjob::Runner.async</tt>
20
+ def current_job
21
+ Thread.current[:current_job]
22
+ end
8
23
 
9
- extend Forwardable
10
- delegate [:logger] => Postjob
24
+ private
11
25
 
12
- Job = Postjob::Job
26
+ def with_current_job(job)
27
+ expect! current_job => nil
28
+ Thread.current[:current_job] = job
29
+ yield
30
+ ensure
31
+ Thread.current[:current_job] = nil
32
+ end
13
33
 
14
- # returns the job that is currently running.
15
- #
16
- # This value is set by +process_job+ (via +with_current_job+), and
17
- # currently only used from <tt>Postjob::Runner.async</tt>
18
- def current_job
19
- Thread.current[:current_job]
20
- end
34
+ public
35
+
36
+ # returns a subjob within the current job, for a +runner+
37
+ # description and +args+.
38
+ def async(workflow, *args, timeout: nil, max_attempts:)
39
+ worker_session_id = Postjob.current_worker_session.id
40
+
41
+ # if the workflow is a symbol, then we change it into "__manual__"
42
+ # - there should never be a workflow with that name - or into
43
+ # "CurrentWorkshop.#{workflow}", denoting the \a workflow method of the
44
+ # current workflow.
45
+ case workflow
46
+ when :manual then workflow = "__manual__"
47
+ when Symbol then workflow = "#{current_job.workflow}.#{workflow}"
48
+ when Module then workflow = workflow.name
49
+ when String then :nop
50
+ else
51
+ raise ArgumentError, "Unsupported workflow spec #{workflow.inspect}. Did you run await(fun(a, b)) instead of await(:fun, a, b)"
52
+ end
21
53
 
22
- private
54
+ ::Postjob::Queue.find_or_create_childjob(worker_session_id, self.current_job, workflow, args,
55
+ timeout: timeout,
56
+ max_attempts: max_attempts)
57
+ end
23
58
 
24
- def with_current_job(job)
25
- expect! current_job => nil
26
- Thread.current[:current_job] = job
27
- yield
28
- ensure
29
- Thread.current[:current_job] = nil
30
- end
59
+ # tries to resolve a job.
60
+ def await(job, *args, timeout: nil, max_attempts: nil)
61
+ case job
62
+ when :all
63
+ unresolved_childjobs = Postjob::Queue.unresolved_childjobs(current_job)
64
+ if unresolved_childjobs > 0
65
+ Postjob.logger.debug "await :all: Found #{unresolved_childjobs} unresolved childjobs"
66
+ throw :pending, :pending
67
+ else
68
+ childjobs = Postjob::Queue.childjobs(current_job)
69
+ childjobs.each(&:resolve).count
70
+ end
71
+ when Job
72
+ expect! args == []
73
+ expect! timeout => nil, max_attempts => nil
74
+ r = job.resolve
75
+ throw :pending, :pending if r == :pending
76
+ r
77
+ else
78
+ job = async(job, *args, timeout: timeout, max_attempts: max_attempts)
79
+ await(job)
80
+ end
81
+ end
31
82
 
32
- public
33
-
34
- # returns a subjob within the current job, for a +runner+
35
- # description and +args+.
36
- def async(workflow, *args, timeout: nil, max_attempts:)
37
- worker_session_id = Postjob.current_worker_session.id
38
-
39
- # if the workflow is a symbol, then we change it into "__manual__"
40
- # - there should never be a workflow with that name - or into
41
- # "CurrentWorkshop.#{workflow}", denoting the \a workflow method of the
42
- # current workflow.
43
- case workflow
44
- when :manual then workflow = "__manual__"
45
- when Symbol then workflow = "#{current_job.workflow}.#{workflow}"
46
- when Module then workflow = workflow.name
47
- when String then :nop
48
- else
49
- raise ArgumentError, "Unsupported workflow spec #{workflow.inspect}. Did you run await(fun(a, b)) instead of await(:fun, a, b)"
83
+ STATUSES = [ :sleep, :ok, :err, :failed ]
84
+
85
+ #
86
+ # runs a specific job
87
+ #
88
+ # returns a tuple [status, value], which follows the following pattern:
89
+ #
90
+ # - <tt>[ <runner-version>, :ok, value, nil ]</tt>: job completed successfully
91
+ # - <tt>[ <runner-version>, :sleep, nil, nil ]</tt>: job has to wait on a child job
92
+ # - <tt>[ <runner-version>, :err, <err>, nil ]</tt>: job errored with a recoverable error
93
+ # - <tt>[ <runner-version>, :failed, <err>, <shutdown> ]</tt>: job failed with a non-recoverable error
94
+ #
95
+ # <err> is a tuple [ error-class-name, error-message, stacktrace ].
96
+ # <shutdown> is either nil or :shutdown
97
+ #
98
+ def process_job(job)
99
+ expect! job => Job
100
+
101
+ spec = Postjob::Registry.lookup!(name: job.workflow, version: job.workflow_version)
102
+ expect! spec.runnable?
103
+
104
+ with_current_job(job) do
105
+ status, value, shutdown = invoke_workflow spec.workflow, job
106
+ log_result! job, status, value
107
+ # If the status is ok the job finished processing. In that case
108
+ # we'll wait for all child jobs to finish.
109
+ # if status == :ok
110
+ # await :all
111
+ # end
112
+ [ spec.options.version, status, value, shutdown ]
113
+ end
50
114
  end
51
115
 
52
- ::Postjob::Queue.find_or_create_childjob(worker_session_id, self.current_job, workflow, args,
53
- timeout: timeout,
54
- max_attempts: max_attempts)
55
- end
116
+ private
117
+
118
+ # runs a job. Returns a [ status, value, shutdown ] tuple.
119
+ #
120
+ # The shutdown value is used by a worker in run mode (i.e. process
121
+ # indefinetively) to determine whether or not it should cancel
122
+ # processing. It is usually nil; but if the worker received a
123
+ # SIGINT it will be :shutdown instead.
124
+ #
125
+ # We are catching SIGINT to allow the job status to be updated.
126
+ def invoke_workflow(workflow, job)
127
+ value = catch(:pending) {
128
+ expect! job.args => [Array, nil]
129
+
130
+ workflow_method = job.workflow_method
131
+ args = job.args
132
+
133
+ insp_args = args.map(&:inspect).join(", ")
134
+ logger.info "Running Postjob##{job.id}: #{job.workflow}.#{workflow_method}(#{insp_args})"
56
135
 
57
- # tries to resolve a job.
58
- def await(job, *args, timeout: nil, max_attempts: nil)
59
- case job
60
- when :all
61
- unresolved_childjobs = Postjob::Queue.unresolved_childjobs(current_job)
62
- if unresolved_childjobs > 0
63
- Postjob.logger.debug "await :all: Found #{unresolved_childjobs} unresolved childjobs"
64
- throw :pending, :pending
136
+ workflow.public_send workflow_method, *args
137
+ }
138
+
139
+ if value == :pending
140
+ [ :pending, nil, nil ]
65
141
  else
66
- childjobs = Postjob::Queue.childjobs(current_job)
67
- childjobs.each(&:resolve).count
142
+ # Check that we can encode the value. If we can't the job returned something invalid
143
+ # i.e. something we cannot encode as JSON. This will raise a Postjob::Queue::Encoder::Error.
144
+ #
145
+ # Usually this points to a non-UTF8 string.
146
+ # This is a fix for https://github.com/mediapeers/postjob/issues/35
147
+ Postjob::Queue::Encoder.check_encodable!([value])
148
+ [ :ok, value, nil ]
68
149
  end
69
- when Job
70
- expect! args == []
71
- expect! timeout => nil, max_attempts => nil
72
- r = job.resolve
73
- throw :pending, :pending if r == :pending
74
- r
75
- else
76
- job = async(job, *args, timeout: timeout, max_attempts: max_attempts)
77
- await(job)
78
- end
79
- end
80
-
81
- STATUSES = [ :sleep, :ok, :err, :failed ]
82
-
83
- #
84
- # runs a specific job
85
- #
86
- # returns a tuple [status, value], which follows the following pattern:
87
- #
88
- # - <tt>[ <runner-version>, :ok, value, nil ]</tt>: job completed successfully
89
- # - <tt>[ <runner-version>, :sleep, nil, nil ]</tt>: job has to wait on a child job
90
- # - <tt>[ <runner-version>, :err, <err>, nil ]</tt>: job errored with a recoverable error
91
- # - <tt>[ <runner-version>, :failed, <err>, <shutdown> ]</tt>: job failed
92
- # with a non-recoverable error
93
- #
94
- # <err> is a tuple [ error-class-name, error-message, stacktrace ].
95
- # <shutdown> is either nil or :shutdown
96
- #
97
- def process_job(job)
98
- expect! job => Job
99
-
100
- workflow = Postjob::Registry.lookup!(name: job.workflow, version: job.workflow_version)
101
-
102
- with_current_job(job) do
103
- status, value, shutdown = invoke_workflow workflow, job
104
- log_result! job, status, value
105
- # If the status is ok the job finished processing. In that case
106
- # we'll wait for all child jobs to finish.
107
- # if status == :ok
108
- # await :all
109
- # end
110
- [ workflow.workflow_version, status, value, shutdown ]
150
+ rescue ArgumentError, LocalJumpError, NameError, RegexpError, ScriptError, TypeError
151
+ Postjob.logger.error "#{$!}, from\n\t#{$!.backtrace[0, 10].join("\n\t")}"
152
+ return_exception :failed, $!
153
+ rescue Postjob::Error::Nonrecoverable
154
+ return_exception :failed, $!
155
+ rescue Exception
156
+ return_exception :err, $!
111
157
  end
112
- end
113
158
 
114
- private
115
-
116
- # runs a job. Returns a [ status, value, shutdown ] tuple.
117
- #
118
- # The shutdown value is used by a worker in run mode (i.e. process
119
- # indefinetively) to determine whether or not it should cancel
120
- # processing. It is usually nil; but if the worker received a
121
- # SIGINT it will be :shutdown instead.
122
- #
123
- # We are catching SIGINT to allow the job status to be updated.
124
- def invoke_workflow(workflow, job)
125
- value = catch(:pending) {
126
- expect! job.args => [Array, nil]
127
-
128
- workflow_method = job.workflow_method
129
- args = job.args
130
-
131
- insp_args = args.map(&:inspect).join(", ")
132
- logger.info "Running Postjob##{job.id}: #{job.workflow}.#{workflow_method}(#{insp_args})"
133
-
134
- workflow.public_send workflow_method, *args
135
- }
136
-
137
- if value == :pending
138
- [ :pending, nil, nil ]
139
- else
140
- # Check that we can encode the value. If we can't the job returned something invalid
141
- # i.e. something we cannot encode as JSON. This will raise a Postjob::Queue::Encoder::Error.
142
- #
143
- # Usually this points to a non-UTF8 string.
144
- # This is a fix for https://github.com/mediapeers/postjob/issues/35
145
- Postjob::Queue::Encoder.check_encodable!([value])
146
- [ :ok, value, nil ]
159
+ def should_shutdown?(exception)
160
+ exception.is_a?(Interrupt)
147
161
  end
148
- rescue ArgumentError, LocalJumpError, NameError, RegexpError, ScriptError, TypeError
149
- Postjob.logger.error "#{$!}, from\n\t#{$!.backtrace[0, 10].join("\n\t")}"
150
- return_exception :failed, $!
151
- rescue Postjob::Error::Nonrecoverable
152
- return_exception :failed, $!
153
- rescue Exception
154
- return_exception :err, $!
155
- end
156
162
 
157
- def should_shutdown?(exception)
158
- exception.is_a?(Interrupt)
159
- end
163
+ def return_exception(state, exception)
164
+ # get and shorten backtrace.
165
+ error_backtrace = exception.backtrace[0, 10]
160
166
 
161
- def return_exception(state, exception)
162
- # get and shorten backtrace.
163
- error_backtrace = exception.backtrace[0, 10]
167
+ curdir = "#{Dir.getwd}/"
168
+ error_backtrace = error_backtrace.map { |path| path.start_with?(curdir) ? path[curdir.length..-1] : path }
164
169
 
165
- curdir = "#{Dir.getwd}/"
166
- error_backtrace = error_backtrace.map { |path| path.start_with?(curdir) ? path[curdir.length..-1] : path }
170
+ shutdown = should_shutdown?(exception) ? :shutdown : nil
171
+ [ state, [exception.class.name, exception.message, error_backtrace], shutdown ]
172
+ end
167
173
 
168
- shutdown = should_shutdown?(exception) ? :shutdown : nil
169
- [ state, [exception.class.name, exception.message, error_backtrace], shutdown ]
170
- end
174
+ def log_result!(job, status, value)
175
+ case status
176
+ when :err
177
+ severity = job.parent_id ? :warn : :error
178
+ logger.send severity, error_message(job, status, value)
179
+ when :failed
180
+ logger.error error_message(job, status, value)
181
+ when :ok
182
+ runtime = Time.now.utc - job.created_at
183
+ runtime = "%.03f secs" % runtime
184
+ severity = job.parent_id ? :info : :warn
185
+ msg = "#{job} successful w/result #{value.inspect}: #{runtime}"
186
+ logger.send severity, msg
187
+ end
188
+ end
171
189
 
172
- def log_result!(job, status, value)
173
- case status
174
- when :err
175
- severity = job.parent_id ? :warn : :error
176
- logger.send severity, error_message(job, status, value)
177
- when :failed
178
- logger.error error_message(job, status, value)
179
- when :ok
190
+ def error_message(job, status, value)
180
191
  runtime = Time.now.utc - job.created_at
181
192
  runtime = "%.03f secs" % runtime
182
- severity = job.parent_id ? :info : :warn
183
- msg = "#{job} successful w/result #{value.inspect}: #{runtime}"
184
- logger.send severity, msg
185
- end
186
- end
187
-
188
- def error_message(job, status, value)
189
- runtime = Time.now.utc - job.created_at
190
- runtime = "%.03f secs" % runtime
191
- error_class, err_message, _error_backtrace = value
193
+ error_class, err_message, _error_backtrace = value
192
194
 
193
- "#{job} #{status} #{error_class} #{err_message.inspect}: #{runtime}"
194
- # + "\n backtrace information:\n #{error_backtrace.join("\n ")}"
195
+ "#{job} #{status} #{error_class} #{err_message.inspect}: #{runtime}"
196
+ # + "\n backtrace information:\n #{error_backtrace.join("\n ")}"
197
+ end
195
198
  end
196
199
  end
@@ -3,34 +3,18 @@
3
3
  require_relative "./record"
4
4
 
5
5
  require "tools/heartbeat"
6
- require "tools/atomic_store"
7
-
8
- class Postjob::Host < Postjob::Record
9
- def self.register(attributes = {})
10
- Postjob.logger.debug "registering host w/#{attributes.inspect}"
11
- ::Postjob::Queue.host_register(attributes)
12
- end
13
- end
14
6
 
15
7
  # A worker worker_session
16
8
  class Postjob::WorkerSession < Postjob::Record
17
- HOST_ID_PATH = ".postjob.host_id"
18
-
19
9
  class << self
20
10
  # Starts a worker session.
21
11
  def start!(workflows_with_versions)
22
- worker_session = nil
23
-
24
- AtomicStore.with(HOST_ID_PATH) do |host_id|
25
- host_id ||= ::Postjob::Host.register
26
- Postjob.logger.debug "Starting worker_session w/host_id #{host_id.inspect}"
27
- worker_session = ::Postjob::Queue.start_worker_session(workflows_with_versions, host_id: host_id)
28
- host_id
29
- end
12
+ host_id = ::Postjob.host_id
13
+ worker_session = ::Postjob::Queue.start_worker_session(workflows_with_versions, host_id: host_id)
30
14
 
31
15
  Postjob.logger.info "Starting worker_session #{worker_session.inspect}"
32
16
 
33
- start_heartbeat_monitor(worker_session.host_id)
17
+ start_heartbeat_monitor(host_id)
34
18
  worker_session
35
19
  end
36
20
 
@@ -58,12 +42,12 @@ class Postjob::WorkerSession < Postjob::Record
58
42
  end
59
43
  end
60
44
 
61
- attribute :id
62
- attribute :host_id
63
- attribute :client_socket
64
- attribute :workflows
65
- attribute :attributes
66
- attribute :created_at
45
+ attr_reader :id
46
+ attr_reader :host_id
47
+ attr_reader :client_socket
48
+ attr_reader :workflows
49
+ attr_reader :attributes
50
+ attr_reader :created_at
67
51
 
68
52
  def to_s
69
53
  "Session##{id}"