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
@@ -1,56 +1,32 @@
1
-
2
- # including the Workflow module marks a module as a Postjob::Job, and mixes
3
- # in a couple of methods into the module (see Workflow::JobMethods)
1
+ # This module defines the interface available for workflow modules.
2
+ #
3
+ # This module is extended into the actual workflow module during registering.
4
4
  module Postjob::Workflow
5
- def self.included(job)
6
- expect! job.class.name => "Module"
7
-
8
- # This method should make sure there is a public run method. This, however,
9
- # is not possible before the run method is defined. We could do the check
10
- # with a job like
11
- #
12
- # module Foo
13
- # def self.run(arg); ..; end
14
- # include Postjob::Workflow
15
- # end
16
- #
17
- # but not the other way around:
18
- #
19
- # module Foo
20
- # include Postjob::Workflow
21
- # def self.run(arg); ..; end
22
- # end
23
- #
24
- # We therefore do not make this test here.
25
- job.extend JobMethods
5
+ # Note: we would like to sure that there is a public run method, and we could
6
+ # inspect the module with a +extended+ callback. This, however, is only
7
+ # possible when the run method is already defined. So, with a job definition
8
+ # of
9
+ #
10
+ # module Foo
11
+ # include Postjob::Workflow
12
+ # def self.run(arg); ..; end
13
+ # end
14
+ #
15
+ # we cannot run such a test.
16
+
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)
26
20
  end
27
21
 
28
- module JobMethods
29
- def async(runner, *args, timeout: nil, max_attempts: nil)
30
- ::Postjob::Runner.async(runner, *args, timeout: timeout, max_attempts: max_attempts)
31
- end
32
-
33
- def await(job, *args, timeout: nil, max_attempts: nil)
34
- ::Postjob::Runner.await(job, *args, timeout: timeout, max_attempts: max_attempts)
35
- end
36
-
37
- def workflow_token(job)
38
- expect! job.parent_id => ::Postjob::Runner.current_job.id
39
- ::Postjob::Queue.find_or_create_token(job)
40
- end
41
-
42
- def workflow_version
43
- @workflow_version || "0.0"
44
- end
45
-
46
- def workflow_name
47
- "#{name}@#{workflow_version}"
48
- end
49
-
50
- private
22
+ # see Postjob::Runner.await
23
+ def await(job, *args, timeout: nil, max_attempts: nil)
24
+ ::Postjob::Runner.await(job, *args, timeout: timeout, max_attempts: max_attempts)
25
+ end
51
26
 
52
- def set_workflow_version(workflow_version)
53
- @workflow_version = workflow_version
54
- end
27
+ # see Postjob::Runner.workflow_token
28
+ def workflow_token(job)
29
+ expect! job.parent_id => ::Postjob::Runner.current_job.id
30
+ ::Postjob::Queue.find_or_create_token(job)
55
31
  end
56
32
  end
data/lib/postjob.rb CHANGED
@@ -1,5 +1,9 @@
1
1
  # rubocop:disable Metrics/ParameterLists
2
2
  # rubocop:disable Metrics/MethodLength
3
+ # rubocop:disable Metrics/ModuleLength
4
+ # rubocop:disable Metrics/AbcSize
5
+ # rubocop:disable Metrics/CyclomaticComplexity
6
+ # rubocop:disable Metrics/PerceivedComplexity
3
7
 
4
8
  require "expectation"
5
9
  require "simple/sql"
@@ -13,6 +17,7 @@ require_relative "postjob/workflow"
13
17
  require_relative "postjob/registry"
14
18
  require_relative "postjob/job"
15
19
  require_relative "postjob/worker_session"
20
+ require_relative "postjob/host"
16
21
  require_relative "postjob/error"
17
22
  require_relative "postjob/queue"
18
23
  require_relative "postjob/runner"
@@ -21,26 +26,46 @@ module Postjob
21
26
  attr_accessor :logger
22
27
  extend self
23
28
 
29
+ def host_id
30
+ Host.host_id
31
+ end
32
+
24
33
  # In fast mode <tt>Postjob.run</tt> doesn't wait that long between retrying
25
34
  # failed jobs. This mode is enabled by default during tests; and it can be
26
35
  # enabled via "postjob run --fast"
27
36
  #
