gearman-ruby 3.0.8 → 4.0.2

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.
Files changed (54) hide show
  1. checksums.yaml +8 -8
  2. data/.travis.yml +5 -0
  3. data/CHANGELOG.md +6 -4
  4. data/README.md +111 -0
  5. data/examples/client.rb +1 -2
  6. data/examples/client_reverse_nohost.rb +30 -0
  7. data/examples/{client_reverse.rb → client_reverse_wait.rb} +9 -11
  8. data/examples/worker.rb +8 -5
  9. data/examples/worker_reverse_string.rb +12 -17
  10. data/gearman-ruby.gemspec +3 -5
  11. data/lib/gearman.rb +17 -77
  12. data/lib/gearman/client.rb +129 -147
  13. data/lib/gearman/connection.rb +158 -0
  14. data/lib/gearman/connection_pool.rb +131 -0
  15. data/lib/gearman/exceptions.rb +24 -0
  16. data/lib/gearman/logging.rb +19 -0
  17. data/lib/gearman/packet.rb +61 -0
  18. data/lib/gearman/task.rb +1 -1
  19. data/lib/gearman/task_set.rb +67 -0
  20. data/lib/gearman/version.rb +1 -1
  21. data/lib/gearman/worker.rb +185 -412
  22. data/lib/gearman/worker/ability.rb +55 -0
  23. data/lib/gearman/worker/callbacks.rb +39 -0
  24. data/lib/gearman/worker/job.rb +44 -0
  25. data/spec/client_spec.rb +32 -20
  26. data/spec/connection_pool_spec.rb +55 -0
  27. data/spec/spec_helper.rb +5 -0
  28. data/spec/task_spec.rb +10 -0
  29. data/spec/taskset_spec.rb +2 -2
  30. metadata +18 -37
  31. data/HOWTO +0 -146
  32. data/README +0 -9
  33. data/TODO +0 -8
  34. data/VERSION.yml +0 -4
  35. data/examples/calculus_client.rb +0 -39
  36. data/examples/calculus_worker.rb +0 -45
  37. data/examples/client.php +0 -23
  38. data/examples/client_background.rb +0 -14
  39. data/examples/client_data.rb +0 -16
  40. data/examples/client_epoch.rb +0 -23
  41. data/examples/client_exception.rb +0 -19
  42. data/examples/client_prefix.rb +0 -17
  43. data/examples/gearman_environment.sh +0 -25
  44. data/examples/scale_image.rb +0 -31
  45. data/examples/scale_image_worker.rb +0 -34
  46. data/examples/server.rb +0 -15
  47. data/examples/worker_data.rb +0 -16
  48. data/examples/worker_exception.rb +0 -14
  49. data/examples/worker_prefix.rb +0 -25
  50. data/examples/worker_reverse_to_file.rb +0 -18
  51. data/examples/worker_signals.rb +0 -36
  52. data/lib/gearman/taskset.rb +0 -293
  53. data/lib/gearman/util.rb +0 -211
  54. data/spec/util_spec.rb +0 -67
