gearman-ruby 2.0.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.
Files changed (48) hide show
  1. data/.gitignore +1 -0
  2. data/HOWTO +146 -0
  3. data/LICENSE +20 -0
  4. data/README +9 -0
  5. data/Rakefile +41 -0
  6. data/TODO +8 -0
  7. data/VERSION.yml +4 -0
  8. data/examples/calculus_client.rb +41 -0
  9. data/examples/calculus_worker.rb +42 -0
  10. data/examples/client.rb +19 -0
  11. data/examples/client_background.rb +14 -0
  12. data/examples/client_data.rb +16 -0
  13. data/examples/client_echo.rb +16 -0
  14. data/examples/client_exception.rb +17 -0
  15. data/examples/client_prefix.rb +15 -0
  16. data/examples/evented_client.rb +23 -0
  17. data/examples/evented_worker.rb +26 -0
  18. data/examples/gearman_environment.sh +25 -0
  19. data/examples/scale_image.rb +30 -0
  20. data/examples/scale_image_worker.rb +34 -0
  21. data/examples/server.rb +15 -0
  22. data/examples/worker.rb +23 -0
  23. data/examples/worker_data.rb +16 -0
  24. data/examples/worker_echo.rb +20 -0
  25. data/examples/worker_echo_pprof.rb +5 -0
  26. data/examples/worker_exception.rb +14 -0
  27. data/examples/worker_prefix.rb +25 -0
  28. data/gearman-ruby.gemspec +111 -0
  29. data/lib/gearman.rb +29 -0
  30. data/lib/gearman/client.rb +80 -0
  31. data/lib/gearman/evented/client.rb +99 -0
  32. data/lib/gearman/evented/reactor.rb +86 -0
  33. data/lib/gearman/evented/worker.rb +118 -0
  34. data/lib/gearman/job.rb +38 -0
  35. data/lib/gearman/protocol.rb +110 -0
  36. data/lib/gearman/server.rb +94 -0
  37. data/lib/gearman/task.rb +99 -0
  38. data/lib/gearman/taskset.rb +11 -0
  39. data/lib/gearman/util.rb +52 -0
  40. data/lib/gearman/worker.rb +39 -0
  41. data/test/basic_integration_test.rb +121 -0
  42. data/test/crash_test.rb +69 -0
  43. data/test/job_test.rb +30 -0
  44. data/test/protocol_test.rb +132 -0
  45. data/test/test_helper.rb +31 -0
  46. data/test/util_test.rb +12 -0
  47. data/test/worker_test.rb +45 -0
  48. metadata +133 -0
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ pkg/
data/HOWTO ADDED
@@ -0,0 +1,146 @@
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 German 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
+
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 XING AG
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,9 @@
1
+ gearman-ruby
2
+ ===============
3
+
4
+ Library for the Gearman distributed job system
5
+
6
+ COPYRIGHT
7
+ =========
8
+
9
+ Copyright (c) 2009 XING AG. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,41 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+ require 'rcov/rcovtask'
5
+
6
+ begin
7
+ require 'jeweler'
8
+ Jeweler::Tasks.new do |s|
9
+ s.name = "gearman-ruby"
10
+ s.summary = "Library for the Gearman distributed job system"
11
+ s.email = "kim.altintop@gmail.com"
12
+ s.homepage = "http://github.com/kim/gearman-ruby"
13
+ s.description = "Library for the Gearman distributed job system"
14
+ s.authors = ["Kim Altintop"]
15
+ s.add_dependency 'eventmachine', '>= 0.12.8'
16
+ end
17
+ rescue LoadError
18
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
19
+ end
20
+
21
+ Rake::TestTask.new do |t|
22
+ t.libs << 'lib'
23
+ t.pattern = 'test/**/*_test.rb'
24
+ t.verbose = false
25
+ end
26
+
27
+ Rake::RDocTask.new do |rdoc|
28
+ rdoc.rdoc_dir = 'rdoc'
29
+ rdoc.title = 'Gearman Ruby'
30
+ rdoc.options << '--line-numbers' << '--inline-source'
31
+ rdoc.rdoc_files.include('README*')
32
+ rdoc.rdoc_files.include('lib/**/*.rb')
33
+ end
34
+
35
+ Rcov::RcovTask.new do |t|
36
+ t.libs << "test"
37
+ t.test_files = FileList['test/*_test.rb']
38
+ t.verbose = true
39
+ end
40
+
41
+ task :default => :test
data/TODO ADDED
@@ -0,0 +1,8 @@
1
+ - Failover strategies
2
+ - Client:
3
+ * If connected for the first time, try to connect to at least one server from the server array
4
+ * If already connected to a server, and it goes down, the client should go down as well
5
+ - Worker:
6
+ * If connected for the first time, try to connect to as many servers as it can.
7
+ Loop trough the bad servers, trying to reconnect to them as well.
8
+ * If a already connected to a server, and it goes down, wait and try to reconnect again.
data/VERSION.yml ADDED
@@ -0,0 +1,4 @@
1
+ ---
2
+ :patch: 0
3
+ :major: 2
4
+ :minor: 0
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require '../lib/gearman'
4
+ #Gearman::Util.debug = true
5
+
6
+ # Connect to the local server (at the default port 4730)
7
+ client = Gearman::Client.new('localhost')
8
+ taskset = Gearman::Taskset.new
9
+
10
+ # Get something to echo
11
+ puts '[client] Write a basic arithmetic operation:'
12
+ input = gets
13
+
14
+ operations = input.chomp.scan(/\d+[\+\-\*\/]\d+/).compact
15
+ puts "[client] The following operations were found: #{operations.inspect}"
16
+
17
+ # Setup a task for operation
18
+ operations.each do |op|
19
+ # Determining the operation
20
+ case op
21
+ when /\+/
22
+ type, data = 'addition', op.split('+')
23
+ when /\-/
24
+ type, data = 'subtraction', op.split('-')
25
+ when /\*/
26
+ type, data = 'multiplication', op.split('*')
27
+ when /\//
28
+ type, data = 'division', op.split('/')
29
+ end
30
+
31
+ task = Gearman::Task.new(type, Marshal.dump(data.map {|v| v.to_i}))
32
+ task.on_complete {|r| puts "[client] #{type} result is: #{r}" }
33
+ task.on_warning {|w| puts "[client] warn: #{w}" }
34
+ task.on_fail { puts "[client] calculation failed" }
35
+
36
+ # Sending the task to the server
37
+ puts "[client] Sending values: #{data.inspect}, to the '#{type}' worker"
38
+ taskset << task
39
+ end
40
+
41
+ client.run(taskset)
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require '../lib/gearman'
4
+
5
+ #Gearman::Util.debug = true
6
+
7
+ worker = Gearman::Worker.new('localhost')
8
+
9
+ # Additon ability
10
+ worker.add_ability('addition') do |data,job|
11
+ values = Marshal.load(data)
12
+ puts "[addition_worker] Calculating #{values.inspect}..."
13
+ # sleep 5
14
+ values.first + values.last
15
+ end
16
+
17
+ # Subtraction ability
18
+ worker.add_ability('subtraction') do |data,job|
19
+ values = Marshal.load(data)
20
+ puts "[subtraction_worker] Calculating #{values.inspect}..."
21
+ # sleep 5
22
+ values.first - values.last
23
+ end
24
+
25
+ # Multiplication worker
26
+ worker.add_ability('multiplication') do |data,job|
27
+ values = Marshal.load(data)
28
+ puts "[multiplication_worker] Calculating #{values.inspect}..."
29
+ # sleep 5
30
+ values.first * values.last
31
+ end
32
+
33
+ # Division worker
34
+ worker.add_ability('division') do |data,job|
35
+ values = Marshal.load(data)
36
+ puts "[division_worker] Calculating #{data.inspect}..."
37
+ # sleep 5
38
+ values.first / values.last
39
+ end
40
+
41
+ # Running the workers
42
+ worker.work
@@ -0,0 +1,19 @@
1
+ require 'rubygems'
2
+ #require 'gearman'
3
+ require '../lib/gearman'
4
+ Gearman::Util.debug = true
5
+
6
+ servers = ['localhost:4730', 'localhost:4731']
7
+
8
+ client = Gearman::Client.new(servers)
9
+ taskset = Gearman::Taskset.new
10
+
11
+ task = Gearman::Task.new('sleep', 2)
12
+ task.on_complete {|d| puts "TASK 1: #{d}" }
13
+ taskset << task
14
+
15
+ task = Gearman::Task.new('sleep', 2)
16
+ task.on_complete {|d| puts "TASK 2: #{d}" }
17
+ taskset << task
18
+
19
+ client.run(taskset)
@@ -0,0 +1,14 @@
1
+ require 'rubygems'
2
+ #require 'gearman'
3
+ require '../lib/gearman'
4
+ Gearman::Util.debug = true
5
+
6
+ servers = ['localhost:4730', 'localhost:4731']
7
+
8
+ client = Gearman::Client.new(servers)
9
+
10
+ task = Gearman::Task.new('sleep', 20, :background => true, :poll_status_interval => 1)
11
+ task.on_complete {|d| puts d } #never called
12
+ task.on_status {|d| puts "Status: #{d}"}
13
+
14
+ client.run(task)
@@ -0,0 +1,16 @@
1
+ require 'rubygems'
2
+ #require 'gearman'
3
+ require '../lib/gearman'
4
+ Gearman::Util.debug = true
5
+
6
+ servers = ['localhost:4730']
7
+
8
+ client = Gearman::Client.new(servers)
9
+ taskset = Gearman::Taskset.new
10
+
11
+ task = Gearman::Task.new('chunked_transfer')
12
+ task.on_data {|d| puts d }
13
+ task.on_complete {|d| puts d }
14
+
15
+ taskset << task
16
+ client.run taskset
@@ -0,0 +1,16 @@
1
+ require 'rubygems'
2
+ require '../lib/gearman'
3
+
4
+ servers = ['localhost:4730']
5
+ client = Gearman::Client.new(servers)
6
+ taskset = Gearman::TaskSet.new(client)
7
+
8
+ 100000.times do |i|
9
+ task = Gearman::Task.new('echo', "hello #{i}")
10
+ task.on_complete {|d| puts d }
11
+ taskset.add_task(task)
12
+ end
13
+ taskset.wait(100)
14
+
15
+ taskset.add_task(Gearman::Task.new('quit'))
16
+ taskset.wait(100)
@@ -0,0 +1,17 @@
1
+ require 'rubygems'
2
+ require '../lib/gearman'
3
+ Gearman::Util.debug = true
4
+
5
+ servers = ['localhost:4730']
6
+
7
+ client = Gearman::Client.new(servers)
8
+
9
+ task = Gearman::Task.new('fail_with_exception', "void")
10
+ task.retries = 2
11
+ task.on_complete {|d| puts d }
12
+ task.on_exception {|ex| puts "This should never be called" }
13
+ task.on_warning {|warning| puts "WARNING: #{warning}" }
14
+ task.on_retry { puts "PRE-RETRY HOOK: retry no. #{task.retries_done}" }
15
+ task.on_fail { puts "TASK FAILED, GIVING UP" }
16
+
17
+ client.run task
@@ -0,0 +1,15 @@
1
+ require 'rubygems'
2
+ #require 'gearman'
3
+ require '../lib/gearman'
4
+ Gearman::Util.debug = true
5
+
6
+ servers = ['localhost:4730', 'localhost:4731']
7
+
8
+ ability_name_with_prefix = Gearman::Util.ability_name_with_prefix("test","sleep")
9
+
10
+ client = Gearman::Client.new(servers)
11
+
12
+ task = Gearman::Task.new(ability_name_with_prefix, 20)
13
+ task.on_complete {|d| puts d }
14
+
15
+ client.run task
@@ -0,0 +1,23 @@
1
+ require 'rubygems'
2
+ require "ruby-debug"
3
+ require '../lib/gearman'
4
+
5
+ Gearman::Util.debug = true
6
+
7
+ servers = ['localhost:4730', 'localhost:4731']
8
+ client = Gearman::Client.new(servers)
9
+
10
+ taskset = Gearman::Taskset.new
11
+
12
+ task = Gearman::Task.new('sleep', 2)
13
+ task.on_status {|numerator, denominator| puts "TASK 1: Completed #{numerator} of #{denominator}"}
14
+ task.on_complete {|d| puts "TASK 1: #{d}" }
15
+ taskset << task
16
+
17
+ task = Gearman::Task.new('sleep', 15, :poll_status_interval => 2, :uuid => nil)
18
+ task.on_status {|numerator, denominator| puts "TASK 2: Completed #{numerator} of #{denominator}"}
19
+ task.on_data {|data| puts "TASK 2 DATA: #{data}" }
20
+ task.on_complete {|d| puts "TASK 2: #{d}" }
21
+ taskset << task
22
+
23
+ client.run(taskset)