geary 0.0.1
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 +7 -0
- data/README.markdown +76 -0
- data/bin/geary +9 -0
- data/lib/gearman/client.rb +80 -0
- data/lib/gearman/connection.rb +132 -0
- data/lib/gearman/error.rb +7 -0
- data/lib/gearman/packet.rb +9 -0
- data/lib/gearman/packet/repository.rb +35 -0
- data/lib/gearman/packet/sugar.rb +103 -0
- data/lib/gearman/worker.rb +61 -0
- data/lib/geary.rb +8 -0
- data/lib/geary/cli.rb +86 -0
- data/lib/geary/configuration.rb +18 -0
- data/lib/geary/error.rb +7 -0
- data/lib/geary/manager.rb +84 -0
- data/lib/geary/option_parser.rb +42 -0
- data/lib/geary/performer.rb +73 -0
- data/lib/geary/railtie.rb +9 -0
- data/lib/geary/worker.rb +49 -0
- data/spec/gearman/client_spec.rb +36 -0
- data/spec/gearman/connection_spec.rb +67 -0
- data/spec/gearman/packet/sugar_spec.rb +58 -0
- data/spec/gearman/packet_spec.rb +22 -0
- data/spec/gearman/worker_spec.rb +68 -0
- data/spec/geary/cli_spec.rb +40 -0
- data/spec/geary/manager_spec.rb +123 -0
- data/spec/geary/option_parser_spec.rb +17 -0
- data/spec/geary/performer_spec.rb +128 -0
- data/spec/geary/worker_spec.rb +23 -0
- metadata +222 -0
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'gearman/client'
|
2
|
+
require 'support/fake_server'
|
3
|
+
require 'uri'
|
4
|
+
|
5
|
+
module Gearman
|
6
|
+
describe Client do
|
7
|
+
|
8
|
+
let!(:address) { URI('gearman://127.0.0.1:4730') }
|
9
|
+
let!(:gearmand) { FakeServer.new(address) }
|
10
|
+
|
11
|
+
before do
|
12
|
+
gearmand.async.run
|
13
|
+
gearmand.wait :accept
|
14
|
+
end
|
15
|
+
|
16
|
+
after { gearmand.shutdown }
|
17
|
+
|
18
|
+
it 'submits background jobs' do
|
19
|
+
gearmand.respond_with(Packet::JOB_CREATED.new(['handle']))
|
20
|
+
|
21
|
+
expected_packet = Packet::SUBMIT_JOB_BG.new(
|
22
|
+
function_name: 'super_ability',
|
23
|
+
unique_id: 'UUID',
|
24
|
+
data: 'data'
|
25
|
+
)
|
26
|
+
|
27
|
+
client = Client.new(address)
|
28
|
+
client.generate_unique_id_with -> { 'UUID' }
|
29
|
+
|
30
|
+
client.submit_job_bg('super_ability', 'data')
|
31
|
+
|
32
|
+
expect(gearmand.packets_read.last).to eql(expected_packet)
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'gearman/connection'
|
2
|
+
require 'support/fake_server'
|
3
|
+
require 'support/without_logging'
|
4
|
+
require 'uri'
|
5
|
+
|
6
|
+
module Gearman
|
7
|
+
|
8
|
+
describe Connection do
|
9
|
+
include WithoutLogging
|
10
|
+
|
11
|
+
let!(:address) { URI('gearman://127.0.0.1:4730') }
|
12
|
+
let!(:server) { FakeServer.new(address) }
|
13
|
+
|
14
|
+
before do
|
15
|
+
server.async.run
|
16
|
+
server.wait :accept
|
17
|
+
end
|
18
|
+
|
19
|
+
after do
|
20
|
+
server.shutdown
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'can write packets to a socket' do
|
24
|
+
connection = Connection.new(address)
|
25
|
+
connection.write(Gearman::Packet::WORK_COMPLETE.new(['*', '*']))
|
26
|
+
|
27
|
+
expect(server.packets_read.last).
|
28
|
+
to eql(Gearman::Packet::WORK_COMPLETE.new(['*', '*']))
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'can read packets from a socket' do
|
32
|
+
server.respond_with(Gearman::Packet::NO_JOB.new)
|
33
|
+
|
34
|
+
connection = Connection.new(address)
|
35
|
+
connection.write(Gearman::Packet::GRAB_JOB.new)
|
36
|
+
|
37
|
+
expect(connection.next).to eql(Gearman::Packet::NO_JOB.new)
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'can specify that it expects only certain types of packets' do
|
41
|
+
without_logging do
|
42
|
+
server.respond_with(Gearman::Packet::JOB_ASSIGN.new([1] * 3))
|
43
|
+
|
44
|
+
connection = Connection.new(address)
|
45
|
+
connection.write(Gearman::Packet::GRAB_JOB.new)
|
46
|
+
|
47
|
+
expect do
|
48
|
+
connection.next(Gearman::Packet::NO_JOB)
|
49
|
+
end.to raise_error(Connection::UnexpectedPacketError)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'will raise a ServerError if it reads an error packet' do
|
54
|
+
without_logging do
|
55
|
+
server.respond_with(Gearman::Packet::ERROR.new(["E", "T"]))
|
56
|
+
|
57
|
+
connection = Connection.new(address)
|
58
|
+
connection.write(Gearman::Packet::GRAB_JOB.new)
|
59
|
+
|
60
|
+
expect do
|
61
|
+
connection.next(Gearman::Packet::NO_JOB)
|
62
|
+
end.to raise_error(Connection::ServerError)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'gearman/packet/sugar'
|
2
|
+
|
3
|
+
module Gearman
|
4
|
+
module Packet
|
5
|
+
|
6
|
+
describe Sugar do
|
7
|
+
|
8
|
+
it 'allows classes to create initializers which accept options' do
|
9
|
+
class_ = Class.new { extend Sugar ; takes(:foo, :bar) }
|
10
|
+
object = class_.new(foo: 'foo', bar: 'bar')
|
11
|
+
|
12
|
+
expect(object.foo).to eql('foo')
|
13
|
+
expect(object.bar).to eql('bar')
|
14
|
+
expect(object.arguments).to eql(['foo', 'bar'])
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'allows classes to create initializers which accept positional arguments' do
|
18
|
+
class_ = Class.new { extend Sugar ; takes(:foo, :bar) }
|
19
|
+
object = class_.new(['foo', 'bar'])
|
20
|
+
|
21
|
+
expect(object.foo).to eql('foo')
|
22
|
+
expect(object.bar).to eql('bar')
|
23
|
+
expect(object.arguments).to eql(['foo', 'bar'])
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'raises an ArgumentError if given something other than a Hash or an Array' do
|
27
|
+
class_ = Class.new { extend Sugar ; takes(:foo, :bar) }
|
28
|
+
|
29
|
+
expect do
|
30
|
+
object = class_.new(1)
|
31
|
+
end.to raise_error(ArgumentError)
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'allows classes to set "numbers" for their instances' do
|
35
|
+
class_ = Class.new { extend Sugar ; number 1 }
|
36
|
+
object = class_.new
|
37
|
+
|
38
|
+
expect(object.number).to eql(1)
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'can create new packet types with ease' do
|
42
|
+
type = Sugar.type 'CanDo', takes: [:function_name], number: 1
|
43
|
+
|
44
|
+
expect(type.new(['foo']).function_name).to eql('foo')
|
45
|
+
expect(type.new(function_name: 'foo').function_name).to eql('foo')
|
46
|
+
expect(type.new(function_name: 'foo').number).to eql(1)
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'creates packets with value equality' do
|
50
|
+
type = Sugar.type 'CanDo', takes: [:function_name], number: 1
|
51
|
+
|
52
|
+
expect(type.new(['foo'])).to eql(type.new(['foo']))
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'gearman/packet'
|
2
|
+
|
3
|
+
module Gearman
|
4
|
+
describe Packet do
|
5
|
+
|
6
|
+
before do
|
7
|
+
Packet::Repository.new
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'contains a bunch of packet types' do
|
11
|
+
%w(CAN_DO PRE_SLEEP NOOP GRAB_JOB NO_JOB JOB_ASSIGN
|
12
|
+
WORK_COMPLETE WORK_EXCEPTION).each do |type|
|
13
|
+
type = Gearman::Packet.const_get(type)
|
14
|
+
arguments = type.const_get('ARGUMENTS').map { 'foo ' }
|
15
|
+
|
16
|
+
expect do
|
17
|
+
type.new(arguments)
|
18
|
+
end.to_not raise_error
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'gearman/worker'
|
2
|
+
require 'support/actor_double'
|
3
|
+
|
4
|
+
module Gearman
|
5
|
+
|
6
|
+
class FakeConnection
|
7
|
+
include Celluloid
|
8
|
+
end
|
9
|
+
|
10
|
+
describe Worker do
|
11
|
+
include ActorDouble
|
12
|
+
|
13
|
+
let!(:connection) { actor_double }
|
14
|
+
|
15
|
+
it 'expects a NOOP after it sends PRE_SLEEP' do
|
16
|
+
connection.stub(:write)
|
17
|
+
connection.should_receive(:next).with(Packet::NOOP)
|
18
|
+
|
19
|
+
worker = Worker.new('gearman://localhost:4730')
|
20
|
+
worker.configure_connection ->(address) { connection }
|
21
|
+
|
22
|
+
worker.pre_sleep
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'expects either a JOB_ASSIGN or a NO_JOB when it grabs a job' do
|
26
|
+
connection.stub(:write)
|
27
|
+
connection.should_receive(:next).with(Packet::JOB_ASSIGN, Packet::NO_JOB)
|
28
|
+
|
29
|
+
worker = Worker.new('gearman://localhost:4730')
|
30
|
+
worker.configure_connection ->(address) { connection }
|
31
|
+
|
32
|
+
worker.grab_job
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'sends WORK_EXCEPTION' do
|
36
|
+
work_exception = Packet::WORK_EXCEPTION.new(handle: 'h', data: 'd')
|
37
|
+
connection.should_receive(:write).with(work_exception)
|
38
|
+
|
39
|
+
worker = Worker.new('gearman://localhost:4730')
|
40
|
+
worker.configure_connection ->(address) { connection }
|
41
|
+
|
42
|
+
worker.work_exception('h', 'd')
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'sends WORK_COMPLETE' do
|
46
|
+
work_complete = Packet::WORK_COMPLETE.new(handle: 'h', data: 'd')
|
47
|
+
connection.should_receive(:write).with(work_complete)
|
48
|
+
|
49
|
+
worker = Worker.new('gearman://localhost:4730')
|
50
|
+
worker.configure_connection ->(address) { connection }
|
51
|
+
|
52
|
+
worker.work_complete('h', 'd')
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'sends CAN_DO' do
|
56
|
+
can_do = Packet::CAN_DO.new(function_name: 'ability')
|
57
|
+
|
58
|
+
connection.should_receive(:write).with(can_do)
|
59
|
+
|
60
|
+
worker = Worker.new('gearman://localhost:4730')
|
61
|
+
worker.configure_connection ->(address) { connection }
|
62
|
+
|
63
|
+
worker.can_do('ability')
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'geary/cli'
|
2
|
+
|
3
|
+
require 'thread'
|
4
|
+
require 'timeout'
|
5
|
+
|
6
|
+
module Geary
|
7
|
+
describe CLI do
|
8
|
+
|
9
|
+
it 'shuts down when sent TERM' do
|
10
|
+
kernel = double('kernel')
|
11
|
+
kernel.should_receive(:exit)
|
12
|
+
argv = ['-c 0']
|
13
|
+
cli = CLI.new(argv, STDOUT, STDERR, kernel)
|
14
|
+
|
15
|
+
t = Thread.new { cli.execute! }
|
16
|
+
t.abort_on_exception = true
|
17
|
+
|
18
|
+
cli.external_signal_queue.puts('TERM')
|
19
|
+
|
20
|
+
Timeout.timeout(1, StandardError) { t.value } rescue nil
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'shuts down when sent INT' do
|
24
|
+
kernel = double('kernel')
|
25
|
+
kernel.should_receive(:exit)
|
26
|
+
|
27
|
+
argv = ['-c 0']
|
28
|
+
cli = CLI.new(argv, STDOUT, STDERR, kernel)
|
29
|
+
|
30
|
+
t = Thread.new { cli.execute! }
|
31
|
+
t.abort_on_exception = true
|
32
|
+
|
33
|
+
IO.select([], [cli.external_signal_queue])
|
34
|
+
cli.external_signal_queue.puts('INT')
|
35
|
+
|
36
|
+
Timeout.timeout(1, StandardError) { t.value } rescue nil
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
require 'gearmand_control'
|
2
|
+
|
3
|
+
require 'geary/configuration'
|
4
|
+
require 'geary/manager'
|
5
|
+
|
6
|
+
require 'support/fake_performer'
|
7
|
+
require 'support/with_tolerance'
|
8
|
+
require 'support/without_logging'
|
9
|
+
|
10
|
+
module Geary
|
11
|
+
|
12
|
+
describe Manager do
|
13
|
+
include WithTolerance
|
14
|
+
include WithoutLogging
|
15
|
+
|
16
|
+
let(:configuration) do
|
17
|
+
configuration = Configuration.new(
|
18
|
+
server_addresses: ['gearman://localhost:4730'],
|
19
|
+
concurrency: 2
|
20
|
+
)
|
21
|
+
end
|
22
|
+
|
23
|
+
describe 'starting the manager' do
|
24
|
+
|
25
|
+
it 'establishes a link to managed performers' do
|
26
|
+
manager = Manager.new(configuration: configuration,
|
27
|
+
performer_type: FakePerformer)
|
28
|
+
manager.start
|
29
|
+
|
30
|
+
expect(manager.links.count).to eql(2)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'starts each managed performer' do
|
34
|
+
manager = Manager.new(configuration: configuration,
|
35
|
+
performer_type: FakePerformer)
|
36
|
+
manager.start
|
37
|
+
|
38
|
+
expect(manager.links.all?(&:started?)).to be_true
|
39
|
+
expect(manager.links.map(&:server_address).uniq).
|
40
|
+
to eql(configuration.server_addresses)
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
describe 'performer supervision' do
|
46
|
+
|
47
|
+
it 'restarts performers when they die' do
|
48
|
+
without_logging do
|
49
|
+
manager = Manager.new(configuration: configuration,
|
50
|
+
performer_type: FakePerformer)
|
51
|
+
manager.start
|
52
|
+
|
53
|
+
imminently_dead_performers = manager.performers
|
54
|
+
imminently_dead_performers.map(&:async).each(&:die)
|
55
|
+
|
56
|
+
with_tolerance do
|
57
|
+
expect(imminently_dead_performers.count(&:alive?)).to eql(0)
|
58
|
+
end
|
59
|
+
|
60
|
+
with_tolerance do
|
61
|
+
expect(manager.links.count).to eql(2)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'forgets performers if they die without a reason' do
|
67
|
+
without_logging do
|
68
|
+
manager = Manager.new(configuration: configuration,
|
69
|
+
performer_type: FakePerformer)
|
70
|
+
manager.start
|
71
|
+
|
72
|
+
forgettable_performers = manager.performers
|
73
|
+
forgettable_performers.map(&:async).each(&:die_quietly)
|
74
|
+
|
75
|
+
with_tolerance do
|
76
|
+
expect(forgettable_performers.count(&:alive?)).to eql(0)
|
77
|
+
end
|
78
|
+
|
79
|
+
with_tolerance do
|
80
|
+
expect(manager.links.count).to eql(0)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
describe 'ceasing management' do
|
88
|
+
|
89
|
+
it 'terminates linked performers' do
|
90
|
+
manager = Manager.new(configuration: configuration,
|
91
|
+
performer_type: FakePerformer)
|
92
|
+
manager.start
|
93
|
+
|
94
|
+
performers = manager.performers
|
95
|
+
|
96
|
+
expect do
|
97
|
+
manager.stop
|
98
|
+
end.to change { performers.count(&:alive?) }.from(2).to(0)
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'unlinks linked performers' do
|
102
|
+
manager = Manager.new(configuration: configuration,
|
103
|
+
performer_type: FakePerformer)
|
104
|
+
manager.start
|
105
|
+
|
106
|
+
expect do
|
107
|
+
manager.stop
|
108
|
+
end.to change { manager.links.count }.from(2).to(0)
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'signals that it has stopped' do
|
112
|
+
manager = Manager.new(configuration: configuration,
|
113
|
+
performer_type: FakePerformer)
|
114
|
+
manager.async.start
|
115
|
+
manager.async.stop
|
116
|
+
|
117
|
+
expect(manager.wait :done).to be_nil
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'geary/option_parser'
|
2
|
+
|
3
|
+
module Geary
|
4
|
+
describe OptionParser do
|
5
|
+
|
6
|
+
it 'understands comma-delimited servers to mean multiple servers' do
|
7
|
+
args = ['-s', 'gearman://localhost:4730,gearman://localhost:4731']
|
8
|
+
parser = OptionParser.new
|
9
|
+
|
10
|
+
configuration = parser.parse(args)
|
11
|
+
|
12
|
+
expect(configuration.server_addresses.map(&:to_s)).
|
13
|
+
to eql(['gearman://localhost:4730', 'gearman://localhost:4731'])
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
require 'geary/performer'
|
2
|
+
require 'support/actor_double'
|
3
|
+
require 'support/without_logging'
|
4
|
+
require 'uri'
|
5
|
+
|
6
|
+
module Geary
|
7
|
+
describe Performer do
|
8
|
+
include ActorDouble
|
9
|
+
include WithoutLogging
|
10
|
+
|
11
|
+
let(:address) do
|
12
|
+
URI('gearman://localhost:4730')
|
13
|
+
end
|
14
|
+
|
15
|
+
let(:gearman) { actor_double }
|
16
|
+
|
17
|
+
it 'registers its ability with Gearman' do
|
18
|
+
gearman.stub(:grab_job)
|
19
|
+
gearman.should_receive(:can_do)
|
20
|
+
|
21
|
+
performer = Performer.new(address)
|
22
|
+
performer.configure_connection ->(address) { gearman }
|
23
|
+
|
24
|
+
performer.start
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'tries to pop a job off the queue' do
|
28
|
+
gearman.stub(:can_do)
|
29
|
+
gearman.should_receive(:grab_job)
|
30
|
+
|
31
|
+
performer = Performer.new(address)
|
32
|
+
performer.configure_connection ->(address) { gearman }
|
33
|
+
|
34
|
+
performer.start
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'sleeps if it gets a NO_JOB' do
|
38
|
+
gearman.stub(:can_do)
|
39
|
+
gearman.stub(:grab_job).and_return(Gearman::Packet::NO_JOB.new, nil)
|
40
|
+
gearman.should_receive(:pre_sleep)
|
41
|
+
|
42
|
+
performer = Performer.new(address)
|
43
|
+
performer.configure_connection ->(address) { gearman }
|
44
|
+
|
45
|
+
performer.start
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'performs the job if it gets a JOB_ASSIGN' do
|
49
|
+
worker_class = Class.new { }
|
50
|
+
worker = worker_class.any_instance
|
51
|
+
|
52
|
+
Object.const_set('A', worker_class)
|
53
|
+
|
54
|
+
job = JSON.dump({
|
55
|
+
class: 'A',
|
56
|
+
args: ['a']
|
57
|
+
})
|
58
|
+
|
59
|
+
job_assign = Gearman::Packet::JOB_ASSIGN.new(['h', 'f', job])
|
60
|
+
|
61
|
+
gearman.stub(:can_do)
|
62
|
+
gearman.stub(:grab_job).and_return(job_assign, nil)
|
63
|
+
gearman.stub(:work_complete)
|
64
|
+
|
65
|
+
worker.should_receive(:perform).with('a')
|
66
|
+
|
67
|
+
performer = Performer.new(address)
|
68
|
+
performer.configure_connection ->(address) { gearman }
|
69
|
+
|
70
|
+
performer.start
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'sends the result of a job to Gearman' do
|
74
|
+
worker_class = Class.new { }
|
75
|
+
worker = worker_class.any_instance
|
76
|
+
worker.stub(:perform) { 'result' }
|
77
|
+
|
78
|
+
Object.const_set('B', worker_class)
|
79
|
+
|
80
|
+
job = JSON.dump({
|
81
|
+
class: 'B',
|
82
|
+
args: ['a']
|
83
|
+
})
|
84
|
+
|
85
|
+
async_proxy = double('gearman.async')
|
86
|
+
job_assign = Gearman::Packet::JOB_ASSIGN.new(['h', 'f', job])
|
87
|
+
|
88
|
+
gearman.stub(:can_do)
|
89
|
+
gearman.stub(:grab_job).and_return(job_assign, nil)
|
90
|
+
gearman.stub(:async) { async_proxy }
|
91
|
+
async_proxy.should_receive(:work_complete).with('h', 'result')
|
92
|
+
|
93
|
+
performer = Performer.new(address)
|
94
|
+
performer.configure_connection ->(address) { gearman }
|
95
|
+
|
96
|
+
performer.start
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'sends a WORK_EXCEPTION to Gearman if the job raises' do
|
100
|
+
worker_class = Class.new { }
|
101
|
+
worker = worker_class.any_instance
|
102
|
+
worker.stub(:perform).and_raise RuntimeError, "ack!"
|
103
|
+
|
104
|
+
Object.const_set('C', worker_class)
|
105
|
+
|
106
|
+
job = JSON.dump({
|
107
|
+
class: 'C',
|
108
|
+
args: ['a']
|
109
|
+
})
|
110
|
+
|
111
|
+
async_proxy = double('gearman.async')
|
112
|
+
job_assign = Gearman::Packet::JOB_ASSIGN.new(['h', 'f', job])
|
113
|
+
|
114
|
+
gearman.stub(:can_do)
|
115
|
+
gearman.stub(:grab_job).and_return(job_assign, nil)
|
116
|
+
gearman.stub(:async) { async_proxy }
|
117
|
+
async_proxy.should_receive(:work_exception).with('h', 'ack!')
|
118
|
+
|
119
|
+
performer = Performer.new(address)
|
120
|
+
performer.configure_connection ->(address) { gearman }
|
121
|
+
|
122
|
+
performer.start
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'can repair its connection to Gearman'
|
126
|
+
|
127
|
+
end
|
128
|
+
end
|