@@ -0,0 +1,55 @@
1
+ module Gearman
2
+ class Worker
3
+
4
+ class Ability
5
+ ##
6
+ # Create a new ability. Setting timeout means we register with CAN_DO_TIMEOUT
7
+ # @param func_name Function name of this ability
8
+ # @param block Code to run
9
+ # @param timeout Server gives up on us after this many seconds
10
+ def initialize(func_name, block, timeout=nil)
11
+ @func_name = func_name
12
+ @block = block
13
+ @timeout = timeout
14
+ @on_complete = nil
15
+ end
16
+
17
+ attr_reader :timeout, :func_name
18
+
19
+ ##
20
+ # Run the block of code given for a job of this type.
21
+ #
22
+ # @param data data passed to us by a client
23
+ # @param job interface to report job information to the server
24
+ def run(data, job)
25
+ begin
26
+ result = @block.call(data, job) if @block
27
+ @on_complete.call(result, data) if @on_complete
28
+ return result
29
+ rescue => ex
30
+ raise ex
31
+ end
32
+ end
33
+
34
+ ##
35
+ # Add an after-ability hook
36
+ #
37
+ # The passed-in block of code will be executed after the work block for
38
+ # jobs with the same function name. It takes two arguments, the result of
39
+ # the work and the original job data. This way, if you need to hook into
40
+ # *after* the job_complete packet is sent to the server, you can do so.
41
+ #
42
+ # N.B The after-ability hook ONLY runs if the ability was successful and no
43
+ # exceptions were raised.
44
+ #
45
+ # @param func function name (without prefix)
46
+ #
47
+ def after_complete(&block)
48
+ @on_complete = block
49
+ end
50
+
51
+
52
+ end
53
+
54
+ end
55
+ end
@@ -0,0 +1,39 @@
1
+ # Provides callbacks for internal worker use:
2
+ #
3
+ # def named_metric(metric)
4
+ # "HardWorker.#{Process.pid}.#{metric}"
5
+ # end
6
+ #
7
+ # worker = Gearman::Worker.new
8
+ # worker.on_grab_job { StatsD.increment(named_metric('grab_job')) }
9
+ # worker.on_job_assign { StatsD.increment(named_metric('job_assign')) }
10
+ # worker.on_no_job { StatsD.increment(named_metric('no_job')) }
11
+ # worker.on_work_complete { StatsD.increment(named_metric('work_complete')) }
12
+
13
+ module Gearman
14
+ class Worker
15
+
16
+ module Callbacks
17
+
18
+ %w(connect grab_job no_job job_assign work_complete work_fail
19
+ work_exception).each do |event|
20
+
21
+ define_method("on_#{event}") do |&callback|
22
+ instance_variable_set("@__on_#{event}", callback)
23
+ end
24
+
25
+ define_method("run_#{event}_callback") do
26
+ callback = instance_variable_get("@__on_#{event}")
27
+ return unless callback
28
+
29
+ begin
30
+ callback.call
31
+ rescue Exception => e
32
+ logger.error "#{event} failed: #{e.inspect}"
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ end
39
+ end
@@ -0,0 +1,44 @@
1
+ module Gearman
2
+ class Worker
3
+
4
+ class Job
5
+ ##
6
+ # Create a new Job.
7
+ #
8
+ # @param sock Socket connected to job server
9
+ # @param handle job server-supplied job handle
10
+ attr_reader :handle
11
+
12
+ def initialize(connection, handle)
13
+ @connection = connection
14
+ @handle = handle
15
+ end
16
+
17
+ ##
18
+ # Report our status to the job server.
19
+ def report_status(numerator, denominator)
20
+ req = Packet.pack_request(:work_status, "#{@handle}\0#{numerator}\0#{denominator}")
21
+ @connection.send_update(req)
22
+ self
23
+ end
24
+
25
+ ##
26
+ # Send data before job completes
27
+ def send_data(data)
28
+ req = Packet.pack_request(:work_data, "#{@handle}\0#{data}")
29
+ @connection.send_update(req)
30
+ self
31
+ end
32
+
33
+ ##
34
+ # Send a warning explicitly
35
+ def report_warning(warning)
36
+ req = Packet.pack_request(:work_warning, "#{@handle}\0#{warning}")
37
+ @connection.send_update(req)
38
+ self
39
+ end
40
+ end
41
+
42
+ end
43
+ end
44
+
@@ -1,19 +1,22 @@
1
1
  require 'spec_helper'
2
2
  require 'socket'
3
- require 'rspec'
4
- require 'rspec/mocks'
5
- require 'gearman'
6
3
 
7
4
  describe Gearman::Client do
8
5
  before(:all) do
9
6
  @tcp_server = TCPServer.new 5789
10
- @client = Gearman::Client.new(["localhost:5789"])
11
7
  end
12
8
 
13
9
  after(:all) do
14
10
  @tcp_server.close
15
11
  end
16
12
 
13
+ before(:each) do
14
+ @mock_connection_pool = double(Gearman::ConnectionPool)
15
+ Gearman::ConnectionPool.stub(:new).and_return @mock_connection_pool
16
+
17
+ @client = Gearman::Client.new(["localhost:5789"])
18
+ end
19
+
17
20
  it "creates a client" do
18
21
  @client.should_not be nil
19
22
  end
@@ -30,31 +33,40 @@ describe Gearman::Client do
30
33
 
31
34
  it "raises an exception when submitting a job fails" do
32
35
  task = Gearman::Task.new("queue", "data")
