job_dispatch 0.0.2 → 0.1.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/.gitignore +2 -0
- data/CHANGELOG.md +5 -0
- data/bin/job-worker +0 -2
- data/lib/job_dispatch/broker.rb +64 -13
- data/lib/job_dispatch/client.rb +33 -1
- data/lib/job_dispatch/version.rb +1 -1
- data/lib/job_dispatch/worker.rb +1 -0
- data/lib/job_dispatch/worker/item.rb +1 -0
- data/lib/job_dispatch/worker/socket.rb +22 -6
- data/spec/job_dispatch/broker_spec.rb +91 -11
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 401fd02367fe4acc36558989fe00883365afcd87
|
4
|
+
data.tar.gz: f45f4e6595a88462a394deb27a103d9a9d274ae5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d07c1dc6f62db463ec888a8e3130893bfb37541854756477200ecc77d79ae8e0e615d4773925b18f71798fccb59d3bb308c1e8ec7e1696958b9b694dd5e7c161
|
7
|
+
data.tar.gz: f3a9e4646d3f4e0e1aea6b5b7691758f3b29057215bbc104875239375a6efb0a99f1ea035d86e7e6ed6dc913d87dffcf8731b42c8e8874a52400aadcdccb1348
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
# job_dispatch change log
|
2
2
|
|
3
|
+
## Version 0.1.0
|
4
|
+
|
5
|
+
* Added 'num_tcp_connections' to status command response
|
6
|
+
* Fixed leaking sockets from job-worker command.
|
7
|
+
|
3
8
|
## Version 0.0.2
|
4
9
|
|
5
10
|
* Broker sends an idle command to a worker immediately upon connect. This helps recover from a case where a worker
|
data/bin/job-worker
CHANGED
@@ -28,8 +28,6 @@ JobDispatch.load_config_from_yml('config/job_dispatch.yml', ENV["RAILS_ENV"])
|
|
28
28
|
|
29
29
|
require File.expand_path('config/environment.rb', ROOT_DIR)
|
30
30
|
|
31
|
-
JobDispatch.logger = Rails.logger
|
32
|
-
|
33
31
|
endpoint = JobDispatch.config.broker[:connect]
|
34
32
|
if endpoint.nil? || endpoint.empty?
|
35
33
|
$stderr.puts "No Job Dispatch broker connect address has been specified."
|
data/lib/job_dispatch/broker.rb
CHANGED
@@ -11,7 +11,7 @@ module JobDispatch
|
|
11
11
|
class Broker
|
12
12
|
|
13
13
|
WORKER_IDLE_TIME = 10.123
|
14
|
-
POLL_TIME =
|
14
|
+
POLL_TIME = 31
|
15
15
|
STOP_SIGNALS = %w[INT TERM KILL]
|
16
16
|
|
17
17
|
IdleWorker = Struct.new :worker_id, :idle_since, :queue, :worker_name, :idle_count
|
@@ -32,6 +32,7 @@ module JobDispatch
|
|
32
32
|
attr :job_subscribers # Key: job_id, value: list of Socket Identities waiting for job completion notifications.
|
33
33
|
attr :pub_socket
|
34
34
|
attr_accessor :reply_exceptions
|
35
|
+
attr :queues_ready
|
35
36
|
|
36
37
|
def initialize(worker_bind_address, wakeup_bind_address, publish_bind_address=nil)
|
37
38
|
@worker_bind_address = worker_bind_address
|
@@ -48,6 +49,7 @@ module JobDispatch
|
|
48
49
|
@jobs_in_progress_workers = {} #key: job_id, value: worker_id
|
49
50
|
@worker_names = {} # Key: Symbol socket identity, value: String claimed name of worker
|
50
51
|
@job_subscribers = {} # Key: job_id, value: list of Socket Identities waiting for job completion notifications.
|
52
|
+
@queues_ready = {} # Key: Symbol queue name, value: bool ready?
|
51
53
|
@status = "OK"
|
52
54
|
@reply_exceptions = true
|
53
55
|
|
@@ -127,7 +129,7 @@ module JobDispatch
|
|
127
129
|
# TODO: calculate the amount of time to sleep to wake up such that a scheduled event happens as close
|
128
130
|
# as possible to the time it was supposed to happen. This could additionally mean that the POLL_TIME
|
129
131
|
# could be arbitrarily large. As any communication with the broker will wake it immediately.
|
130
|
-
poll_time = POLL_TIME
|
132
|
+
poll_time = JobDispatch.config.broker_options.try(:[], :poll_time) || POLL_TIME
|
131
133
|
poller.poll(poll_time)
|
132
134
|
|
133
135
|
if @wake_socket && poller.readables.include?(@wake_socket)
|
@@ -136,6 +138,7 @@ module JobDispatch
|
|
136
138
|
|
137
139
|
if poller.readables.include?(socket.socket)
|
138
140
|
command = read_command
|
141
|
+
JobDispatch.logger.debug("JobDispatch::Broker received command: #{command.command}(#{command.parameters.inspect})")
|
139
142
|
reply = process_command(command)
|
140
143
|
send_command(reply) if reply
|
141
144
|
end
|
@@ -217,6 +220,12 @@ module JobDispatch
|
|
217
220
|
when "enqueue"
|
218
221
|
reply.parameters = create_job(command)
|
219
222
|
|
223
|
+
when "last"
|
224
|
+
reply.parameters = last_job(command)
|
225
|
+
|
226
|
+
when "fetch"
|
227
|
+
reply.parameters = fetch_job(command)
|
228
|
+
|
220
229
|
when "quit"
|
221
230
|
process_quit
|
222
231
|
reply.parameters = {:status => 'bye'}
|
@@ -233,6 +242,7 @@ module JobDispatch
|
|
233
242
|
if reply_exceptions
|
234
243
|
# all others reply over socket.
|
235
244
|
JobDispatch.logger.error("JobDispatch::Broker #{e}")
|
245
|
+
JobDispatch.logger.error e.backtrace.join("\n")
|
236
246
|
reply.parameters = {:status => 'error', :message => e.to_s}
|
237
247
|
else
|
238
248
|
# used during testing to raise errors so that Rspec can catch them as a test failure.
|
@@ -294,6 +304,7 @@ module JobDispatch
|
|
294
304
|
idle_worker = IdleWorker.new(command.worker_id, Time.now, queue, command.worker_name, idle_count)
|
295
305
|
workers_waiting_for_jobs[command.worker_id] = idle_worker
|
296
306
|
queues[queue] << command.worker_id
|
307
|
+
queues_ready[queue] = true
|
297
308
|
if command.worker_name # this is only sent on initial requests.
|
298
309
|
worker_names[command.worker_id] = command.worker_name
|
299
310
|
end
|
@@ -323,9 +334,9 @@ module JobDispatch
|
|
323
334
|
|
324
335
|
def dispatch_jobs_to_workers
|
325
336
|
# dequeue jobs from database for each queue
|
326
|
-
|
337
|
+
queues.each_pair do |queue, worker_ids|
|
327
338
|
# we only need to check the database if there are available workers in that queue
|
328
|
-
if worker_ids.count > 0
|
339
|
+
if worker_ids.count > 0 && queues_ready[queue]
|
329
340
|
worker_id = worker_ids.first
|
330
341
|
|
331
342
|
job = begin
|
@@ -344,8 +355,10 @@ module JobDispatch
|
|
344
355
|
job.expire_execution_at = Time.now + (job.timeout || Job::DEFAULT_EXECUTION_TIMEOUT)
|
345
356
|
job.status = JobDispatch::Job::IN_PROGRESS
|
346
357
|
job.save
|
347
|
-
|
348
358
|
publish_job_status(job)
|
359
|
+
else
|
360
|
+
# no job. mark the queue as not ready so we don't repeatedly check for jobs in an empty queue.
|
361
|
+
queues_ready[queue] = false
|
349
362
|
end
|
350
363
|
end
|
351
364
|
end
|
@@ -425,19 +438,24 @@ module JobDispatch
|
|
425
438
|
|
426
439
|
|
427
440
|
def json_for_job(job)
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
441
|
+
if job
|
442
|
+
hash = if job.respond_to? :as_job_queue_item
|
443
|
+
job.as_job_queue_item
|
444
|
+
else
|
445
|
+
job.as_json
|
446
|
+
end.with_indifferent_access
|
447
|
+
hash[:id] = hash[:id].to_s
|
448
|
+
hash
|
449
|
+
end
|
435
450
|
end
|
436
451
|
|
437
452
|
|
438
453
|
def status_response
|
454
|
+
num_tcp_connections = `lsof -p #{Process.pid}`.split.select { |l| l=~ /TCP/ }.count
|
455
|
+
|
439
456
|
response = {
|
440
457
|
:status => status,
|
458
|
+
:num_tcp_connections => num_tcp_connections,
|
441
459
|
:queues => {}
|
442
460
|
}
|
443
461
|
|
@@ -477,14 +495,15 @@ module JobDispatch
|
|
477
495
|
# @return [Hash] result to be sent to client.
|
478
496
|
def touch_job(command)
|
479
497
|
job_id = command.parameters[:job_id]
|
480
|
-
timeout = command.parameters[:timeout] || Job::DEFAULT_EXECUTION_TIMEOUT
|
481
498
|
job = @jobs_in_progress[job_id]
|
482
499
|
if job
|
500
|
+
timeout = command.parameters[:timeout] || job.timeout || Job::DEFAULT_EXECUTION_TIMEOUT
|
483
501
|
job.expire_execution_at = Time.now + timeout
|
484
502
|
JobDispatch.logger.info("JobDispatch::Broker#touch timeout on job #{job_id} to #{job.expire_execution_at}")
|
485
503
|
job.save
|
486
504
|
{status: "success"}
|
487
505
|
else
|
506
|
+
JobDispatch.logger.info("JobDispatch::Broker#touch job #{job_id} not in progress.")
|
488
507
|
{status: "error", message: "the specified job does not appear to be in progress"}
|
489
508
|
end
|
490
509
|
end
|
@@ -494,10 +513,42 @@ module JobDispatch
|
|
494
513
|
raise MissingParameterError, "Missing 'job' from command" unless command.parameters[:job].present?
|
495
514
|
|
496
515
|
job_attrs = command.parameters[:job]
|
516
|
+
job_attrs[:queue] ||= :default
|
497
517
|
job = job_source.create!(job_attrs)
|
518
|
+
queues_ready[job_attrs[:queue].to_sym] = true
|
498
519
|
{status: 'success', job_id: job.id.to_s}
|
499
520
|
rescue StandardError => e
|
500
521
|
JobDispatch.logger.error "JobDispatch::Broker#create_job error: #{e}"
|
522
|
+
JobDispatch.logger.error e.backtrace.join("\n")
|
523
|
+
{status: 'error', message: e.to_s}
|
524
|
+
end
|
525
|
+
end
|
526
|
+
|
527
|
+
def last_job(command)
|
528
|
+
begin
|
529
|
+
queue = command.parameters[:queue] || 'default'
|
530
|
+
job = job_source.where(:queue => queue).last
|
531
|
+
if job
|
532
|
+
{status: 'success', job: json_for_job(job)}
|
533
|
+
else
|
534
|
+
{status: 'error', message: 'no last job'}
|
535
|
+
end
|
536
|
+
rescue StandardError => e
|
537
|
+
JobDispatch.logger.error e.to_s
|
538
|
+
JobDispatch.logger.error e.backtrace.join("\n")
|
539
|
+
{status: 'error', message: e.to_s}
|
540
|
+
end
|
541
|
+
end
|
542
|
+
|
543
|
+
def fetch_job(command)
|
544
|
+
begin
|
545
|
+
raise "Missing parameter 'job_id'" unless command.parameters[:job_id]
|
546
|
+
job = job_source.find(command.parameters[:job_id])
|
547
|
+
raise "Job not found" unless job
|
548
|
+
{status: 'success', job: json_for_job(job)}
|
549
|
+
rescue StandardError => e
|
550
|
+
JobDispatch.logger.error e.to_s
|
551
|
+
JobDispatch.logger.error e.backtrace.join("\n")
|
501
552
|
{status: 'error', message: e.to_s}
|
502
553
|
end
|
503
554
|
end
|
data/lib/job_dispatch/client.rb
CHANGED
@@ -34,14 +34,46 @@ module JobDispatch
|
|
34
34
|
SynchronousProxy.new(self, target, options)
|
35
35
|
end
|
36
36
|
|
37
|
-
|
37
|
+
# Enqueue a job to be processed describe by the passed job attributes.
|
38
|
+
#
|
39
|
+
# Required attributes:
|
40
|
+
# target: The target object that will execute the job. typically a class.
|
41
|
+
# method: the message to be sent to the target.
|
42
|
+
# Optional:
|
43
|
+
# parameters: an array of parameters to be passed to the method.
|
44
|
+
# timeout: number of seconds after which the job is considered timed out and failed.
|
45
|
+
def enqueue(job_attrs={})
|
38
46
|
send_request('enqueue', {job: job_attrs})
|
39
47
|
end
|
40
48
|
|
49
|
+
# send a message to the dispatcher requesting to be notified when the job completes (or fails).
|
41
50
|
def notify(job_id)
|
42
51
|
send_request('notify', {job_id: job_id})
|
43
52
|
end
|
44
53
|
|
54
|
+
# as the dispatcher what was the last job enqueued on the given queue (or default)
|
55
|
+
def last(queue=nil)
|
56
|
+
job_or_raise send_request('last', {queue: queue||'default'})
|
57
|
+
end
|
58
|
+
|
59
|
+
# fetch the complete details for hte last job
|
60
|
+
def fetch(job_id)
|
61
|
+
job_or_raise send_request('fetch', {job_id: job_id})
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def job_or_raise(response)
|
67
|
+
if response.is_a?(Hash) && response[:status] == 'success'
|
68
|
+
response[:job]
|
69
|
+
else
|
70
|
+
p response
|
71
|
+
raise ClientError, response[:message]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
class ClientError < StandardError
|
45
77
|
end
|
46
78
|
end
|
47
79
|
|
data/lib/job_dispatch/version.rb
CHANGED
data/lib/job_dispatch/worker.rb
CHANGED
@@ -36,6 +36,7 @@ module JobDispatch
|
|
36
36
|
backtrace: ex.backtrace,
|
37
37
|
}
|
38
38
|
@status = :error
|
39
|
+
JobDispatch.logger.debug ex
|
39
40
|
ensure
|
40
41
|
Thread.current["JobDispatch::Worker.job_id"] = nil
|
41
42
|
JobDispatch.logger.info "Worker completed job #{job_id}: #{target}.#{method}, status: #{@status}"
|
@@ -8,11 +8,14 @@ module JobDispatch
|
|
8
8
|
class Socket
|
9
9
|
|
10
10
|
attr :socket
|
11
|
+
attr :touch_socket
|
11
12
|
attr :item_class
|
12
13
|
|
13
14
|
def initialize(connect_address, item_klass)
|
14
15
|
@socket = JobDispatch.context.socket(ZMQ::REQ)
|
15
16
|
@socket.connect(connect_address)
|
17
|
+
@touch_socket = JobDispatch.context.socket(ZMQ::DEALER)
|
18
|
+
@touch_socket.connect(connect_address)
|
16
19
|
@item_class = item_klass
|
17
20
|
end
|
18
21
|
|
@@ -29,7 +32,14 @@ module JobDispatch
|
|
29
32
|
end
|
30
33
|
|
31
34
|
def close
|
32
|
-
@socket
|
35
|
+
if @socket
|
36
|
+
@socket.close rescue nil
|
37
|
+
@socket = nil
|
38
|
+
end
|
39
|
+
if @touch_socket
|
40
|
+
@touch_socket.close rescue nil
|
41
|
+
@touch_socket = nil
|
42
|
+
end
|
33
43
|
end
|
34
44
|
|
35
45
|
def identity
|
@@ -45,8 +55,9 @@ module JobDispatch
|
|
45
55
|
#
|
46
56
|
# @return [JobDispatch::Item] the item to be processed (or nil if there isn't a valid job)
|
47
57
|
def read_item
|
48
|
-
json = @socket.recv
|
49
58
|
begin
|
59
|
+
drain_touch_socket
|
60
|
+
json = @socket.recv
|
50
61
|
params = JSON.parse(json)
|
51
62
|
case params["command"]
|
52
63
|
when "job"
|
@@ -67,6 +78,14 @@ module JobDispatch
|
|
67
78
|
item
|
68
79
|
end
|
69
80
|
|
81
|
+
# drain any messages that may have been received on the touch socket.
|
82
|
+
def drain_touch_socket
|
83
|
+
loop do
|
84
|
+
message = @touch_socket.recv_nonblock
|
85
|
+
break if message.nil?
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
70
89
|
# after execution, send the response.
|
71
90
|
def send_response(job_id, status, result)
|
72
91
|
JobDispatch.logger.info "Worker #{Process.pid} completed job_id: #{job_id}: #{status}, result: #{result}"
|
@@ -86,11 +105,8 @@ module JobDispatch
|
|
86
105
|
job_id: job_id
|
87
106
|
}
|
88
107
|
hash[:timeout] = timeout if timeout
|
89
|
-
@
|
90
|
-
json = @socket.recv # wait for acknowledgement... this could be done via pub/sub to be asynchronous.
|
91
|
-
JSON.parse(json) rescue {:error => "Failed to decode JSON from dispatcher: #{json}"}
|
108
|
+
@touch_socket.send(JSON.dump(hash))
|
92
109
|
end
|
93
|
-
|
94
110
|
end
|
95
111
|
end
|
96
112
|
end
|
@@ -488,6 +488,8 @@ describe JobDispatch::Broker do
|
|
488
488
|
@job = FactoryGirl.build :job
|
489
489
|
@socket = double('Broker::Socket', :send_command => nil)
|
490
490
|
subject.stub(:socket => @socket)
|
491
|
+
@job_class = double('JobClass')
|
492
|
+
JobDispatch.config.job_class = @job_class
|
491
493
|
end
|
492
494
|
|
493
495
|
it "the job is sent to an idle worker" do
|
@@ -497,10 +499,8 @@ describe JobDispatch::Broker do
|
|
497
499
|
expect(cmd.parameters[:target]).to eq(@job.target)
|
498
500
|
end
|
499
501
|
|
500
|
-
job_class
|
501
|
-
job_class.
|
502
|
-
job_class.should_receive(:dequeue_job_for_queue).with('example')
|
503
|
-
JobDispatch.config.job_class = job_class
|
502
|
+
@job_class.stub(:dequeue_job_for_queue).and_return(@job)
|
503
|
+
@job_class.should_receive(:dequeue_job_for_queue).with('example')
|
504
504
|
|
505
505
|
# send ready command => adds idle worker state
|
506
506
|
subject.workers_waiting_for_reply << worker_id # simulating read_command
|
@@ -511,9 +511,29 @@ describe JobDispatch::Broker do
|
|
511
511
|
}))
|
512
512
|
expect(@result).to be_nil # no immediate response
|
513
513
|
expect(subject.workers_waiting_for_jobs[worker_id]).not_to be_nil
|
514
|
+
subject.queues_ready[:example] = true
|
514
515
|
|
515
516
|
subject.dispatch_jobs_to_workers
|
516
517
|
end
|
518
|
+
|
519
|
+
it "when no job is found, the queue is marked inactive" do
|
520
|
+
# send ready command => adds idle worker state
|
521
|
+
subject.workers_waiting_for_reply << worker_id # simulating read_command
|
522
|
+
@result = subject.process_command(Command.new(worker_id, {
|
523
|
+
command: 'ready',
|
524
|
+
queue: 'example',
|
525
|
+
worker_name: 'ruby worker',
|
526
|
+
}))
|
527
|
+
|
528
|
+
@job_class.stub(:dequeue_job_for_queue).and_return(nil)
|
529
|
+
|
530
|
+
expect(@result).to be_nil # no immediate response
|
531
|
+
expect(subject.workers_waiting_for_jobs[worker_id]).not_to be_nil
|
532
|
+
subject.queues_ready[:example] = true
|
533
|
+
|
534
|
+
subject.dispatch_jobs_to_workers
|
535
|
+
expect(subject.queues_ready[:example]).to be_false
|
536
|
+
end
|
517
537
|
end
|
518
538
|
|
519
539
|
context "when an error occurs dequeuing jobs" do
|
@@ -578,7 +598,7 @@ describe JobDispatch::Broker do
|
|
578
598
|
|
579
599
|
context "touching a job" do
|
580
600
|
before :each do
|
581
|
-
@time = Time.now
|
601
|
+
@time = Time.now.change(:usec => 0)
|
582
602
|
# this worker will be IDLE
|
583
603
|
@job = FactoryGirl.build :job, :expire_execution_at => @time + 5.seconds
|
584
604
|
@job_id = @job.id.to_s
|
@@ -594,7 +614,7 @@ describe JobDispatch::Broker do
|
|
594
614
|
Timecop.freeze(@time) do
|
595
615
|
subject.touch_job(Command.new(worker_id, {command: "touch", job_id: @job_id}))
|
596
616
|
end
|
597
|
-
expect(@job.expire_execution_at).to eq(@time +
|
617
|
+
expect(@job.expire_execution_at).to eq(@time + @job.timeout)
|
598
618
|
end
|
599
619
|
|
600
620
|
it "updates the expire_execution_at time with a custom timeout" do
|
@@ -608,10 +628,10 @@ describe JobDispatch::Broker do
|
|
608
628
|
context "enqueue a job" do
|
609
629
|
before :each do
|
610
630
|
@job_attrs = FactoryGirl.attributes_for :job
|
631
|
+
JobDispatch.config.job_class = double('JobClass')
|
611
632
|
end
|
612
633
|
|
613
634
|
it "Creates a job" do
|
614
|
-
JobDispatch.config.job_class = double('JobClass')
|
615
635
|
JobDispatch.config.job_class.should_receive(:create!).with(@job_attrs)
|
616
636
|
command = Command.new(:some_client, {command: "enqueue", job: @job_attrs})
|
617
637
|
subject.process_command(command)
|
@@ -619,7 +639,6 @@ describe JobDispatch::Broker do
|
|
619
639
|
|
620
640
|
it "returns the job id" do
|
621
641
|
job_id = 12345
|
622
|
-
JobDispatch.config.job_class = double('JobClass')
|
623
642
|
JobDispatch.config.job_class.stub(:create! => double('Job', :id => job_id))
|
624
643
|
command = Command.new(:some_client, {command: "enqueue", job: @job_attrs})
|
625
644
|
result = subject.process_command(command)
|
@@ -628,7 +647,6 @@ describe JobDispatch::Broker do
|
|
628
647
|
end
|
629
648
|
|
630
649
|
it "returns an error if the arguments are no good" do
|
631
|
-
JobDispatch.config.job_class = double('JobClass')
|
632
650
|
JobDispatch.config.job_class.stub(:create!).and_raise("no good") # simulate some database save error
|
633
651
|
command = Command.new(:some_client, {command: "enqueue", job: @job_attrs})
|
634
652
|
result = subject.process_command(command)
|
@@ -637,13 +655,18 @@ describe JobDispatch::Broker do
|
|
637
655
|
end
|
638
656
|
|
639
657
|
it "returns an error if the 'job' parameter is missing" do
|
640
|
-
JobDispatch.config.job_class = double('JobClass')
|
641
658
|
command = Command.new(:some_client, {command: "enqueue"})
|
642
659
|
result = subject.process_command(command)
|
643
660
|
expect(result.parameters[:status]).to eq('error')
|
644
661
|
end
|
645
|
-
end
|
646
662
|
|
663
|
+
it "marks the queue as ready" do
|
664
|
+
JobDispatch.config.job_class.stub(:create! => double('Job', :id => 1))
|
665
|
+
command = Command.new(:some_client, {command: "enqueue", job: @job_attrs})
|
666
|
+
result = subject.process_command(command)
|
667
|
+
expect(subject.queues_ready[:default]).to be_true
|
668
|
+
end
|
669
|
+
end
|
647
670
|
|
648
671
|
context "'notify'" do
|
649
672
|
|
@@ -779,4 +802,61 @@ describe JobDispatch::Broker do
|
|
779
802
|
end
|
780
803
|
end
|
781
804
|
|
805
|
+
context "last" do
|
806
|
+
let(:json){ {'id' => '12341234', 'target' => 'Example', 'method' => 'method'}}
|
807
|
+
before do
|
808
|
+
@job_class = double('JobClass')
|
809
|
+
JobDispatch.config.job_class = @job_class
|
810
|
+
end
|
811
|
+
it "returns last job in specified queue" do
|
812
|
+
command = Command.new(:client, {command: 'last', queue: 'ruby'})
|
813
|
+
relation = double('relation')
|
814
|
+
@job_class.should_receive(:where).with(queue: 'ruby').and_return(relation)
|
815
|
+
relation.should_receive(:last).and_return(double("job", id: "12341234", as_json: json))
|
816
|
+
result = subject.process_command(command)
|
817
|
+
expect(result.parameters).to eq({status: 'success', job: json})
|
818
|
+
end
|
819
|
+
it "returns last job in default queue" do
|
820
|
+
command = Command.new(:client, {command: 'last'})
|
821
|
+
relation = double('relation')
|
822
|
+
@job_class.should_receive(:where).with(queue: 'default').and_return(relation)
|
823
|
+
relation.should_receive(:last).and_return(double("job", id: "12341234", as_json: json))
|
824
|
+
result = subject.process_command(command)
|
825
|
+
expect(result.parameters).to eq({status: 'success', job: json})
|
826
|
+
end
|
827
|
+
it "handles no last job" do
|
828
|
+
command = Command.new(:client, {command: 'last'})
|
829
|
+
relation = double('relation')
|
830
|
+
@job_class.should_receive(:where).with(queue: 'default').and_return(relation)
|
831
|
+
relation.should_receive(:last).and_return(nil)
|
832
|
+
result = subject.process_command(command)
|
833
|
+
expect(result.parameters).to eq({status: 'error', message: 'no last job'})
|
834
|
+
end
|
835
|
+
end
|
836
|
+
|
837
|
+
context "fetch" do
|
838
|
+
before do
|
839
|
+
@job_class = double('JobClass')
|
840
|
+
JobDispatch.config.job_class = @job_class
|
841
|
+
end
|
842
|
+
it "returns the job" do
|
843
|
+
command = Command.new(:client, {command: 'fetch', job_id: '12341234'})
|
844
|
+
json = {'id' => '12341234', 'queue' => 'ruby', 'target' => 'String', 'method' => 'new'}
|
845
|
+
job = double("Job", as_json: json)
|
846
|
+
@job_class.should_receive(:find).with('12341234').and_return(job)
|
847
|
+
result = subject.process_command(command)
|
848
|
+
expect(result.parameters).to eq({status: 'success', job: json})
|
849
|
+
end
|
850
|
+
it "returns error when job_id is not present" do
|
851
|
+
command = Command.new(:client, {command: 'fetch'})
|
852
|
+
result = subject.process_command(command)
|
853
|
+
expect(result.parameters[:status]).to eq('error')
|
854
|
+
end
|
855
|
+
it "returns error when job_id is not found" do
|
856
|
+
command = Command.new(:client, {command: 'fetch', job_id: '12341234'})
|
857
|
+
@job_class.should_receive(:find).with('12341234').and_raise(StandardError, "not found")
|
858
|
+
result = subject.process_command(command)
|
859
|
+
expect(result.parameters[:status]).to eq('error')
|
860
|
+
end
|
861
|
+
end
|
782
862
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: job_dispatch
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matt Connolly
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-07-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rbczmq
|