28
37
  # Note that fast mode should only be used during development and tests.
29
- attr_accessor :fast_mode
38
+ attr_accessor :fast_mode # :nodoc:
30
39
  self.fast_mode = false
31
40
 
41
+ # Enqueues a workflow.
42
+ #
43
+ # Options include
44
+ #
45
+ # - version
46
+ # - max_attempts
47
+ # - timeout
48
+ # - sticky
49
+ # - cron_interval
50
+ # - queue
51
+ #
32
52
  def enqueue!(workflow, *args, queue: nil,
33
53
  parent_id: nil,
34
54
  max_attempts: nil,
35
55
  timeout: nil,
36
56
  version: nil,
37
- tags: nil)
57
+ tags: nil,
58
+ cron_interval: nil,
59
+ sticky: nil)
38
60
  expect! queue => [nil, String]
39
61
  expect! workflow => String
40
62
  expect! parent_id => [nil, Integer]
41
63
  expect! max_attempts => [nil, Integer]
42
64
  expect! timeout => [nil, Numeric]
43
65
  expect! tags => [nil, Hash]
66
+ expect! sticky => [nil, false, true]
67
+
68
+ # -- prepare arguments ----------------------------------------------------
44
69
 
45
70
  if workflow == "__manual__" && max_attempts != 1
46
71
  if parent_id
@@ -52,13 +77,40 @@ module Postjob
52
77
  max_attempts = 1
53
78
  end
54
79
 
80
+ # -- fetch defaults from registry -----------------------------------------
81
+
82
+ spec = Postjob::Registry[workflow]
83
+ if spec
84
+ max_attempts = spec.options.max_attempts if max_attempts.nil?
85
+ timeout = spec.options.timeout if timeout.nil?
86
+ sticky = spec.options.sticky if sticky.nil?
87
+ cron_interval = spec.options.cron_interval if cron_interval.nil?
88
+ queue = spec.options.queue if queue.nil?
89
+ end
90
+
91
+ if cron_interval && cron_interval < 300
92
+ raise "cron interval must be at least 5 minutes"
93
+ end
94
+
95
+ # -- disable existing cron jobs -------------------------------------------
96
+
97
+ if cron_interval
98
+ Queue.disable_cron_jobs(workflow, args)
99
+ end
100
+
101
+ # -- enqueue jobs ---------------------------------------------------------
102
+
55
103
  tags = stringify_hash(tags) if tags
104
+
56
105
  job = Queue.enqueue_job current_worker_session.id, workflow, *args, queue: queue,
57
106
  parent_id: parent_id,
58
107
  max_attempts: max_attempts,
59
108
  timeout: timeout,
60
109
  tags: tags,
61
- version: version
110
+ version: version,
111
+ cron_interval: cron_interval,
112
+ sticky: sticky
113
+
62
114
  logger.info "Generated process #{job}"
63
115
  job.id
64
116
  end
@@ -147,7 +199,48 @@ module Postjob
147
199
  # This method connects to the queue. This means it registers as a new worker_session,
148
200
  # if there was no worker_session yet.
149
201
  def current_worker_session
150
- @worker_session ||= WorkerSession.start!(Registry.workflows_with_versions)
202
+ @worker_session ||= begin
203
+ WorkerSession.start!(Registry.runnable_workflows_with_versions)
204
+ end
205
+ end
206
+
207
+ # Explicitely resolve a workflow.
208
+ def resolve(token:, result:)
209
+ job = Queue.find_job_by_token(token)
210
+ raise "No job with token #{token}" unless job
211
+
212
+ Queue.set_job_result current_worker_session.id, job, result, version: nil
213
+ end
214
+
215
+ # Registers a workflow.
216
+ #
217
+ # This call registers a workflow with a set of options.
218
+ #
219
+ # This is usually used via
220
+ #
221
+ #
222
+ # module X
223
+ # Postjob.register self, max_attempts: 2, timeout: 86400
224
+ # end
225
+ #
226
+ #
227
+ # The +workflow+ parameter is either a module which implements a workflow,
228
+ # or a String with the name of a workflow, and a set of options.
229
+ #
230
+ # Options include
231
+ #
232
+ # - version
233
+ # - max_attempts
234
+ # - timeout
235
+ # - sticky
236
+ # - cron_interval
237
+ # - queue
238
+ #
239
+ def register_workflow(workflow, options = {})
240
+ expect! workflow => [ Module, String ]
241
+
242
+ workflow.extend Postjob::Workflow if workflow.is_a?(Module)
243
+ Registry.register workflow, options
151
244
  end