33
- @client.should_receive(:get_job_server).and_raise Gearman::NoJobServersError
36
+ @mock_connection_pool.should_receive(:get_connection).and_raise Gearman::NoJobServersError
34
37
  expect {
35
38
  @client.do_task(task)
36
- }.to raise_error
39
+ }.to raise_exception
37
40
  end
38
41
 
39
- it "gets a socket for the client's host:port combo" do
40
- sock = @client.get_socket("localhost:5789")
41
- sock.should_not be nil
42
- end
42
+ it "properly emits an options request" do
43
+ mock_connection = double(Gearman::Connection)
44
+ mock_connection.should_receive(:send_request).and_return([:error, "Snarf"])
43
45
 
44
- it "closes sockets it doesn't know about when asked to return them" do
45
- sock = double(TCPSocket)
46
- sock.should_receive(:addr).and_return [nil, 1234, 'hostname', '1.2.3.4']
47
- sock.should_receive(:close)
48
- @client.return_socket(sock)
49
- end
46
+ @mock_connection_pool.should_receive(:with_all_connections).and_yield mock_connection
50
47
 
51
- it "properly emits an options request" do
52
- Gearman::Util.should_receive(:send_request)
53
- Gearman::Util.should_receive(:read_response).and_return([:error, "Snarf"])
54
48
  expect {
55
- @client.option_request("exceptions")
49
+ @client.set_options("exceptions")
56
50
  }.to raise_error
57
51
 
58
52
  end
59
53
 
54
+
55
+
56
+ it "should raise a NetworkError when it didn't write as much as expected to a socket" do
57
+ socket = double(TCPSocket)
58
+ socket.should_receive(:write).with(anything).and_return(0)
59
+
60
+ task = Gearman::Task.new("job_queue", "data")
61
+ request = task.get_submit_packet
62
+ connection = Gearman::Connection.new("localhost", 1234)
63
+ connection.should_receive(:socket).and_return socket
64
+
65
+ expect {
66
+ connection.send_request(request)
67
+ }.to raise_error
68
+ end
69
+
70
+
71
+
60
72
  end
@@ -0,0 +1,55 @@
1
+
2
+ require 'spec_helper'
3
+ require 'socket'
4
+
5
+ describe Gearman::ConnectionPool do
6
+ context "normalizing job servers" do
7
+ before :each do
8
+ @connection_pool = Gearman::ConnectionPool.new
9
+ end
10
+
11
+ it "should handle a string for input" do
12
+ connection = Gearman::Connection.new("localhost", 1234)
13
+ connection.should_receive(:is_healthy?).and_return true
14
+ Gearman::Connection.should_receive(:new).with("localhost", 1234).and_return connection
15
+ @connection_pool.add_servers("localhost:1234")
16
+ @connection_pool.get_connection.should be connection
17
+ end
18
+
19
+ it "should handle an array of host:port without changing a thing" do
20
+ connection_one = Gearman::Connection.new("localhost", 123)
21
+ connection_one.should_receive(:is_healthy?).and_return true
22
+ connection_two = Gearman::Connection.new("localhost", 456)
23
+ connection_two.should_receive(:is_healthy?).and_return true
24
+
25
+ Gearman::Connection.should_receive(:new).with("localhost", 123).and_return connection_one
26
+ Gearman::Connection.should_receive(:new).with("localhost", 456).and_return connection_two
27
+
28
+ servers = [ "#{connection_one.to_host_port}", "#{connection_two.to_host_port}" ]
29
+ @connection_pool.add_servers(servers)
30
+
31
+
32
+ @connection_pool.get_connection.should be connection_two
33
+ @connection_pool.get_connection.should be connection_one
34
+
35
+ end
36
+
37
+ it "should append the default port to anything in the array that doesn't have a port" do
38
+ in_servers = ["foo.bar.com:123", "narf.quiddle.com"]
39
+ out_servers = ["foo.bar.com:123", "narf.quiddle.com:4730"]
40
+
41
+ connection_one = Gearman::Connection.new("foo.bar.com", 123)
42
+ connection_one.should_receive(:is_healthy?).and_return true
43
+ connection_two = Gearman::Connection.new("narf.quiddle.com", 4730)
44
+ connection_two.should_receive(:is_healthy?).and_return true
45
+
46
+ Gearman::Connection.should_receive(:new).with("foo.bar.com", 123).and_return connection_one
47
+ Gearman::Connection.should_receive(:new).with("narf.quiddle.com", 4730).and_return connection_two
48
+
49
+ @connection_pool.add_servers(in_servers)
50
+
51
+ @connection_pool.get_connection.should be connection_two
52
+ @connection_pool.get_connection.should be connection_one
53
+ end
54
+ end
55
+ end
@@ -1,4 +1,6 @@
1
1
  require 'simplecov'
