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