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