2
+ require 'rspec'
3
+ require 'rspec/mocks'
2
4
 
3
5
  SimpleCov.start do
4
6
  add_filter "/spec/"
@@ -8,6 +10,9 @@ end
8
10
  $:.unshift(File.expand_path('../lib', __FILE__))
9
11
  require 'gearman'
10
12
 
13
+ Gearman.logger = Logger.new(STDERR)
14
+ Gearman.logger.level = Logger::DEBUG
15
+
11
16
  RSpec.configure do |config|
12
17
  config.mock_with :rspec
13
18
  end
@@ -16,6 +16,16 @@ describe Gearman::Task do
16
16
  }.to raise_error
17
17
  end
18
18
 
19
+ it "should generate a task from two arguments" do
20
+ task = Gearman::Task.new("queue", "data")
21
+ task.should_not be nil
22
+ end
23
+
24
+ it "should generate a task from three arguments" do
25
+ task = Gearman::Task.new("queue", "data", {:background => true})
26
+ task.should_not be nil
27
+ end
28
+
19
29
  it "generates a uniq value based on the data and the function" do
20
30
  hash_data = 'bc2ca93d86a28cb72fedf36326d1da0cc3d4ed6a'
21
31
  task_one = Gearman::Task.new("unique_id", "abcdef")
@@ -13,7 +13,7 @@ describe Gearman::TaskSet do
13
13
 
14
14
  end
15
15
 
16
- it "handles a NetworkError when submitting a job" do
16
+ xit "handles a NetworkError when submitting a job" do
17
17
  bad_socket = double(TCPSocket)