152
245
 
153
246
  private
@@ -177,23 +270,4 @@ module Postjob
177
270
 
178
271
  shutdown
179
272
  end
180
-
181
- public
182
-
183
- def resolve(token:, result:)
184
- job = Queue.find_job_by_token(token)
185
- raise "No job with token #{token}" unless job
186
-
187
- Queue.set_job_result current_worker_session.id, job, result, version: nil
188
- end
189
-
190
- def register_workflow(workflow, options = {})
191
- expect! options => {
192
- version: [nil, /^\d+(\.\d+)*/]
193
- }
194
-
195
- workflow.include Postjob::Workflow
196
- workflow.send(:set_workflow_version, options[:version] || "0.0")
197
- Registry.register workflow, options
198
- end
199
273
  end
@@ -26,7 +26,7 @@ require "vmstat/task"
26
26
  # and yields current measurements once a second.
27
27
  #
28
28
  #
29
- module Heartbeat
29
+ module Heartbeat # :nodoc:
30
30
  # The heartbeat monitor watches various machine metrics (disk usage, CPU load, network traffic)
31
31
  # and yields current measurements once every cycle_length_seconds seconds.
32
32
 
@@ -62,7 +62,7 @@ module Heartbeat
62
62
  end
63
63
  end
64
64
 
65
- class Monitor
65
+ class Monitor # :nodoc:
66
66
  def initialize(cycle_length_seconds)
67
67
  @history = History.new(15 * 60 / cycle_length_seconds + 1)
68
68
  @cycle_length_seconds = cycle_length_seconds
data/lib/tools/history.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # A History object, which holds the last +size+ objects in memory.
2
2
  #
3
3
  # Implemented as a ring buffer which wraps over.
4
- class History
4
+ class History # :nodoc:
5
5
  attr_reader :size
6
6
 
7
7
  def initialize(size)
@@ -2,6 +2,9 @@ require "spec_helper"
2
2
 
3
3
  describe "Postjob.enqueue!" do
4
4
  let(:workflow_name) { "WorkflowName" }
5
+ before(:all) do
6
+ Postjob.register_workflow "WorkflowName"
7
+ end
5
8
 
6
9
  include TestHelper
7
10
 
@@ -3,83 +3,21 @@ require "spec_helper"
3
3
  describe "Heartbeat Events" do
4
4
  include TestHelper
5
5
 
6
- # This test uses the nil host_id, which is configured during migration.
7
- let(:null_host_id) { "00000000-0000-0000-0000-000000000000" }
8
-
9
- def heartbeat!(host_id: nil)
10
- host_id ||= null_host_id
11
- Postjob::WorkerSession.send(:run_heartbeat_monitor, host_id) do
12
- # By returning false we create only a single heartbeat event
13
- false
6
+ describe "::Postjob::Queue.host_heartbeat" do
7
+ def run!
8
+ ::Postjob::Queue.host_heartbeat(null_host_id, {})
14
9
  end
15
- end
16
-
17
- describe "creation" do
18
- before { heartbeat! }
19
10
 
20
11
  it "creates a heartbeat event" do
21
- event = Simple::SQL.ask <<~SQL, into: OpenStruct
22
- SELECT * FROM postjob.events
23
- WHERE name='heartbeat' ORDER BY created_at DESC
24
- SQL
25
-
26
- expect(event.worker_session_id).to be_nil
27
- expect(event.host_id).to eq(null_host_id)
28
-
29
- expected_keys = %w(
30
- cpu_load_1min cpu_load_5min cpu_load_15min
31
- disk_available disk_used
32
- net_errors_1min net_errors_5min net_errors_15min
33
- net_in_1min net_in_5min net_in_15min
34
- net_out_1min net_out_5min net_out_15min
35
- uptime
36
- )
37
-
38
- expect(event.attributes.keys).to include(*expected_keys)
39
- end
12
+ run!
40
13
 
