rocketjob 0.8.0 → 0.9.0
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 +4 -4
- data/README.md +1 -1
- data/lib/rocket_job/cli.rb +4 -4
- data/lib/rocket_job/concerns/worker.rb +5 -5
- data/lib/rocket_job/config.rb +8 -8
- data/lib/rocket_job/heartbeat.rb +5 -5
- data/lib/rocket_job/job.rb +69 -38
- data/lib/rocket_job/job_exception.rb +3 -3
- data/lib/rocket_job/version.rb +1 -1
- data/lib/rocket_job/{server.rb → worker.rb} +47 -47
- data/lib/rocketjob.rb +1 -1
- data/test/dirmon_job_test.rb +2 -2
- data/test/job_test.rb +20 -20
- data/test/job_worker_test.rb +85 -0
- data/test/worker_test.rb +28 -74
- metadata +5 -5
- data/test/server_test.rb +0 -39
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c01cfe6dbadea5f8d327a520b68c7262b1bcff96
|
4
|
+
data.tar.gz: 4e52926f26dc216852bae81f780b48103a5625fe
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3286460b8ce4f27c31c47226b5d157c62541114f0c645b1260ff6cbe86cdd23f985bd6c180024b2812bf8b0ca650634e186f28faf0f5a87c0648a2cdd3edcff3
|
7
|
+
data.tar.gz: 26af31595e81983ab38e70fbc2b2d1c5101a876bfa2fcfdf9a465648e87269f42c70ee9fb580b9bfda6cfbacec18d67d36d502d235d3a22e0e7e8d5a372947af
|
data/README.md
CHANGED
@@ -80,7 +80,7 @@ This differs from the traditional approach of separate queues for jobs which
|
|
80
80
|
quickly becomes cumbersome when there are for example over a hundred different
|
81
81
|
types of jobs.
|
82
82
|
|
83
|
-
The global priority based queue ensures that the
|
83
|
+
The global priority based queue ensures that the workers are utilized to their
|
84
84
|
capacity without requiring constant manual intervention.
|
85
85
|
|
86
86
|
`rocketjob` is designed to handle hundreds of millions of concurrent jobs
|
data/lib/rocket_job/cli.rb
CHANGED
@@ -15,7 +15,7 @@ module RocketJob
|
|
15
15
|
parse(argv)
|
16
16
|
end
|
17
17
|
|
18
|
-
# Run a RocketJob::
|
18
|
+
# Run a RocketJob::Worker from the command line
|
19
19
|
def run
|
20
20
|
SemanticLogger.add_appender(STDOUT, &SemanticLogger::Appender::Base.colorized_formatter) unless quiet
|
21
21
|
boot_rails if defined?(:Rails)
|
@@ -24,14 +24,14 @@ module RocketJob
|
|
24
24
|
opts = {}
|
25
25
|
opts[:name] = name if name
|
26
26
|
opts[:max_threads] = threads if threads
|
27
|
-
|
27
|
+
Worker.run(opts)
|
28
28
|
end
|
29
29
|
|
30
30
|
# Initialize the Rails environment
|
31
31
|
def boot_rails
|
32
32
|
require File.expand_path("#{directory}/config/environment.rb")
|
33
33
|
if Rails.configuration.eager_load
|
34
|
-
RocketJob::
|
34
|
+
RocketJob::Worker.logger.benchmark_info('Eager loaded Rails and all Engines') do
|
35
35
|
Rails.application.eager_load!
|
36
36
|
Rails::Engine.subclasses.each { |engine| engine.eager_load! }
|
37
37
|
end
|
@@ -53,7 +53,7 @@ module RocketJob
|
|
53
53
|
# Parse command line options placing results in the corresponding instance variables
|
54
54
|
def parse(argv)
|
55
55
|
parser = OptionParser.new do |o|
|
56
|
-
o.on('-n', '--name NAME', 'Unique Name of this
|
56
|
+
o.on('-n', '--name NAME', 'Unique Name of this worker instance (Default: hostname:PID)') { |arg| @name = arg }
|
57
57
|
o.on('-t', '--threads COUNT', 'Number of worker threads to start') { |arg| @threads = arg.to_i }
|
58
58
|
o.on('-q', '--quiet', 'Do not write to stdout, only to logfile. Necessary when running as a daemon') { @quiet = true }
|
59
59
|
o.on('-d', '--dir DIR', 'Directory containing Rails app, if not current directory') { |arg| @directory = arg }
|
@@ -29,10 +29,10 @@ module RocketJob
|
|
29
29
|
# Create a job and process it immediately in-line by this thread
|
30
30
|
def now(method, *args, &block)
|
31
31
|
job = build(method, *args, &block)
|
32
|
-
|
33
|
-
|
32
|
+
worker = RocketJob::Worker.new(name: 'inline')
|
33
|
+
worker.started
|
34
34
|
job.start
|
35
|
-
while job.running? && !job.work(
|
35
|
+
while job.running? && !job.work(worker)
|
36
36
|
end
|
37
37
|
job
|
38
38
|
end
|
@@ -86,7 +86,7 @@ module RocketJob
|
|
86
86
|
# is set in the job itself.
|
87
87
|
#
|
88
88
|
# Thread-safe, can be called by multiple threads at the same time
|
89
|
-
def work(
|
89
|
+
def work(worker)
|
90
90
|
raise 'Job must be started before calling #work' unless running?
|
91
91
|
begin
|
92
92
|
# before_perform
|
@@ -102,7 +102,7 @@ module RocketJob
|
|
102
102
|
call_method(perform_method, arguments, event: :after, log_level: log_level)
|
103
103
|
complete!
|
104
104
|
rescue Exception => exc
|
105
|
-
set_exception(
|
105
|
+
set_exception(worker.name, exc)
|
106
106
|
raise exc if RocketJob::Config.inline_mode
|
107
107
|
end
|
108
108
|
false
|
data/lib/rocket_job/config.rb
CHANGED
@@ -21,16 +21,16 @@ module RocketJob
|
|
21
21
|
end
|
22
22
|
|
23
23
|
# By enabling inline_mode jobs will be called in-line
|
24
|
-
# No
|
24
|
+
# No worker processes will be created, nor threads created
|
25
25
|
sync_cattr_accessor(:inline_mode) { false }
|
26
26
|
|
27
|
-
# The maximum number of worker threads to create on any one
|
27
|
+
# The maximum number of worker threads to create on any one worker
|
28
28
|
key :max_worker_threads, Integer, default: 10
|
29
29
|
|
30
|
-
# Number of seconds between heartbeats from Rocket Job
|
30
|
+
# Number of seconds between heartbeats from Rocket Job Worker processes
|
31
31
|
key :heartbeat_seconds, Integer, default: 15
|
32
32
|
|
33
|
-
# Maximum number of seconds a
|
33
|
+
# Maximum number of seconds a Worker will wait before checking for new jobs
|
34
34
|
key :max_poll_seconds, Integer, default: 5
|
35
35
|
|
36
36
|
# Number of seconds between checking for:
|
@@ -44,21 +44,21 @@ module RocketJob
|
|
44
44
|
# Not all job types support pausing in the middle
|
45
45
|
key :re_check_seconds, Integer, default: 60
|
46
46
|
|
47
|
-
# Limit the number of workers per job class per
|
47
|
+
# Limit the number of workers per job class per worker
|
48
48
|
# 'class_name' / group => 100
|
49
49
|
#key :limits, Hash
|
50
50
|
|
51
51
|
# Replace the MongoMapper default mongo connection for holding jobs
|
52
52
|
def self.mongo_connection=(connection)
|
53
53
|
connection(connection)
|
54
|
-
|
54
|
+
Worker.connection(connection)
|
55
55
|
Job.connection(connection)
|
56
56
|
Config.connection(connection)
|
57
57
|
DirmonEntry.connection(connection)
|
58
58
|
|
59
59
|
db_name = connection.db.name
|
60
60
|
set_database_name(db_name)
|
61
|
-
|
61
|
+
Worker.set_database_name(db_name)
|
62
62
|
Job.set_database_name(db_name)
|
63
63
|
Config.set_database_name(db_name)
|
64
64
|
DirmonEntry.set_database_name(db_name)
|
@@ -68,7 +68,7 @@ module RocketJob
|
|
68
68
|
# Allows the records and results to be stored in a separate Mongo database
|
69
69
|
# from the Jobs themselves.
|
70
70
|
#
|
71
|
-
# It is recommended to set the work_connection to a local Mongo
|
71
|
+
# It is recommended to set the work_connection to a local Mongo Worker that
|
72
72
|
# is not replicated to another data center to prevent flooding the network
|
73
73
|
# with replication of data records and results.
|
74
74
|
# The jobs themselves can/should be replicated across data centers so that
|
data/lib/rocket_job/heartbeat.rb
CHANGED
@@ -2,13 +2,13 @@
|
|
2
2
|
module RocketJob
|
3
3
|
# Heartbeat
|
4
4
|
#
|
5
|
-
# Information from the
|
5
|
+
# Information from the worker as at it's last heartbeat
|
6
6
|
class Heartbeat
|
7
7
|
include MongoMapper::EmbeddedDocument
|
8
8
|
|
9
|
-
embedded_in :
|
9
|
+
embedded_in :worker
|
10
10
|
|
11
|
-
# Time of the last heartbeat received from this
|
11
|
+
# Time of the last heartbeat received from this worker
|
12
12
|
key :updated_at, Time
|
13
13
|
|
14
14
|
# Number of threads running as at the last heartbeat interval
|
@@ -21,9 +21,9 @@ module RocketJob
|
|
21
21
|
# Process Information
|
22
22
|
#
|
23
23
|
|
24
|
-
# Percentage utilization for the
|
24
|
+
# Percentage utilization for the worker process alone
|
25
25
|
key :process_cpu, Integer
|
26
|
-
# Kilo Bytes used by the
|
26
|
+
# Kilo Bytes used by the worker process (Virtual & Physical)
|
27
27
|
key :process_mem_phys_kb, Integer
|
28
28
|
key :process_mem_virt_kb, Integer
|
29
29
|
|
data/lib/rocket_job/job.rb
CHANGED
@@ -94,8 +94,8 @@ module RocketJob
|
|
94
94
|
# Number of times that this job has failed to process
|
95
95
|
key :failure_count, Integer, default: 0
|
96
96
|
|
97
|
-
# This name of the
|
98
|
-
key :
|
97
|
+
# This name of the worker that this job is being processed by, or was processed by
|
98
|
+
key :worker_name, String
|
99
99
|
|
100
100
|
#
|
101
101
|
# Values that jobs can update during processing
|
@@ -196,11 +196,11 @@ module RocketJob
|
|
196
196
|
ensure_index [[:created_at, 1]]
|
197
197
|
end
|
198
198
|
|
199
|
-
# Requeue all jobs for the specified dead
|
200
|
-
def self.
|
199
|
+
# Requeue all jobs for the specified dead worker
|
200
|
+
def self.requeue_dead_worker(worker_name)
|
201
201
|
collection.update(
|
202
|
-
{ '
|
203
|
-
{ '$unset' => { '
|
202
|
+
{ 'worker_name' => worker_name, 'state' => :running },
|
203
|
+
{ '$unset' => { 'worker_name' => true, 'started_at' => true }, '$set' => { 'state' => :queued } },
|
204
204
|
multi: true
|
205
205
|
)
|
206
206
|
end
|
@@ -220,17 +220,18 @@ module RocketJob
|
|
220
220
|
collect_output == true
|
221
221
|
end
|
222
222
|
|
223
|
-
# Returns [
|
224
|
-
#
|
225
|
-
|
226
|
-
|
223
|
+
# Returns [Float] the number of seconds the job has taken
|
224
|
+
# - Elapsed seconds to process the job from when a worker first started working on it
|
225
|
+
# until now if still running, or until it was completed
|
226
|
+
# - Seconds in the queue if queued
|
227
|
+
def seconds
|
228
|
+
if completed_at
|
227
229
|
completed_at - (started_at || created_at)
|
228
230
|
elsif started_at
|
229
231
|
Time.now - started_at
|
230
232
|
else
|
231
233
|
Time.now - created_at
|
232
234
|
end
|
233
|
-
Time.at(seconds)
|
234
235
|
end
|
235
236
|
|
236
237
|
# A job has expired if the expiry time has passed before it is started
|
@@ -239,28 +240,46 @@ module RocketJob
|
|
239
240
|
end
|
240
241
|
|
241
242
|
# Returns [Hash] status of this job
|
242
|
-
def
|
243
|
-
|
244
|
-
|
245
|
-
description: description
|
246
|
-
}
|
247
|
-
h[:started_at] = started_at.in_time_zone(time_zone) if started_at
|
248
|
-
|
243
|
+
def as_json
|
244
|
+
attrs = serializable_hash(methods: :seconds)
|
245
|
+
attrs.delete('result') unless collect_output?
|
249
246
|
case
|
250
|
-
when running?
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
247
|
+
when running?
|
248
|
+
attrs.delete('completed_at')
|
249
|
+
attrs.delete('result')
|
250
|
+
attrs
|
251
|
+
when paused?
|
252
|
+
attrs.delete('completed_at')
|
253
|
+
attrs.delete('result')
|
254
|
+
# Ensure 'paused_at' appears first in the hash
|
255
|
+
{ 'paused_at' => completed_at }.merge(attrs)
|
255
256
|
when aborted?
|
256
|
-
|
257
|
-
|
257
|
+
attrs.delete('completed_at')
|
258
|
+
attrs.delete('result')
|
259
|
+
{ 'aborted_at' => completed_at }.merge(attrs)
|
258
260
|
when failed?
|
259
|
-
|
260
|
-
|
261
|
-
|
261
|
+
attrs.delete('completed_at')
|
262
|
+
attrs.delete('result')
|
263
|
+
{ 'failed_at' => completed_at }.merge(attrs)
|
264
|
+
else
|
265
|
+
attrs
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
def status(time_zone='Eastern Time (US & Canada)')
|
270
|
+
h = as_json
|
271
|
+
if seconds = h.delete('seconds')
|
272
|
+
h['duration'] = seconds_as_duration(seconds)
|
273
|
+
end
|
274
|
+
h.delete('perform_method') if h['perform_method'] == :perform
|
275
|
+
h.dup.each_pair do |k,v|
|
276
|
+
case
|
277
|
+
when v.kind_of?(Time)
|
278
|
+
h[k] = v.in_time_zone(time_zone).to_s
|
279
|
+
when v.kind_of?(BSON::ObjectId)
|
280
|
+
h[k] = v.to_s
|
281
|
+
end
|
262
282
|
end
|
263
|
-
h[:duration] = duration.strftime('%H:%M:%S')
|
264
283
|
h
|
265
284
|
end
|
266
285
|
|
@@ -288,6 +307,7 @@ module RocketJob
|
|
288
307
|
self.arguments = arguments.collect {|i| i.is_a?(BSON::OrderedHash) ? i.with_indifferent_access : i } if arguments.present?
|
289
308
|
end
|
290
309
|
|
310
|
+
############################################################################
|
291
311
|
protected
|
292
312
|
|
293
313
|
# Before events that can be overridden by child classes
|
@@ -320,23 +340,34 @@ module RocketJob
|
|
320
340
|
self.completed_at = Time.now
|
321
341
|
end
|
322
342
|
|
323
|
-
|
324
|
-
|
343
|
+
# Returns a human readable duration from the supplied [Float] number of seconds
|
344
|
+
def seconds_as_duration(seconds)
|
345
|
+
time = Time.at(seconds)
|
346
|
+
if seconds >= 1.day
|
347
|
+
"#{seconds / 1.day}d #{time.strftime('%-Hh %-Mm %-Ss')}"
|
348
|
+
elsif seconds >= 1.hour
|
349
|
+
time.strftime('%-Hh %-Mm %-Ss')
|
350
|
+
elsif seconds >= 1.minute
|
351
|
+
time.strftime('%-Mm %-Ss')
|
352
|
+
else
|
353
|
+
time.strftime('%-Ss')
|
354
|
+
end
|
355
|
+
end
|
325
356
|
|
326
357
|
# Returns the next job to work on in priority based order
|
327
358
|
# Returns nil if there are currently no queued jobs, or processing batch jobs
|
328
359
|
# with records that require processing
|
329
360
|
#
|
330
361
|
# Parameters
|
331
|
-
#
|
332
|
-
# Name of the
|
362
|
+
# worker_name [String]
|
363
|
+
# Name of the worker that will be processing this job
|
333
364
|
#
|
334
365
|
# skip_job_ids [Array<BSON::ObjectId>]
|
335
366
|
# Job ids to exclude when looking for the next job
|
336
367
|
#
|
337
368
|
# Note:
|
338
369
|
# If a job is in queued state it will be started
|
339
|
-
def self.next_job(
|
370
|
+
def self.next_job(worker_name, skip_job_ids = nil)
|
340
371
|
query = {
|
341
372
|
'$and' => [
|
342
373
|
{
|
@@ -358,7 +389,7 @@ module RocketJob
|
|
358
389
|
while doc = find_and_modify(
|
359
390
|
query: query,
|
360
391
|
sort: [['priority', 'asc'], ['created_at', 'asc']],
|
361
|
-
update: { '$set' => { '
|
392
|
+
update: { '$set' => { 'worker_name' => worker_name, 'state' => 'running' } }
|
362
393
|
)
|
363
394
|
job = load(doc)
|
364
395
|
if job.running?
|
@@ -381,11 +412,11 @@ module RocketJob
|
|
381
412
|
private
|
382
413
|
|
383
414
|
# Set exception information for this job
|
384
|
-
def set_exception(
|
385
|
-
self.
|
415
|
+
def set_exception(worker_name, exc)
|
416
|
+
self.worker_name = nil
|
386
417
|
self.failure_count += 1
|
387
418
|
self.exception = JobException.from_exception(exc)
|
388
|
-
exception.
|
419
|
+
exception.worker_name = worker_name
|
389
420
|
fail! unless failed?
|
390
421
|
logger.error("Exception running #{self.class.name}##{perform_method}", exc)
|
391
422
|
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
module RocketJob
|
3
3
|
# Heartbeat
|
4
4
|
#
|
5
|
-
# Information from the
|
5
|
+
# Information from the worker as at it's last heartbeat
|
6
6
|
class JobException
|
7
7
|
include MongoMapper::EmbeddedDocument
|
8
8
|
|
@@ -15,8 +15,8 @@ module RocketJob
|
|
15
15
|
# Exception Backtrace [Array<String>]
|
16
16
|
key :backtrace, Array
|
17
17
|
|
18
|
-
# Name of the
|
19
|
-
key :
|
18
|
+
# Name of the worker on which this exception occurred
|
19
|
+
key :worker_name, String
|
20
20
|
|
21
21
|
# The record within which this exception occurred
|
22
22
|
key :record_number, Integer
|
data/lib/rocket_job/version.rb
CHANGED
@@ -3,31 +3,31 @@ require 'socket'
|
|
3
3
|
require 'sync_attr'
|
4
4
|
require 'aasm'
|
5
5
|
module RocketJob
|
6
|
-
#
|
6
|
+
# Worker
|
7
7
|
#
|
8
|
-
# On startup a
|
8
|
+
# On startup a worker instance will automatically register itself
|
9
9
|
# if not already present
|
10
10
|
#
|
11
|
-
# Starting a
|
11
|
+
# Starting a worker in the foreground:
|
12
12
|
# - Using a Rails runner:
|
13
13
|
# bin/rocketjob
|
14
14
|
#
|
15
|
-
# Starting a
|
15
|
+
# Starting a worker in the background:
|
16
16
|
# - Using a Rails runner:
|
17
17
|
# nohup bin/rocketjob --quiet 2>&1 1>output.log &
|
18
18
|
#
|
19
|
-
# Stopping a
|
20
|
-
# - Stop the
|
19
|
+
# Stopping a worker:
|
20
|
+
# - Stop the worker via the Web UI
|
21
21
|
# - Send a regular kill signal to make it shutdown once all active work is complete
|
22
22
|
# kill <pid>
|
23
23
|
# - Or, use the following Ruby code:
|
24
|
-
#
|
25
|
-
#
|
24
|
+
# worker = RocketJob::Worker.where(name: 'worker name').first
|
25
|
+
# worker.stop!
|
26
26
|
#
|
27
27
|
# Sending the kill signal locally will result in starting the shutdown process
|
28
|
-
# immediately. Via the UI or Ruby code the
|
28
|
+
# immediately. Via the UI or Ruby code the worker can take up to 15 seconds
|
29
29
|
# (the heartbeat interval) to start shutting down.
|
30
|
-
class
|
30
|
+
class Worker
|
31
31
|
include MongoMapper::Document
|
32
32
|
include AASM
|
33
33
|
include SyncAttr
|
@@ -36,21 +36,21 @@ module RocketJob
|
|
36
36
|
# Prevent data in MongoDB from re-defining the model behavior
|
37
37
|
#self.static_keys = true
|
38
38
|
|
39
|
-
# Unique Name of this
|
40
|
-
# Defaults to the `hostname` but _must_ be overriden if mutiple
|
39
|
+
# Unique Name of this worker instance
|
40
|
+
# Defaults to the `hostname` but _must_ be overriden if mutiple Worker instances
|
41
41
|
# are started on the same host
|
42
42
|
# The unique name is used on re-start to re-queue any jobs that were being processed
|
43
|
-
# at the time the
|
43
|
+
# at the time the worker or host unexpectedly terminated, if any
|
44
44
|
key :name, String, default: -> { "#{Socket.gethostname}:#{$$}" }
|
45
45
|
|
46
46
|
# The maximum number of threads that this worker should use
|
47
47
|
# If set, it will override the default value in RocketJob::Config
|
48
48
|
key :max_threads, Integer, default: -> { Config.instance.max_worker_threads }
|
49
49
|
|
50
|
-
# When this
|
50
|
+
# When this worker process was started
|
51
51
|
key :started_at, Time
|
52
52
|
|
53
|
-
# The heartbeat information for this
|
53
|
+
# The heartbeat information for this worker
|
54
54
|
one :heartbeat, class_name: 'RocketJob::Heartbeat'
|
55
55
|
|
56
56
|
# Current state
|
@@ -89,20 +89,20 @@ module RocketJob
|
|
89
89
|
|
90
90
|
attr_reader :thread_pool
|
91
91
|
|
92
|
-
# Requeue any jobs being worked by this
|
92
|
+
# Requeue any jobs being worked by this worker when it is destroyed
|
93
93
|
before_destroy :requeue_jobs
|
94
94
|
|
95
|
-
# Run the
|
95
|
+
# Run the worker process
|
96
96
|
# Attributes supplied are passed to #new
|
97
97
|
def self.run(attrs={})
|
98
|
-
|
99
|
-
|
100
|
-
|
98
|
+
worker = new(attrs)
|
99
|
+
worker.build_heartbeat
|
100
|
+
worker.save!
|
101
101
|
create_indexes
|
102
102
|
register_signal_handlers
|
103
103
|
raise "The RocketJob configuration is being applied after the system has been initialized" unless RocketJob::Job.database.name == RocketJob::SlicedJob.database.name
|
104
104
|
logger.info "Using MongoDB Database: #{RocketJob::Job.database.name}"
|
105
|
-
|
105
|
+
worker.run
|
106
106
|
end
|
107
107
|
|
108
108
|
# Create indexes
|
@@ -112,40 +112,40 @@ module RocketJob
|
|
112
112
|
Job.create_indexes
|
113
113
|
end
|
114
114
|
|
115
|
-
# Destroy dead
|
116
|
-
# Requeue jobs assigned to dead
|
117
|
-
# Destroy dead
|
118
|
-
def self.
|
115
|
+
# Destroy dead workers ( missed at least the last 4 heartbeats )
|
116
|
+
# Requeue jobs assigned to dead workers
|
117
|
+
# Destroy dead workers
|
118
|
+
def self.destroy_dead_workers
|
119
119
|
dead_seconds = Config.instance.heartbeat_seconds * 4
|
120
|
-
each do |
|
121
|
-
next if (Time.now -
|
122
|
-
logger.warn "Destroying
|
123
|
-
|
120
|
+
each do |worker|
|
121
|
+
next if (Time.now - worker.heartbeat.updated_at) < dead_seconds
|
122
|
+
logger.warn "Destroying worker #{worker.name}, and requeueing its jobs"
|
123
|
+
worker.destroy
|
124
124
|
end
|
125
125
|
end
|
126
126
|
|
127
|
-
# Stop all running, paused, or starting
|
127
|
+
# Stop all running, paused, or starting workers
|
128
128
|
def self.stop_all
|
129
|
-
where(state: ['running', 'paused', 'starting']).each { |
|
129
|
+
where(state: ['running', 'paused', 'starting']).each { |worker| worker.stop! }
|
130
130
|
end
|
131
131
|
|
132
|
-
# Pause all running
|
132
|
+
# Pause all running workers
|
133
133
|
def self.pause_all
|
134
|
-
where(state: 'running').each { |
|
134
|
+
where(state: 'running').each { |worker| worker.pause! }
|
135
135
|
end
|
136
136
|
|
137
|
-
# Resume all paused
|
137
|
+
# Resume all paused workers
|
138
138
|
def self.resume_all
|
139
|
-
each { |
|
139
|
+
each { |worker| worker.resume! if worker.paused? }
|
140
140
|
end
|
141
141
|
|
142
|
-
# Register a handler to perform cleanups etc. whenever a
|
142
|
+
# Register a handler to perform cleanups etc. whenever a worker is
|
143
143
|
# explicitly destroyed
|
144
144
|
def self.register_destroy_handler(&block)
|
145
145
|
@@destroy_handlers << block
|
146
146
|
end
|
147
147
|
|
148
|
-
# Returns [Boolean] whether the
|
148
|
+
# Returns [Boolean] whether the worker is shutting down
|
149
149
|
def shutting_down?
|
150
150
|
if self.class.shutdown
|
151
151
|
stop! if running?
|
@@ -160,7 +160,7 @@ module RocketJob
|
|
160
160
|
@thread_pool ||= []
|
161
161
|
end
|
162
162
|
|
163
|
-
# Run this instance of the
|
163
|
+
# Run this instance of the worker
|
164
164
|
def run
|
165
165
|
Thread.current.name = 'RocketJob main'
|
166
166
|
build_heartbeat unless heartbeat
|
@@ -168,17 +168,17 @@ module RocketJob
|
|
168
168
|
started
|
169
169
|
adjust_thread_pool(true)
|
170
170
|
save
|
171
|
-
logger.info "RocketJob
|
171
|
+
logger.info "RocketJob Worker started with #{max_threads} workers running"
|
172
172
|
|
173
173
|
count = 0
|
174
174
|
loop do
|
175
|
-
# Update heartbeat so that monitoring tools know that this
|
175
|
+
# Update heartbeat so that monitoring tools know that this worker is alive
|
176
176
|
set(
|
177
177
|
'heartbeat.updated_at' => Time.now,
|
178
178
|
'heartbeat.current_threads' => thread_pool_count
|
179
179
|
)
|
180
180
|
|
181
|
-
# Reload the
|
181
|
+
# Reload the worker model every 10 heartbeats in case its config was changed
|
182
182
|
# TODO make 3 configurable
|
183
183
|
if count >= 3
|
184
184
|
reload
|
@@ -188,7 +188,7 @@ module RocketJob
|
|
188
188
|
count += 1
|
189
189
|
end
|
190
190
|
|
191
|
-
# Stop
|
191
|
+
# Stop worker if shutdown signal was raised
|
192
192
|
stop! if self.class.shutdown && !stopping?
|
193
193
|
|
194
194
|
break if stopping?
|
@@ -204,9 +204,9 @@ module RocketJob
|
|
204
204
|
thread_pool.each { |t| t.join }
|
205
205
|
logger.info 'Shutdown'
|
206
206
|
rescue Exception => exc
|
207
|
-
logger.error('RocketJob::
|
207
|
+
logger.error('RocketJob::Worker is stopping due to an exception', exc)
|
208
208
|
ensure
|
209
|
-
# Destroy this
|
209
|
+
# Destroy this worker instance
|
210
210
|
destroy
|
211
211
|
end
|
212
212
|
|
@@ -258,7 +258,7 @@ module RocketJob
|
|
258
258
|
end
|
259
259
|
end
|
260
260
|
|
261
|
-
# Keep processing jobs until
|
261
|
+
# Keep processing jobs until worker stops running
|
262
262
|
def worker(worker_id)
|
263
263
|
Thread.current.name = "rocketjob #{worker_id}"
|
264
264
|
logger.info 'Started'
|
@@ -271,7 +271,7 @@ module RocketJob
|
|
271
271
|
sleep RocketJob::Config.instance.max_poll_seconds
|
272
272
|
end
|
273
273
|
end
|
274
|
-
logger.info "Stopping.
|
274
|
+
logger.info "Stopping. Worker state: #{state.inspect}"
|
275
275
|
rescue Exception => exc
|
276
276
|
logger.fatal('Unhandled exception in job processing thread', exc)
|
277
277
|
end
|
@@ -294,7 +294,7 @@ module RocketJob
|
|
294
294
|
false
|
295
295
|
end
|
296
296
|
|
297
|
-
# Requeue any jobs assigned to this
|
297
|
+
# Requeue any jobs assigned to this worker
|
298
298
|
def requeue_jobs
|
299
299
|
stop! if running? || paused?
|
300
300
|
@@destroy_handlers.each { |handler| handler.call(name) }
|
data/lib/rocketjob.rb
CHANGED
@@ -12,7 +12,7 @@ module RocketJob
|
|
12
12
|
autoload :Heartbeat, 'rocket_job/heartbeat'
|
13
13
|
autoload :Job, 'rocket_job/job'
|
14
14
|
autoload :JobException, 'rocket_job/job_exception'
|
15
|
-
autoload :
|
15
|
+
autoload :Worker, 'rocket_job/worker'
|
16
16
|
module Concerns
|
17
17
|
autoload :Worker, 'rocket_job/concerns/worker'
|
18
18
|
end
|
data/test/dirmon_job_test.rb
CHANGED
@@ -5,8 +5,8 @@ require_relative 'jobs/test_job'
|
|
5
5
|
class DirmonJobTest < Minitest::Test
|
6
6
|
context RocketJob::Jobs::DirmonJob do
|
7
7
|
setup do
|
8
|
-
@
|
9
|
-
@
|
8
|
+
@worker = RocketJob::Worker.new
|
9
|
+
@worker.started
|
10
10
|
@dirmon_job = RocketJob::Jobs::DirmonJob.new
|
11
11
|
@archive_directory = '/tmp/archive_directory'
|
12
12
|
@entry = RocketJob::DirmonEntry.new(
|
data/test/job_test.rb
CHANGED
@@ -5,8 +5,8 @@ require_relative 'jobs/test_job'
|
|
5
5
|
class JobTest < Minitest::Test
|
6
6
|
context RocketJob::Job do
|
7
7
|
setup do
|
8
|
-
@
|
9
|
-
@
|
8
|
+
@worker = RocketJob::Worker.new
|
9
|
+
@worker.started
|
10
10
|
@description = 'Hello World'
|
11
11
|
@arguments = [ 1 ]
|
12
12
|
@job = Jobs::TestJob.new(
|
@@ -46,7 +46,7 @@ class JobTest < Minitest::Test
|
|
46
46
|
context '#save!' do
|
47
47
|
should 'save a blank job' do
|
48
48
|
@job.save!
|
49
|
-
assert_nil @job.
|
49
|
+
assert_nil @job.worker_name
|
50
50
|
assert_nil @job.completed_at
|
51
51
|
assert @job.created_at
|
52
52
|
assert_equal @description, @job.description
|
@@ -66,8 +66,8 @@ class JobTest < Minitest::Test
|
|
66
66
|
should 'return status for a queued job' do
|
67
67
|
assert_equal true, @job.queued?
|
68
68
|
h = @job.status
|
69
|
-
assert_equal :queued, h[
|
70
|
-
assert_equal @description, h[
|
69
|
+
assert_equal :queued, h['state']
|
70
|
+
assert_equal @description, h['description']
|
71
71
|
end
|
72
72
|
|
73
73
|
should 'return status for a failed job' do
|
@@ -79,17 +79,17 @@ class JobTest < Minitest::Test
|
|
79
79
|
@job.fail!
|
80
80
|
assert_equal true, @job.failed?
|
81
81
|
h = @job.status
|
82
|
-
assert_equal :failed, h[
|
83
|
-
assert_equal @description, h[
|
84
|
-
assert_equal 'Test', h[
|
85
|
-
assert_equal 'hello world', h[
|
82
|
+
assert_equal :failed, h['state']
|
83
|
+
assert_equal @description, h['description']
|
84
|
+
assert_equal 'Test', h['exception']['class_name'], h
|
85
|
+
assert_equal 'hello world', h['exception']['message'], h
|
86
86
|
end
|
87
87
|
end
|
88
88
|
|
89
89
|
context '#work' do
|
90
90
|
should 'call default perform method' do
|
91
91
|
@job.start!
|
92
|
-
assert_equal false, @job.work(@
|
92
|
+
assert_equal false, @job.work(@worker)
|
93
93
|
assert_equal true, @job.completed?, @job.state
|
94
94
|
assert_equal 2, Jobs::TestJob.result
|
95
95
|
end
|
@@ -98,7 +98,7 @@ class JobTest < Minitest::Test
|
|
98
98
|
@job.perform_method = :sum
|
99
99
|
@job.arguments = [ 23, 45 ]
|
100
100
|
@job.start!
|
101
|
-
assert_equal false, @job.work(@
|
101
|
+
assert_equal false, @job.work(@worker)
|
102
102
|
assert_equal true, @job.completed?
|
103
103
|
assert_equal 68, Jobs::TestJob.result
|
104
104
|
end
|
@@ -106,7 +106,7 @@ class JobTest < Minitest::Test
|
|
106
106
|
should 'destroy on complete' do
|
107
107
|
@job.destroy_on_complete = true
|
108
108
|
@job.start!
|
109
|
-
assert_equal false, @job.work(@
|
109
|
+
assert_equal false, @job.work(@worker)
|
110
110
|
assert_equal nil, RocketJob::Job.find_by_id(@job.id)
|
111
111
|
end
|
112
112
|
|
@@ -118,7 +118,7 @@ class JobTest < Minitest::Test
|
|
118
118
|
@job.start!
|
119
119
|
logged = false
|
120
120
|
Jobs::TestJob.logger.stub(:log_internal, -> level, index, message, payload, exception { logged = true if message.include?('some very noisy logging')}) do
|
121
|
-
assert_equal false, @job.work(@
|
121
|
+
assert_equal false, @job.work(@worker), @job.inspect
|
122
122
|
end
|
123
123
|
assert_equal false, logged
|
124
124
|
end
|
@@ -133,7 +133,7 @@ class JobTest < Minitest::Test
|
|
133
133
|
# Raise global log level to :info
|
134
134
|
SemanticLogger.stub(:default_level_index, 3) do
|
135
135
|
Jobs::TestJob.logger.stub(:log_internal, -> { logged = true }) do
|
136
|
-
assert_equal false, @job.work(@
|
136
|
+
assert_equal false, @job.work(@worker)
|
137
137
|
end
|
138
138
|
end
|
139
139
|
assert_equal false, logged
|
@@ -144,7 +144,7 @@ class JobTest < Minitest::Test
|
|
144
144
|
@job.perform_method = :event
|
145
145
|
@job.arguments = [ named_parameters ]
|
146
146
|
@job.start!
|
147
|
-
assert_equal false, @job.work(@
|
147
|
+
assert_equal false, @job.work(@worker), @job.inspect
|
148
148
|
assert_equal true, @job.completed?
|
149
149
|
assert_equal named_parameters.merge('before_event' => true, 'after_event' => true), @job.arguments.first
|
150
150
|
end
|
@@ -157,25 +157,25 @@ class JobTest < Minitest::Test
|
|
157
157
|
end
|
158
158
|
|
159
159
|
should 'return nil when no jobs available' do
|
160
|
-
assert_equal nil, RocketJob::Job.next_job(@
|
160
|
+
assert_equal nil, RocketJob::Job.next_job(@worker.name)
|
161
161
|
end
|
162
162
|
|
163
163
|
should 'return the first job' do
|
164
164
|
@job.save!
|
165
|
-
assert job = RocketJob::Job.next_job(@
|
165
|
+
assert job = RocketJob::Job.next_job(@worker.name), "Failed to find job"
|
166
166
|
assert_equal @job.id, job.id
|
167
167
|
end
|
168
168
|
|
169
169
|
should 'Ignore future dated jobs' do
|
170
170
|
@job.run_at = Time.now + 1.hour
|
171
171
|
@job.save!
|
172
|
-
assert_equal nil, RocketJob::Job.next_job(@
|
172
|
+
assert_equal nil, RocketJob::Job.next_job(@worker.name)
|
173
173
|
end
|
174
174
|
|
175
175
|
should 'Process future dated jobs when time is now' do
|
176
176
|
@job.run_at = Time.now
|
177
177
|
@job.save!
|
178
|
-
assert job = RocketJob::Job.next_job(@
|
178
|
+
assert job = RocketJob::Job.next_job(@worker.name), "Failed to find future job"
|
179
179
|
assert_equal @job.id, job.id
|
180
180
|
end
|
181
181
|
|
@@ -183,7 +183,7 @@ class JobTest < Minitest::Test
|
|
183
183
|
count = RocketJob::Job.count
|
184
184
|
@job.expires_at = Time.now - 100
|
185
185
|
@job.save!
|
186
|
-
assert_equal nil, RocketJob::Job.next_job(@
|
186
|
+
assert_equal nil, RocketJob::Job.next_job(@worker.name)
|
187
187
|
assert_equal count, RocketJob::Job.count
|
188
188
|
end
|
189
189
|
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
require_relative 'jobs/test_job'
|
3
|
+
|
4
|
+
# Unit Test for RocketJob::Job
|
5
|
+
class WorkerTest < Minitest::Test
|
6
|
+
context RocketJob::Job do
|
7
|
+
[true, false].each do |inline_mode|
|
8
|
+
setup do
|
9
|
+
RocketJob::Config.inline_mode = inline_mode
|
10
|
+
@worker = RocketJob::Worker.new
|
11
|
+
@worker.started
|
12
|
+
end
|
13
|
+
|
14
|
+
teardown do
|
15
|
+
@job.destroy if @job && !@job.new_record?
|
16
|
+
RocketJob::Config.inline_mode = false
|
17
|
+
end
|
18
|
+
|
19
|
+
context '.perform_later' do
|
20
|
+
should "process single request (inline_mode=#{inline_mode})" do
|
21
|
+
@job = Jobs::TestJob.perform_later(1) do |job|
|
22
|
+
job.destroy_on_complete = false
|
23
|
+
end
|
24
|
+
assert_nil @job.worker_name
|
25
|
+
assert_nil @job.completed_at
|
26
|
+
assert @job.created_at
|
27
|
+
assert_nil @job.description
|
28
|
+
assert_equal false, @job.destroy_on_complete
|
29
|
+
assert_nil @job.expires_at
|
30
|
+
assert_equal 0, @job.percent_complete
|
31
|
+
assert_equal 50, @job.priority
|
32
|
+
assert_equal 0, @job.failure_count
|
33
|
+
assert_nil @job.run_at
|
34
|
+
assert_nil @job.started_at
|
35
|
+
assert_equal :queued, @job.state
|
36
|
+
|
37
|
+
@job.worker_name = 'me'
|
38
|
+
@job.start
|
39
|
+
assert_equal false, @job.work(@worker), @job.exception.inspect
|
40
|
+
assert_equal true, @job.completed?
|
41
|
+
assert_equal 2, Jobs::TestJob.result
|
42
|
+
|
43
|
+
assert @job.worker_name
|
44
|
+
assert @job.completed_at
|
45
|
+
assert @job.created_at
|
46
|
+
assert_nil @job.description
|
47
|
+
assert_equal false, @job.destroy_on_complete
|
48
|
+
assert_nil @job.expires_at
|
49
|
+
assert_equal 100, @job.percent_complete
|
50
|
+
assert_equal 50, @job.priority
|
51
|
+
assert_equal 0, @job.failure_count
|
52
|
+
assert_nil @job.run_at
|
53
|
+
assert @job.started_at
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context '.later' do
|
58
|
+
should "process non default method (inline_mode=#{inline_mode})" do
|
59
|
+
@job = Jobs::TestJob.later(:sum, 23, 45)
|
60
|
+
@job.start
|
61
|
+
assert_equal false, @job.work(@worker), @job.exception.inspect
|
62
|
+
assert_equal true, @job.completed?
|
63
|
+
assert_equal 68, Jobs::TestJob.result
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context '.perform_now' do
|
68
|
+
should "process perform (inline_mode=#{inline_mode})" do
|
69
|
+
@job = Jobs::TestJob.perform_now(5)
|
70
|
+
assert_equal true, @job.completed?
|
71
|
+
assert_equal 6, Jobs::TestJob.result
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context '.now' do
|
76
|
+
should "process non default method (inline_mode=#{inline_mode})" do
|
77
|
+
@job = Jobs::TestJob.now(:sum, 23, 45)
|
78
|
+
assert_equal true, @job.completed?, @job.inspect
|
79
|
+
assert_equal 68, Jobs::TestJob.result
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
data/test/worker_test.rb
CHANGED
@@ -1,85 +1,39 @@
|
|
1
1
|
require_relative 'test_helper'
|
2
2
|
require_relative 'jobs/test_job'
|
3
3
|
|
4
|
-
# Unit Test for RocketJob::
|
4
|
+
# Unit Test for RocketJob::Worker
|
5
5
|
class WorkerTest < Minitest::Test
|
6
|
-
context RocketJob::
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
@
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
context '.perform_later' do
|
20
|
-
should "process single request (inline_mode=#{inline_mode})" do
|
21
|
-
@job = Jobs::TestJob.perform_later(1) do |job|
|
22
|
-
job.destroy_on_complete = false
|
23
|
-
end
|
24
|
-
assert_nil @job.server_name
|
25
|
-
assert_nil @job.completed_at
|
26
|
-
assert @job.created_at
|
27
|
-
assert_nil @job.description
|
28
|
-
assert_equal false, @job.destroy_on_complete
|
29
|
-
assert_nil @job.expires_at
|
30
|
-
assert_equal 0, @job.percent_complete
|
31
|
-
assert_equal 50, @job.priority
|
32
|
-
assert_equal 0, @job.failure_count
|
33
|
-
assert_nil @job.run_at
|
34
|
-
assert_nil @job.started_at
|
35
|
-
assert_equal :queued, @job.state
|
36
|
-
|
37
|
-
@job.server_name = 'me'
|
38
|
-
@job.start
|
39
|
-
assert_equal false, @job.work(@server), @job.exception.inspect
|
40
|
-
assert_equal true, @job.completed?
|
41
|
-
assert_equal 2, Jobs::TestJob.result
|
42
|
-
|
43
|
-
assert @job.server_name
|
44
|
-
assert @job.completed_at
|
45
|
-
assert @job.created_at
|
46
|
-
assert_nil @job.description
|
47
|
-
assert_equal false, @job.destroy_on_complete
|
48
|
-
assert_nil @job.expires_at
|
49
|
-
assert_equal 100, @job.percent_complete
|
50
|
-
assert_equal 50, @job.priority
|
51
|
-
assert_equal 0, @job.failure_count
|
52
|
-
assert_nil @job.run_at
|
53
|
-
assert @job.started_at
|
54
|
-
end
|
55
|
-
end
|
6
|
+
context RocketJob::Worker do
|
7
|
+
setup do
|
8
|
+
RocketJob::Config.instance.heartbeat_seconds = 0.1
|
9
|
+
RocketJob::Config.instance.max_poll_seconds = 0.1
|
10
|
+
@worker = RocketJob::Worker.new
|
11
|
+
@description = 'Hello World'
|
12
|
+
@arguments = [ 1 ]
|
13
|
+
@job = Jobs::TestJob.new(
|
14
|
+
description: @description,
|
15
|
+
arguments: @arguments,
|
16
|
+
destroy_on_complete: false
|
17
|
+
)
|
18
|
+
end
|
56
19
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
@job.start
|
61
|
-
assert_equal false, @job.work(@server), @job.exception.inspect
|
62
|
-
assert_equal true, @job.completed?
|
63
|
-
assert_equal 68, Jobs::TestJob.result
|
64
|
-
end
|
65
|
-
end
|
20
|
+
teardown do
|
21
|
+
@job.destroy if @job && !@job.new_record?
|
22
|
+
end
|
66
23
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
assert_equal true, @job.completed?
|
71
|
-
assert_equal 6, Jobs::TestJob.result
|
72
|
-
end
|
24
|
+
context '.config' do
|
25
|
+
should 'support multiple databases' do
|
26
|
+
assert_equal 'test_rocketjob', RocketJob::Job.collection.db.name
|
73
27
|
end
|
28
|
+
end
|
74
29
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
end
|
30
|
+
context '#run' do
|
31
|
+
should 'run a worker' do
|
32
|
+
Thread.new { sleep 1; @worker.stop!}
|
33
|
+
@worker.run
|
34
|
+
assert_equal :stopping, @worker.state, @worker.inspect
|
81
35
|
end
|
82
|
-
|
83
36
|
end
|
37
|
+
|
84
38
|
end
|
85
|
-
end
|
39
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rocketjob
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Reid Morrison
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-07-
|
11
|
+
date: 2015-07-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: aasm
|
@@ -128,14 +128,14 @@ files:
|
|
128
128
|
- lib/rocket_job/job.rb
|
129
129
|
- lib/rocket_job/job_exception.rb
|
130
130
|
- lib/rocket_job/jobs/dirmon_job.rb
|
131
|
-
- lib/rocket_job/server.rb
|
132
131
|
- lib/rocket_job/version.rb
|
132
|
+
- lib/rocket_job/worker.rb
|
133
133
|
- lib/rocketjob.rb
|
134
134
|
- test/config/mongo.yml
|
135
135
|
- test/dirmon_job_test.rb
|
136
136
|
- test/job_test.rb
|
137
|
+
- test/job_worker_test.rb
|
137
138
|
- test/jobs/test_job.rb
|
138
|
-
- test/server_test.rb
|
139
139
|
- test/test_helper.rb
|
140
140
|
- test/worker_test.rb
|
141
141
|
homepage: https://github.com/rocketjob/rocketjob
|
@@ -166,7 +166,7 @@ test_files:
|
|
166
166
|
- test/config/mongo.yml
|
167
167
|
- test/dirmon_job_test.rb
|
168
168
|
- test/job_test.rb
|
169
|
+
- test/job_worker_test.rb
|
169
170
|
- test/jobs/test_job.rb
|
170
|
-
- test/server_test.rb
|
171
171
|
- test/test_helper.rb
|
172
172
|
- test/worker_test.rb
|
data/test/server_test.rb
DELETED
@@ -1,39 +0,0 @@
|
|
1
|
-
require_relative 'test_helper'
|
2
|
-
require_relative 'jobs/test_job'
|
3
|
-
|
4
|
-
# Unit Test for RocketJob::Server
|
5
|
-
class ServerTest < Minitest::Test
|
6
|
-
context RocketJob::Server do
|
7
|
-
setup do
|
8
|
-
RocketJob::Config.instance.heartbeat_seconds = 0.1
|
9
|
-
RocketJob::Config.instance.max_poll_seconds = 0.1
|
10
|
-
@server = RocketJob::Server.new
|
11
|
-
@description = 'Hello World'
|
12
|
-
@arguments = [ 1 ]
|
13
|
-
@job = Jobs::TestJob.new(
|
14
|
-
description: @description,
|
15
|
-
arguments: @arguments,
|
16
|
-
destroy_on_complete: false
|
17
|
-
)
|
18
|
-
end
|
19
|
-
|
20
|
-
teardown do
|
21
|
-
@job.destroy if @job && !@job.new_record?
|
22
|
-
end
|
23
|
-
|
24
|
-
context '.config' do
|
25
|
-
should 'support multiple databases' do
|
26
|
-
assert_equal 'test_rocketjob', RocketJob::Job.collection.db.name
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
context '#run' do
|
31
|
-
should 'run a server' do
|
32
|
-
Thread.new { sleep 1; @server.stop!}
|
33
|
-
@server.run
|
34
|
-
assert_equal :stopping, @server.state, @server.inspect
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
end
|
39
|
-
end
|