18
18
  bad_socket.should_receive(:write) { |*args|
19
19
  args[0].length
@@ -41,7 +41,7 @@ describe Gearman::TaskSet do
41
41
  task_set.add_task(task)
42
42
  end
43
43
 
44
- it "waits for an answer from the server" do
44
+ xit "waits for an answer from the server" do
45
45
  good_socket = double(TCPSocket)
46
46
  good_socket.should_receive(:write) { |*args|
47
47
  args[0].length
metadata CHANGED
@@ -1,21 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gearman-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.8
4
+ version: 4.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Ewart
8
- - Colin Curtin
9
- - Daniel Erat
10
- - Ladislav Martincik
11
- - Pablo Delgado
12
- - Mauro Pompilio
13
- - Antonio Garrote
14
- - Kim Altintop
15
8
  autorequire:
16
9
  bindir: bin
17
10
  cert_chain: []
18
- date: 2013-07-25 00:00:00.000000000 Z
11
+ date: 2014-11-29 00:00:00.000000000 Z
19
12
  dependencies: []
20
13
  description: Library for the Gearman distributed job system
21
14
  email: john@johnewart.net
@@ -23,54 +16,42 @@ executables: []
23
16
  extensions: []
24
17
  extra_rdoc_files:
25
18
  - LICENSE
26
- - README
27
- - TODO
19
+ - README.md
28
20
  files:
29
21
  - .gitignore
22
+ - .travis.yml
30
23
  - CHANGELOG.md
31
24
  - Gemfile
32
- - HOWTO
33
25
  - LICENSE
34
- - README
26
+ - README.md
35
27
  - Rakefile
36
- - TODO
37
- - VERSION.yml
38
- - examples/calculus_client.rb
39
- - examples/calculus_worker.rb
40
- - examples/client.php
41
28
  - examples/client.rb
42
- - examples/client_background.rb
43
- - examples/client_data.rb
44
- - examples/client_epoch.rb
45
- - examples/client_exception.rb
46
- - examples/client_prefix.rb
47
- - examples/client_reverse.rb
48
- - examples/gearman_environment.sh
49
- - examples/scale_image.rb
50
- - examples/scale_image_worker.rb
51
- - examples/server.rb
29
+ - examples/client_reverse_nohost.rb
30
+ - examples/client_reverse_wait.rb
52
31
  - examples/worker.rb
53
- - examples/worker_data.rb
54
- - examples/worker_exception.rb
55
- - examples/worker_prefix.rb
56
32
  - examples/worker_reverse_string.rb
57
- - examples/worker_reverse_to_file.rb
58
- - examples/worker_signals.rb
59
33
  - gearman-ruby.gemspec
60
34
  - lib/gearman.rb
61
35
  - lib/gearman/client.rb
36
+ - lib/gearman/connection.rb
37
+ - lib/gearman/connection_pool.rb
38
+ - lib/gearman/exceptions.rb
39
+ - lib/gearman/logging.rb
40
+ - lib/gearman/packet.rb
62
41
  - lib/gearman/server.rb
63
42
  - lib/gearman/task.rb
64
- - lib/gearman/taskset.rb
65
- - lib/gearman/util.rb
43
+ - lib/gearman/task_set.rb
66
44
  - lib/gearman/version.rb
67
45
  - lib/gearman/worker.rb
46
+ - lib/gearman/worker/ability.rb
47
+ - lib/gearman/worker/callbacks.rb
48
+ - lib/gearman/worker/job.rb
68
49
  - spec/client_spec.rb
50
+ - spec/connection_pool_spec.rb
69
51
  - spec/spec_helper.rb
70
52
  - spec/support/fake_tcp_socket.rb
71
53
  - spec/task_spec.rb
72
54
  - spec/taskset_spec.rb
73
- - spec/util_spec.rb
74
55
  - test/client_test.rb
75
56
  - test/mock_client_test.rb
76
57
  - test/mock_worker_test.rb
@@ -102,11 +83,11 @@ specification_version: 4
102
83
  summary: Ruby Gearman library
103
84
  test_files:
104
85
  - spec/client_spec.rb
86
+ - spec/connection_pool_spec.rb
105
87
  - spec/spec_helper.rb
106
88
  - spec/support/fake_tcp_socket.rb
107
89
  - spec/task_spec.rb
108
90
  - spec/taskset_spec.rb
109
- - spec/util_spec.rb
110
91
  - test/client_test.rb
111
92
  - test/mock_client_test.rb
112
93
  - test/mock_worker_test.rb
data/HOWTO DELETED
@@ -1,146 +0,0 @@
1
- = GEARMAN
2
-
3
- "Gearman provides a generic application framework to farm out work to other
4
- machines or processes that are better suited to do the work. It allows you to
5
- do work in parallel, to load balance processing, and to call functions between
6
- languages. It can be used in a variety of applications, from high-availability
7
- web sites to the transport of database replication events. In other words, it
8
- is the nervous system for how distributed processing communicates."
9
-
10
- - http://www.gearman.org/
11
-
12
-
13
- == Setting up a basic environment
14
-
15
- A very basic Gearman environment will look like this:
16
-
17
- ----------
18
- | Client |
19
- ----------
20
- |
21
- --------------
22
- | Job Server |
23
- --------------
24
- |
25
- ----------------------------------------------
26
- | | | |
27
- ---------- ---------- ---------- ----------
28
- | Worker | | Worker | | Worker | | Worker |
29
- ---------- ---------- ---------- ----------
30
-
31
- And the behavior will be the following:
32
-
33
- * JobServer: Acts as a message passing point.
34
- * Client: Sends tasks to the JobServer. Will be connected to only one JobServer
35
- in case more than one exits for failover purposes.
36
- * Worker: Anounce his 'abilities' to the JobServer and waits for tasks.
37
-
38
- For the JobServer we recommend to use the offical Perl version, there's also a
39
- more performant C implementation of the server with support for persistent
40
- queues, bells and whistles but is not stable enough for production use at the
41
- time of this document was wrote.
42
-
43
- The Client and the Worker can be implemented in any language. This way you can
44
- send tasks from a Ruby client server, to a Perl or C worker in order to get
45
- better performance.
46
-
47
- == Installing the required software
48
-
49
- For the JobServer we recommend to use the offical Perl version, to install it:
50
-
51
- * Mac OS X: sudo port install p5-gearman-server
52
- * Debian/Ubuntu: sudo apt-get install gearman-server
53
-
54
- To get the Ruby libraries by Xing:
55
-
56
- git clone git://github.com/xing/gearman-ruby.git
57
-
58
- == Gearman demo
59
-
60
- Now you're ready for you first experience with Gearman. In the cloned repository
61
- you'll find an 'examples' directory.
62
-
63
- Run the 'gearman_environment.sh' to build an environment like the one showed in
64
- the diagram above.
65
-
66
- * Client: Will ask you for an arithmetic operation, like: 2+3
67
- The code of the client is in: 'examples/calculus_client.rb'
68
-
69
- * JobServer: The Perl server.
70
-
71
- * Workers: You'll have 4 worker, one for each of the basic arithmetic
72
- operations.
73
- The code of the worker is in: 'examples/calculus_worker.rb'
74
-
75
- There are other demos in the examples folder you can give a look at. Each demo usually
76
- consist in the client and server scripts.
77
-
78
- === Creating clients and tasks
79
-
80
- In order to get a job scheduled by a Gearman server using the gearman ruby library, there
81
- are three main objects you must interact with: Gearman::Client, Gearman::Task and Gearman::TaskSet.
82
- Let's review all of them briefly:
83
-
84
- - Gearman::Client -> the portion of the library storing the data about the connection to
85
- the Gearman server.
86
- - Gearman::Task -> a job execution request that will be dispatched by the Gearman server to
87
- worker and whose result data will be returned to the client.
88
- - Gearman::TaskSet -> a collection of tasks to be executed. The Taskset object will track the
89
- execution of the tasks with the info returned from the Gearman server
90
- and notify the client with the results or errors when all the tasks
91
- have completed their execution.
92
-
93
- To send a new task to the Gearman server, the client must build a new Gearman::Task object, add it to
94
- a Gearman::TaskSet that must hold a reference to a Gearman::Client and send the wait message to
95
- the TaskSet.
96
- The following code taken from examples/client.rb shows the process:
97
-
98
- ----------------------------------------------------
99
- servers = ['localhost:4730', 'localhost:4731']
100
-
101
- client = Gearman::Client.new(servers)
102
- taskset = Gearman::TaskSet.new(client)
103
-
104
- task = Gearman::Task.new('sleep', 20)
105
- task.on_complete {|d| puts d }
106
-
107
- taskset.add_task(task)
108
- taskset.wait(100)
109
- ----------------------------------------------------
110
-
111
- The name of the function to be executed is the first parameter to the constructor of the Task object.
112
- Take into account that the string you pass as a parameter will be used 'as it' by the Gearman server
113
- to locate a suitable worker for that function.
114
- The second parameter is the argument to be sent to the worker that will execute, if the arguments for
115
- the task are complex, a serialization format like YAML or XML must be agreeded with the workers.
116
- The last and optional parameter is a hash of options. The following options are currently available:
117
-
118
- - :priority -> (:high | :low) the priority of the job, a high priority job is executed before a low on
119
- - :background -> (true | false) a background task will return no further information to the client.
120
-
121
- The execution of a task in a Gearman remote worker can fail, the worker can throw an exception, etc.
122
- All these events can be handled by the client of the ruby library registering callback blocks.
123
- The following events are currently available:
124
-
125
- - on_complete -> the task was executed succesfully
126
- - on_fail -> the task fail for some unknown reason
127
- - on_retry -> after failure, the task is gonna be retried, the number of retries is passed
128
- - on_exception -> the remote worker send an exception notification, the exception text is passed
129
- - on_stauts -> a status update is sent by the remote worker
130
-
131
- In order to receive exception notifications in the client, this option must be sent in the server, the
132
- method option_request can be used this task. The following example, extracted from the examples/client_exception.rb
133
- demo script shows the process:
134
-
135
- ----------------------------------------------------
136
- client = Gearman::Client.new(servers)
137
- #try this out
138
- client.option_request("exceptions")
139
- ----------------------------------------------------
140
-
141
- This feature will only works if the server and workers have implemented support for the OPT_REQ and WORK_EXCEPTION
142
- messages of the Gearman protocol.
143
-
144
-
145
- Enjoy.
146
-