postjob 0.5.5 → 0.5.6

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