evented-gearman-ruby 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. data/.gitignore +1 -0
  2. data/HOWTO +146 -0
  3. data/LICENSE +20 -0
  4. data/README +4 -0
  5. data/Rakefile +41 -0
  6. data/TODO +8 -0
  7. data/VERSION.yml +4 -0
  8. data/evented-gearman-ruby.gemspec +110 -0
  9. data/examples/calculus_client.rb +41 -0
  10. data/examples/calculus_worker.rb +42 -0
  11. data/examples/client.rb +19 -0
  12. data/examples/client_background.rb +14 -0
  13. data/examples/client_data.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_exception.rb +14 -0
  25. data/examples/worker_prefix.rb +25 -0
  26. data/lib/gearman.rb +29 -0
  27. data/lib/gearman/client.rb +80 -0
  28. data/lib/gearman/evented/client.rb +99 -0
  29. data/lib/gearman/evented/reactor.rb +86 -0
  30. data/lib/gearman/evented/worker.rb +118 -0
  31. data/lib/gearman/job.rb +38 -0
  32. data/lib/gearman/protocol.rb +110 -0
  33. data/lib/gearman/server.rb +94 -0
  34. data/lib/gearman/task.rb +99 -0
  35. data/lib/gearman/taskset.rb +11 -0
  36. data/lib/gearman/util.rb +52 -0
  37. data/lib/gearman/worker.rb +39 -0
  38. data/test/basic_integration_test.rb +121 -0
  39. data/test/crash_test.rb +69 -0
  40. data/test/job_test.rb +30 -0
  41. data/test/protocol_test.rb +132 -0
  42. data/test/test_helper.rb +31 -0
  43. data/test/util_test.rb +12 -0
  44. data/test/worker_test.rb +45 -0
  45. metadata +149 -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 Kim Altintop
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,4 @@
1
+ evented-gearman-ruby
2
+ ===============
3
+
4
+ eventmachine-based library for the Gearman distributed job system
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 = "evented-gearman-ruby"
10
+ s.summary = "eventmachine-based library for the Gearman distributed job system"
11
+ s.email = "kim.altintop@gmail.com"
12
+ s.homepage = "http://github.com/kim/evented-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: 1
4
+ :minor: 0
@@ -0,0 +1,110 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{evented-gearman-ruby}
8
+ s.version = "1.0.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Kim Altintop"]
12
+ s.date = %q{2010-07-19}
13
+ s.description = %q{Library for the Gearman distributed job system}
14
+ s.email = %q{kim.altintop@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README",
18
+ "TODO"
19
+ ]
20
+ s.files = [
21
+ ".gitignore",
22
+ "HOWTO",
23
+ "LICENSE",
24
+ "README",
25
+ "Rakefile",
26
+ "TODO",
27
+ "VERSION.yml",
28
+ "evented-gearman-ruby.gemspec",
29
+ "examples/calculus_client.rb",
30
+ "examples/calculus_worker.rb",
31
+ "examples/client.rb",
32
+ "examples/client_background.rb",
33
+ "examples/client_data.rb",
34
+ "examples/client_exception.rb",
35
+ "examples/client_prefix.rb",
36
+ "examples/evented_client.rb",
37
+ "examples/evented_worker.rb",
38
+ "examples/gearman_environment.sh",
39
+ "examples/scale_image.rb",
40
+ "examples/scale_image_worker.rb",
41
+ "examples/server.rb",
42
+ "examples/worker.rb",
43
+ "examples/worker_data.rb",
44
+ "examples/worker_exception.rb",
45
+ "examples/worker_prefix.rb",
46
+ "lib/gearman.rb",
47
+ "lib/gearman/client.rb",
48
+ "lib/gearman/evented/client.rb",
49
+ "lib/gearman/evented/reactor.rb",
50
+ "lib/gearman/evented/worker.rb",
51
+ "lib/gearman/job.rb",
52
+ "lib/gearman/protocol.rb",
53
+ "lib/gearman/server.rb",
54
+ "lib/gearman/task.rb",
55
+ "lib/gearman/taskset.rb",
56
+ "lib/gearman/util.rb",
57
+ "lib/gearman/worker.rb",
58
+ "test/basic_integration_test.rb",
59
+ "test/crash_test.rb",
60
+ "test/job_test.rb",
61
+ "test/protocol_test.rb",
62
+ "test/test_helper.rb",
63
+ "test/util_test.rb",
64
+ "test/worker_test.rb"
65
+ ]
66
+ s.homepage = %q{http://github.com/kim/evented-gearman-ruby}
67
+ s.rdoc_options = ["--charset=UTF-8"]
68
+ s.require_paths = ["lib"]
69
+ s.rubygems_version = %q{1.3.7}
70
+ s.summary = %q{eventmachine-based library for the Gearman distributed job system}
71
+ s.test_files = [
72
+ "test/basic_integration_test.rb",
73
+ "test/crash_test.rb",
74
+ "test/job_test.rb",
75
+ "test/protocol_test.rb",
76
+ "test/test_helper.rb",
77
+ "test/util_test.rb",
78
+ "test/worker_test.rb",
79
+ "examples/calculus_client.rb",
80
+ "examples/calculus_worker.rb",
81
+ "examples/client.rb",
82
+ "examples/client_background.rb",
83
+ "examples/client_data.rb",
84
+ "examples/client_exception.rb",
85
+ "examples/client_prefix.rb",
86
+ "examples/evented_client.rb",
87
+ "examples/evented_worker.rb",
88
+ "examples/scale_image.rb",
89
+ "examples/scale_image_worker.rb",
90
+ "examples/server.rb",
91
+ "examples/worker.rb",
92
+ "examples/worker_data.rb",
93
+ "examples/worker_exception.rb",
94
+ "examples/worker_prefix.rb"
95
+ ]
96
+
97
+ if s.respond_to? :specification_version then
98
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
99
+ s.specification_version = 3
100
+
101
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
102
+ s.add_runtime_dependency(%q<eventmachine>, [">= 0.12.8"])
103
+ else
104
+ s.add_dependency(%q<eventmachine>, [">= 0.12.8"])
105
+ end
106
+ else
107
+ s.add_dependency(%q<eventmachine>, [">= 0.12.8"])
108
+ end
109
+ end
110
+
@@ -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)