41
- it "creates a zombie event" do
42
14
  event = Simple::SQL.ask <<~SQL, into: OpenStruct
43
15
  SELECT * FROM postjob.events
44
- WHERE name='zombie' ORDER BY created_at DESC
16
+ WHERE name='heartbeat' ORDER BY created_at DESC
45
17
  SQL
46
18
 
47
19
  expect(event.worker_session_id).to be_nil
48
20
  expect(event.host_id).to eq(null_host_id)
49
- expect(event.attributes.keys).to eq([ "zombie_count" ])
50
- expect(event.attributes["zombie_count"]).to be_a(Integer)
51
- end
52
- end
53
-
54
- describe "zombie checking" do
55
- let!(:job_id) { Postjob.enqueue! "HeartbeatSpecWorkflow" }
56
-
57
- before do
58
- # change the job status to processing, and move all timestamps into the past.
59
- # This simulates a zombie situation.
60
- Simple::SQL.ask "UPDATE postjob.postjobs SET status='processing' WHERE id=$1", job_id
61
- Simple::SQL.ask "UPDATE postjob.events SET created_at = (now() at time zone 'utc' - interval '2 hours')"
62
- end
63
-
64
- context "when running with the real host_id" do
65
- it "detects zombies" do
66
- job = load_job(job_id)
67
- session = Simple::SQL.ask "SELECT * FROM postjob.worker_sessions WHERE id=$1", job.last_worker_session_id, into: OpenStruct
68
-
69
- heartbeat! host_id: session.host_id
70
-
71
- job = Simple::SQL.ask "SELECT * FROM postjob.postjobs WHERE id=$1", job_id, into: Hash
72
- expect(job).to include(status: "err", failed_attempts: 1, error: "Zombie", error_message: "zombie")
73
- end
74
- end
75
-
76
- context "when running with a different host_id" do
77
- it "detects zombies" do
78
- heartbeat!
79
-
80
- job = Simple::SQL.ask "SELECT * FROM postjob.postjobs WHERE id=$1", job_id, into: Hash
81
- expect(job).to include(status: "err", failed_attempts: 1, error: "Zombie", error_message: "zombie")
82
- end
83
21
  end
84
22
  end
85
23
  end
@@ -0,0 +1,61 @@
1
+ require "spec_helper"
2
+
3
+ module HeartbeatSpecWorkflow
4
+ Postjob.register_workflow self
5
+ end
6
+
7
+ describe "Heartbeat Events" do
8
+ include TestHelper
9
+
10
+ before do
11
+ Postjob.enqueue! "HeartbeatSpecWorkflow"
12
+
13
+ @host_id = Simple::SQL.ask "SELECT id FROM postjob.hosts WHERE id != $1", null_host_id
14
+
15
+ send_heartbeat!
16
+
17
+ Simple::SQL.ask "UPDATE postjob.postjobs SET status='processing'"
18
+ end
19
+
20
+ let(:host_id) { @host_id || raise("host_id must be set") }
21
+
22
+ def send_heartbeat!
23
+ ::Postjob::Queue.host_heartbeat(host_id, {})
24
+ end
25
+
26
+ describe "::Postjob::Queue.host_heartbeat" do
27
+ context "zombies in the database" do
28
+ before do
29
+ Simple::SQL.ask "UPDATE postjob.events SET created_at = (now() at time zone 'utc' - interval '2 days')"
30
+ end
31
+
32
+ it "does creates a zombie events" do
33
+ send_heartbeat!
34
+
35
+ event = Simple::SQL.ask <<~SQL, into: Hash
36
+ SELECT * FROM postjob.events
37
+ WHERE name='zombie' ORDER BY created_at DESC
38
+ SQL
39
+
40
+ expect(event).to include(
41
+ attributes: { "zombie_count" => 1 },
42
+ name: "zombie",
43
+ postjob_id: nil
44
+ )
45
+ end
46
+ end
47
+ end
48
+
49
+ context "no zombies in the database, 2" do
50
+ it "does creates a zombie events" do
51
+ send_heartbeat!
52
+
53
+ event = Simple::SQL.ask <<~SQL, into: Hash
54
+ SELECT * FROM postjob.events
55
+ WHERE name='zombie' ORDER BY created_at DESC
56
+ SQL
57
+
58
+ expect(event).to be_nil
59
+ end
60
+ end
61
+ end
@@ -1,7 +1,7 @@
1
1
  require "spec_helper"
2
2
 
3
3
  describe "Postjob::WorkerSession.start!" do
4
- let(:store_path) { ".postjob.host_id" }
4
+ let(:store_path) { ".postjob.test.host_id" }
5
5
 
6
6
  def session_count
7
7
  Simple::SQL.ask "SELECT count(*) from postjob.worker_sessions"
@@ -15,27 +15,4 @@ describe "Postjob::WorkerSession.start!" do
15
15
  expect(session.id).to match(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/i)
16
16
  end.to change { session_count }.by(1)
17
17
  end
18
-
19
- it "stores and reuses the host_id" do
20
- FileUtils.rm_rf store_path
21
-
22
- session = Postjob::WorkerSession.start!(workflows_with_versions)
23
- expect(File.read(store_path)).to match(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/i)
24
-
25
- session2 = Postjob::WorkerSession.start!(workflows_with_versions)
26
- expect(session2.host_id).to eq(session.host_id)
27
- end
28
-
29
- context "when passing in an invalid host id" do
30
- it "raises an argument error" do
31
- invalid_uuid = "foo"
32
- File.open store_path, "w" do |io|
33
- io.write invalid_uuid
34
- end
35
-
36
- expect do
37
- Postjob::WorkerSession.start!(workflows_with_versions)
38
- end.to raise_error(ArgumentError)
39
- end
40
- end
41
18
  end
data/spec/spec_helper.rb CHANGED
@@ -40,6 +40,6 @@ RSpec.configure do |config|
40
40
  config.after {}
41
41
 
42
42
  config.before(:all) do
43
- FileUtils.rm_rf ::Postjob::WorkerSession::HOST_ID_PATH
43
+ ::Postjob::Host.clear_storage
44
44
  end
45
45
  end
@@ -1,18 +1,9 @@
1
1
  require "active_record"
2
- ActiveRecord::Base.establish_connection(adapter: "postgresql",
3
- database: "postjob_test",
4
- username: "postjob",
5
- password: "postjob")
6
2
 
7
- # RSpec.configure do |config|
8
- # config.around(:each) do |example|
9
- # if example.metadata[:transactions] == false
10
- # example.run
11
- # else
12
- # ::ActiveRecord::Base.connection.transaction do
13
- # example.run
14
- # raise ActiveRecord::Rollback, "clean up"
15
- # end
16
- # end
17
- # end
18
- # end
3
+ lambda do
4
+ require "yaml"
5
+ configs = YAML.load_file "config/database.yml"
6
+ config = configs.fetch("test")
7
+
8
+ ActiveRecord::Base.establish_connection(config)
9
+ end.call
@@ -5,9 +5,20 @@ else
5
5
  end
6
6
 
7
7
  RSpec.configure do |config|
8
+ # This test uses the nil host_id, which is configured during migration.
9
+ def null_host_id
10
+ "00000000-0000-0000-0000-000000000000"
11
+ end
12
+
8
13
  config.around(:each) do |example|
9
14
  Simple::SQL.ask "DELETE FROM postjob.postjobs"
10
15
  Simple::SQL.ask "DELETE FROM postjob.tokens"
16
+ Simple::SQL.ask "DELETE FROM postjob.events"
17
+ Simple::SQL.ask "DELETE FROM postjob.tokens"
18
+
19
+ # Simple::SQL.ask "DELETE FROM postjob.hosts"
20
+ # Simple::SQL.ask "DELETE FROM postjob.worker_sessions"
21
+
11
22
  example.run
12
23
  end
13
24
  end
@@ -1,17 +1 @@
1
- ENV["DATABASE_URL"] = "postgresql://postjob:postjob@localhost/postjob_test"
2
1
  ::Simple::SQL.connect!
3
-
4
- # RSpec.configure do |config|
5
- # config.around(:each) do |example|
6
- # if example.metadata[:transactions] == false
7
- # example.run
8
- # else
9
- # catch(:rollback) do
10
- # ::Simple::SQL.transaction do
11
- # example.run
12
- # throw :rollback
13
- # end
14
- # end
15
- # end
16
- # end
17
- # 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.5.5
4
+ version: 0.5.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - radiospiel
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-08-01 00:00:00.000000000 Z
11
+ date: 2018-08-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -226,7 +226,9 @@ files:
226
226
  - bin/postjob
227
227
  - lib/postjob.rb
228
228
  - lib/postjob/cli.rb
229
+ - lib/postjob/cli/cron.rb
229
230
  - lib/postjob/cli/db.rb
231
+ - lib/postjob/cli/enqueue.rb
230
232
  - lib/postjob/cli/events.rb
231
233
  - lib/postjob/cli/heartbeat.rb
232
234
  - lib/postjob/cli/hosts.rb
@@ -236,6 +238,7 @@ files:
236
238
  - lib/postjob/cli/sessions.rb
237
239
  - lib/postjob/cli/version.rb
238
240
  - lib/postjob/error.rb
241
+ - lib/postjob/host.rb
239
242
  - lib/postjob/job.rb
240
243
  - lib/postjob/migrations.rb
241
244
  - lib/postjob/migrations/002_statuses.rb
@@ -247,19 +250,21 @@ files:
247
250
  - lib/postjob/migrations/006_enqueue.sql
248
251
  - lib/postjob/migrations/006a_processing.sql
249
252
  - lib/postjob/migrations/007_job_results.sql
250
- - lib/postjob/migrations/008_checkout_runnable.sql
251
253
  - lib/postjob/migrations/008a_childjobs.sql
252
254
  - lib/postjob/migrations/009_tokens.sql
253
255
  - lib/postjob/migrations/010_settings.sql
254
256
  - lib/postjob/migrations/011_null_uuid.sql
255
257
  - lib/postjob/migrations/012_hosts.sql
256
258
  - lib/postjob/migrations/013_worker_sessions.sql
259
+ - lib/postjob/migrations/013a_checkout_runnable.sql
257
260
  - lib/postjob/migrations/014_postjob_session_id.sql
258
261
  - lib/postjob/migrations/015_events.sql
259
262
  - lib/postjob/migrations/016_sessions_functions.sql
260
263
  - lib/postjob/migrations/017_zombie_check.sql
261
264
  - lib/postjob/migrations/018_heartbeat.sql
262
265
  - lib/postjob/migrations/019_heartbeat_indices.sql
266
+ - lib/postjob/migrations/021_cron_jobs.sql
267
+ - lib/postjob/migrations/023_sticky_jobs.sql
263
268
  - lib/postjob/queue.rb
264
269
  - lib/postjob/queue/associations.rb
265
270
  - lib/postjob/queue/encoder.rb
@@ -273,12 +278,12 @@ files:
273
278
  - lib/postjob/runner.rb
274
279
  - lib/postjob/worker_session.rb
275
280
  - lib/postjob/workflow.rb
276
- - lib/tools/atomic_store.rb
277
281
  - lib/tools/heartbeat.rb
278
282
  - lib/tools/history.rb
279
283
  - spec/postjob/enqueue_spec.rb
280
284
  - spec/postjob/events/heartbeat_event_spec.rb
281
285
  - spec/postjob/events/job_event_spec.rb
286
+ - spec/postjob/events/zombie_event_spec.rb
282
287
  - spec/postjob/full_workflow_spec.rb
283
288
  - spec/postjob/job_control/error_status_spec.rb
284
289
  - spec/postjob/job_control/manual_spec.rb
@@ -317,7 +322,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
317
322
  version: '0'
318
323
  requirements: []
319
324
  rubyforge_project:
320
- rubygems_version: 2.5.1
325
+ rubygems_version: 2.7.7
321
326
  signing_key:
322
327
  specification_version: 4
323
328
  summary: restartable, asynchronous, and distributed processes
@@ -1,17 +0,0 @@
1
- module AtomicStore
2
- def self.with(path)
3
- File.open(path, File::RDWR | File::CREAT, 0644) do |f|
4
- f.flock(File::LOCK_EX)
5
- value = f.read
6
- value = nil if value == ""
7
- new_value = yield value
8
- expect! new_value => /./
9
- next if new_value == value
10
-
11
- f.rewind
12
- f.write(new_value)
13
- f.flush
14
- f.truncate(f.pos)
15
- end
16
- end
17
- end