xing-gearman-ruby 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,455 @@
1
+ <?php
2
+
3
+ /**
4
+ * Interface for Danga's Gearman job scheduling system
5
+ *
6
+ * PHP version 5.1.0+
7
+ *
8
+ * LICENSE: This source file is subject to the New BSD license that is
9
+ * available through the world-wide-web at the following URI:
10
+ * http://www.opensource.org/licenses/bsd-license.php. If you did not receive
11
+ * a copy of the New BSD License and are unable to obtain it through the web,
12
+ * please send a note to license@php.net so we can mail you a copy immediately.
13
+ *
14
+ * @category Net
15
+ * @package Net_Gearman
16
+ * @author Joe Stump <joe@joestump.net>
17
+ * @copyright 2007-2008 Digg.com, Inc.
18
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
19
+ * @version CVS: $Id$
20
+ * @link http://pear.php.net/package/Net_Gearman
21
+ * @link http://www.danga.com/gearman/
22
+ */
23
+
24
+ require_once 'Net/Gearman/Connection.php';
25
+ require_once 'Net/Gearman/Job.php';
26
+
27
+ /**
28
+ * Gearman worker class
29
+ *
30
+ * Run an instance of a worker to listen for jobs. It then manages the running
31
+ * of jobs, etc.
32
+ *
33
+ * <code>
34
+ * <?php
35
+ *
36
+ * $servers = array(
37
+ * '127.0.0.1:7003',
38
+ * '127.0.0.1:7004'
39
+ * );
40
+ *
41
+ * $abilities = array('HelloWorld', 'Foo', 'Bar');
42
+ *
43
+ * try {
44
+ * $worker = new Net_Gearman_Worker($servers);
45
+ * foreach ($abilities as $ability) {
46
+ * $worker->addAbility('HelloWorld');
47
+ * }
48
+ * $worker->beginWork();
49
+ * } catch (Net_Gearman_Exception $e) {
50
+ * echo $e->getMessage() . "\n";
51
+ * exit;
52
+ * }
53
+ *
54
+ * ?>
55
+ * </code>
56
+ *
57
+ * @category Net
58
+ * @package Net_Gearman
59
+ * @author Joe Stump <joe@joestump.net>
60
+ * @copyright 2007-2008 Digg.com, Inc.
61
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
62
+ * @link http://www.danga.com/gearman/
63
+ * @see Net_Gearman_Job, Net_Gearman_Connection
64
+ */
65
+ class Net_Gearman_Worker
66
+ {
67
+ /**
68
+ * Pool of connections to Gearman servers
69
+ *
70
+ * @var array $conn
71
+ */
72
+ protected $conn = array();
73
+
74
+ /**
75
+ * Pool of retry connections
76
+ *
77
+ * @var array $conn
78
+ */
79
+ protected $retryConn = array();
80
+
81
+ /**
82
+ * Pool of worker abilities
83
+ *
84
+ * @var array $conn
85
+ */
86
+ protected $abilities = array();
87
+
88
+
89
+ /**
90
+ * Callbacks registered for this worker
91
+ *
92
+ * @var array $callback
93
+ * @see Net_Gearman_Worker::JOB_START
94
+ * @see Net_Gearman_Worker::JOB_COMPLETE
95
+ * @see Net_Gearman_Worker::JOB_FAIL
96
+ */
97
+ protected $callback = array(
98
+ self::JOB_START => array(),
99
+ self::JOB_COMPLETE => array(),
100
+ self::JOB_FAIL => array()
101
+ );
102
+
103
+ /**
104
+ * Unique id for this worker
105
+ *
106
+ * @var string $id
107
+ */
108
+ protected $id = "";
109
+
110
+
111
+ /**
112
+ * Callback types
113
+ *
114
+ * @const integer JOB_START Ran when a job is started
115
+ * @const integer JOB_COMPLETE Ran when a job is finished
116
+ * @const integer JOB_FAIL Ran when a job fails
117
+ */
118
+ const JOB_START = 1;
119
+ const JOB_COMPLETE = 2;
120
+ const JOB_FAIL = 3;
121
+
122
+ /**
123
+ * Constructor
124
+ *
125
+ * @param array $servers List of servers to connect to
126
+ * @param string $id Optional unique id for this worker
127
+ *
128
+ * @return void
129
+ * @throws Net_Gearman_Exception
130
+ * @see Net_Gearman_Connection
131
+ */
132
+ public function __construct($servers, $id = "")
133
+ {
134
+ if (!is_array($servers) && strlen($servers)) {
135
+ $servers = array($servers);
136
+ } elseif (is_array($servers) && !count($servers)) {
137
+ throw new Net_Gearman_Exception('Invalid servers specified');
138
+ }
139
+
140
+ if(empty($id)){
141
+ $id = "pid_".getmypid()."_".uniqid();
142
+ }
143
+
144
+ $this->id = $id;
145
+
146
+ foreach ($servers as $s) {
147
+ try {
148
+ $conn = Net_Gearman_Connection::connect($s);
149
+
150
+ Net_Gearman_Connection::send($conn, "set_client_id", array("client_id" => $this->id));
151
+
152
+ $this->conn[$s] = $conn;
153
+
154
+ } catch (Net_Gearman_Exception $e) {
155
+
156
+ $this->retryConn[$s] = time();
157
+ }
158
+ }
159
+
160
+ if (empty($this->conn)) {
161
+ throw new Net_Gearman_Exception(
162
+ "Couldn't connect to any available servers"
163
+ );
164
+ }
165
+ }
166
+
167
+ /**
168
+ * Announce an ability to the job server
169
+ *
170
+ * @param string $ability Name of functcion/ability
171
+ * @param integer $timeout How long to give this job
172
+ *
173
+ * @return void
174
+ * @see Net_Gearman_Connection::send()
175
+ */
176
+ public function addAbility($ability, $timeout = null)
177
+ {
178
+ $call = 'can_do';
179
+ $params = array('func' => $ability);
180
+ if (is_int($timeout) && $timeout > 0) {
181
+ $params['timeout'] = $timeout;
182
+ $call = 'can_do_timeout';
183
+ }
184
+
185
+ $this->abilities[$ability] = $timeout;
186
+
187
+ foreach ($this->conn as $conn) {
188
+ Net_Gearman_Connection::send($conn, $call, $params);
189
+ }
190
+ }
191
+
192
+ /**
193
+ * Begin working
194
+ *
195
+ * This starts the worker on its journey of actually working. The first
196
+ * argument is a PHP callback to a function that can be used to monitor
197
+ * the worker. If no callback is provided then the worker works until it
198
+ * is killed. The monitor is passed two arguments; whether or not the
199
+ * worker is idle and when the last job was ran.
200
+ *
201
+ * @param callback $monitor Function to monitor work
202
+ *
203
+ * @return void
204
+ * @see Net_Gearman_Connection::send(), Net_Gearman_Connection::connect()
205
+ * @see Net_Gearman_Worker::doWork(), Net_Gearman_Worker::addAbility()
206
+ */
207
+ public function beginWork($monitor = null)
208
+ {
209
+ if (!is_callable($monitor)) {
210
+ $monitor = array($this, 'stopWork');
211
+ }
212
+
213
+ $write = null;
214
+ $except = null;
215
+ $working = true;
216
+ $lastJob = time();
217
+ $retryTime = 5;
218
+
219
+ while ($working) {
220
+ $sleep = true;
221
+ $currentTime = time();
222
+
223
+ foreach ($this->conn as $server => $socket) {
224
+ try {
225
+ $worked = $this->doWork($socket);
226
+ } catch (Net_Gearman_Exception $e) {
227
+ unset($this->conn[$server]);
228
+ $this->retryConn[$server] = $currentTime;
229
+ }
230
+ if ($worked) {
231
+ $lastJob = time();
232
+ $sleep = false;
233
+ }
234
+ }
235
+
236
+ $idle = false;
237
+ if ($sleep && count($this->conn)) {
238
+ foreach ($this->conn as $socket) {
239
+ Net_Gearman_Connection::send($socket, 'pre_sleep');
240
+ }
241
+
242
+ $read = $this->conn;
243
+ socket_select($read, $write, $except, 60);
244
+ $idle = (count($read) == 0);
245
+ }
246
+
247
+ $retryChange = false;
248
+ foreach ($this->retryConn as $s => $lastTry) {
249
+ if (($lastTry + $retryTime) < $currentTime) {
250
+ try {
251
+ $conn = Net_Gearman_Connection::connect($s);
252
+ $this->conn[$s] = $conn;
253
+ $retryChange = true;
254
+ unset($this->retryConn[$s]);
255
+ Net_Gearman_Connection::send($conn, "set_client_id", array("client_id" => $this->id));
256
+ } catch (Net_Gearman_Exception $e) {
257
+ $this->retryConn[$s] = $currentTime;
258
+ }
259
+ }
260
+ }
261
+
262
+ if (count($this->conn) == 0) {
263
+ // sleep to avoid wasted cpu cycles if no connections to block on using socket_select
264
+ sleep(1);
265
+ }
266
+
267
+ if ($retryChange === true) {
268
+ // broadcast all abilities to all servers
269
+ foreach ($this->abilities as $ability => $timeout) {
270
+ $this->addAbility($ability, $timeout);
271
+ }
272
+ }
273
+
274
+ if (call_user_func($monitor, $idle, $lastJob) == true) {
275
+ $working = false;
276
+ }
277
+ }
278
+ }
279
+
280
+ /**
281
+ * Listen on the socket for work
282
+ *
283
+ * Sends the 'grab_job' command and then listens for either the 'noop' or
284
+ * the 'no_job' command to come back. If the 'job_assign' comes down the
285
+ * pipe then we run that job.
286
+ *
287
+ * @param resource $socket The socket to work on
288
+ *
289
+ * @return boolean Returns true if work was done, false if not
290
+ * @throws Net_Gearman_Exception
291
+ * @see Net_Gearman_Connection::send()
292
+ */
293
+ protected function doWork($socket)
294
+ {
295
+ Net_Gearman_Connection::send($socket, 'grab_job');
296
+
297
+ $resp = array('function' => 'noop');
298
+ while (count($resp) && $resp['function'] == 'noop') {
299
+ $resp = Net_Gearman_Connection::blockingRead($socket);
300
+ }
301
+
302
+ if (in_array($resp['function'], array('noop', 'no_job'))) {
303
+ return false;
304
+ }
305
+
306
+ if ($resp['function'] != 'job_assign') {
307
+ throw new Net_Gearman_Exception('Holy Cow! What are you doing?!');
308
+ }
309
+
310
+ $name = $resp['data']['func'];
311
+ $handle = $resp['data']['handle'];
312
+ $arg = array();
313
+
314
+ if (isset($resp['data']['arg']) &&
315
+ Net_Gearman_Connection::stringLength($resp['data']['arg'])) {
316
+ $arg = json_decode($resp['data']['arg'], true);
317
+ if($arg === null){
318
+ $arg = $resp['data']['arg'];
319
+ }
320
+ }
321
+
322
+ $job = Net_Gearman_Job::factory($name, $socket, $handle);
323
+ try {
324
+ $this->start($handle, $name, $arg);
325
+ $res = $job->run($arg);
326
+ if (!is_array($res)) {
327
+ $res = array('result' => $res);
328
+ }
329
+
330
+ $job->complete($res);
331
+ $this->complete($handle, $name, $res);
332
+ } catch (Net_Gearman_Job_Exception $e) {
333
+ $job->fail();
334
+ $this->fail($handle, $name, $e);
335
+ }
336
+
337
+ // Force the job's destructor to run
338
+ $job = null;
339
+
340
+ return true;
341
+ }
342
+
343
+ /**
344
+ * Attach a callback
345
+ *
346
+ * @param callback $callback A valid PHP callback
347
+ * @param integer $type Type of callback
348
+ *
349
+ * @return void
350
+ * @throws Net_Gearman_Exception
351
+ */
352
+ public function attachCallback($callback, $type = self::JOB_COMPLETE)
353
+ {
354
+ if (!is_callable($callback)) {
355
+ throw new Net_Gearman_Exception('Invalid callback specified');
356
+ }
357
+
358
+ $this->callback[$type][] = $callback;
359
+ }
360
+
361
+ /**
362
+ * Run the job start callbacks
363
+ *
364
+ * @param string $handle The job's Gearman handle
365
+ * @param string $job The name of the job
366
+ * @param mixed $args The job's argument list
367
+ *
368
+ * @return void
369
+ */
370
+ protected function start($handle, $job, $args)
371
+ {
372
+ if (!count($this->callback[self::JOB_START])) {
373
+ return; // No callbacks to run
374
+ }
375
+
376
+ foreach ($this->callback[self::JOB_START] as $callback) {
377
+ call_user_func($callback, $handle, $job, $args);
378
+ }
379
+ }
380
+
381
+ /**
382
+ * Run the complete callbacks
383
+ *
384
+ * @param string $handle The job's Gearman handle
385
+ * @param string $job The name of the job
386
+ * @param array $result The job's returned result
387
+ *
388
+ * @return void
389
+ */
390
+ protected function complete($handle, $job, array $result)
391
+ {
392
+ if (!count($this->callback[self::JOB_COMPLETE])) {
393
+ return; // No callbacks to run
394
+ }
395
+
396
+ foreach ($this->callback[self::JOB_COMPLETE] as $callback) {
397
+ call_user_func($callback, $handle, $job, $result);
398
+ }
399
+ }
400
+
401
+ /**
402
+ * Run the fail callbacks
403
+ *
404
+ * @param string $handle The job's Gearman handle
405
+ * @param string $job The name of the job
406
+ * @param object $error The exception thrown
407
+ *
408
+ * @return void
409
+ */
410
+ protected function fail($handle, $job, PEAR_Exception $error)
411
+ {
412
+ if (!count($this->callback[self::JOB_FAIL])) {
413
+ return; // No callbacks to run
414
+ }
415
+
416
+ foreach ($this->callback[self::JOB_FAIL] as $callback) {
417
+ call_user_func($callback, $handle, $job, $error);
418
+ }
419
+ }
420
+
421
+ /**
422
+ * Stop working
423
+ *
424
+ * @return void
425
+ */
426
+ public function endWork()
427
+ {
428
+ foreach ($this->conn as $conn) {
429
+ Net_Gearman_Connection::close($conn);
430
+ }
431
+ }
432
+
433
+ /**
434
+ * Destructor
435
+ *
436
+ * @return void
437
+ * @see Net_Gearman_Worker::stop()
438
+ */
439
+ public function __destruct()
440
+ {
441
+ $this->endWork();
442
+ }
443
+
444
+ /**
445
+ * Should we stop work?
446
+ *
447
+ * @return boolean
448
+ */
449
+ public function stopWork()
450
+ {
451
+ return false;
452
+ }
453
+ }
454
+
455
+ ?>
@@ -0,0 +1,23 @@
1
+ <?php
2
+
3
+ require_once 'Net/Gearman/Client.php';
4
+
5
+ $set = new Net_Gearman_Set();
6
+
7
+ function result($func, $handle, $result) {
8
+ var_dump($func);
9
+ var_dump($handle);
10
+ var_dump($result);
11
+ }
12
+
13
+ $task = new Net_Gearman_Task('Sleep', array(
14
+ 'seconds' => 20
15
+ ));
16
+
17
+ $task->attachCallback('result');
18
+ $set->addTask($task);
19
+
20
+ $client = new Net_Gearman_Client(array('localhost:4730', 'localhost:4731'));
21
+ $client->runSet($set);
22
+
23
+ ?>
@@ -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
+ client = Gearman::Client.new(servers)
9
+ taskset = Gearman::TaskSet.new(client)
10
+
11
+ task = Gearman::Task.new('sleep', 20)
12
+ task.on_complete {|d| puts d }
13
+
14
+ taskset.add_task(task)
15
+ taskset.wait(100)
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/ruby
2
+
3
+ $: << '../lib'
4
+ require 'gearman'
5
+ require 'optparse'
6
+
7
+ Gearman::Util.debug = true
8
+ servers = 'localhost:7003'
9
+ format = 'PNG'
10
+ width, height = 100, 100
11
+
12
+ opts = OptionParser.new
13
+ opts.banner = "Usage: #{$0} [options] <input> <output>"
14
+ opts.on('-f FORMAT', '--format', 'Scaled image format') { format }
15
+ opts.on('-h HEIGHT', '--height', 'Scaled image height') { height }
16
+ opts.on('-s SERVERS', '--servers',
17
+ 'Servers, comma-separated host:port') { servers }
18
+ opts.on('-w WIDTH', '--width', 'Scaled image width') { width }
19
+ opts.parse!
20
+
21
+ if ARGV.size != 2
22
+ $stderr.puts opts.banner
23
+ exit 1
24
+ end
25
+
26
+ client = Gearman::Client.new(servers.split(','), 'example')
27
+ taskset = Gearman::TaskSet.new(client)
28
+ arg = [width, height, format, File.read(ARGV[0])].join("\0")
29
+ task = Gearman::Task.new('scale_image', arg)
30
+ task.on_complete {|d| File.new(ARGV[1],'w').write(d) }
31
+ taskset.add_task(task)
32
+ taskset.wait(10)
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/ruby
2
+
3
+ $: << '../lib'
4
+ require 'gearman'
5
+ require 'optparse'
6
+ require 'RMagick'
7
+
8
+ Gearman::Util.debug = true
9
+ servers = 'localhost:7003'
10
+
11
+ opts = OptionParser.new
12
+ opts.banner = "Usage: #{$0} [options]"
13
+ opts.on('-s SERVERS', '--servers',
14
+ 'Job servers, comma-separated host:port') { servers }
15
+ opts.parse!
16
+
17
+ worker = Gearman::Worker.new(servers.split(','), 'example')
18
+
19
+ worker.add_ability('scale_image') do |data,job|
20
+ width, height, format, data = data.split("\0", 4)
21
+ width = width.to_f
22
+ height = height.to_f
23
+ image = Magick::Image.from_blob(data)[0]
24
+ orig_ratio = image.columns.to_f / image.rows
25
+ new_ratio = width / height
26
+ w = new_ratio < orig_ratio ? width : orig_ratio / new_ratio * width
27
+ h = new_ratio > orig_ratio ? height : new_ratio / orig_ratio * height
28
+ puts "Got #{image.inspect}; resizing to #{w}x#{h} #{format}"
29
+ image.resize!(w, h)
30
+ image.format = format
31
+ image.to_blob
32
+ end
33
+
34
+ loop { worker.work }
@@ -0,0 +1,13 @@
1
+ require 'rubygems'
2
+ require 'gearman'
3
+ require 'gearman/server'
4
+ require 'pp'
5
+
6
+ Gearman::Util.debug = true
7
+ w = Gearman::Server.new('localhost:4730')
8
+
9
+ loop {
10
+ pp "Status: ", w.status
11
+ pp "Workers: ", w.workers
12
+ sleep 5
13
+ }
@@ -0,0 +1,15 @@
1
+ <?php
2
+ error_reporting(E_ALL & ~E_NOTICE);
3
+
4
+ require_once 'Net/Gearman/Worker.php';
5
+
6
+ try {
7
+ $worker = new Net_Gearman_Worker(array('localhost:4730'));
8
+ $worker->addAbility('Sleep');
9
+ $worker->beginWork();
10
+ } catch (Net_Gearman_Exception $e) {
11
+ echo $e->getMessage() . "\n";
12
+ exit;
13
+ }
14
+
15
+ ?>
@@ -0,0 +1,23 @@
1
+ require 'rubygems'
2
+ #require 'gearman'
3
+ require '../lib/gearman'
4
+
5
+ Gearman::Util.debug = true
6
+
7
+ servers = ['localhost:4730', 'localhost:4731']
8
+ w = Gearman::Worker.new(servers)
9
+
10
+ # Add a handler for a "sleep" function that takes a single argument, the
11
+ # number of seconds to sleep before reporting success.
12
+ w.add_ability('sleep') do |data,job|
13
+ seconds = data
14
+ (1..seconds.to_i).each do |i|
15
+ sleep 1
16
+ print i
17
+ # Report our progress to the job server every second.
18
+ job.report_status(i, seconds)
19
+ end
20
+ # Report success.
21
+ true
22
+ end
23
+ loop { w.work }
@@ -0,0 +1,81 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{gearman-ruby}
5
+ s.version = "1.0.0"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Daniel Erat", "Ladislav Martincik"]
9
+ s.date = %q{2009-06-25}
10
+ s.description = %q{Library for the Gearman distributed job system}
11
+ s.email = %q{ladislav.martincik@xing.com}
12
+ s.extra_rdoc_files = [
13
+ "LICENSE",
14
+ "README"
15
+ ]
16
+ s.files = [
17
+ ".gitignore",
18
+ "LICENSE",
19
+ "README",
20
+ "Rakefile",
21
+ "VERSION.yml",
22
+ "examples/Net/Gearman/Client.php",
23
+ "examples/Net/Gearman/Connection.php",
24
+ "examples/Net/Gearman/Exception.php",
25
+ "examples/Net/Gearman/Job.php",
26
+ "examples/Net/Gearman/Job/Common.php",
27
+ "examples/Net/Gearman/Job/Exception.php",
28
+ "examples/Net/Gearman/Job/Sleep.php",
29
+ "examples/Net/Gearman/Manager.php",
30
+ "examples/Net/Gearman/Set.php",
31
+ "examples/Net/Gearman/Task.php",
32
+ "examples/Net/Gearman/Worker.php",
33
+ "examples/client.php",
34
+ "examples/client.rb",
35
+ "examples/scale_image.rb",
36
+ "examples/scale_image_worker.rb",
37
+ "examples/server.rb",
38
+ "examples/worker.php",
39
+ "examples/worker.rb",
40
+ "gearman-ruby.gemspec",
41
+ "lib/gearman.rb",
42
+ "lib/gearman/client.rb",
43
+ "lib/gearman/server.rb",
44
+ "lib/gearman/task.rb",
45
+ "lib/gearman/taskset.rb",
46
+ "lib/gearman/testlib.rb",
47
+ "lib/gearman/util.rb",
48
+ "lib/gearman/worker.rb",
49
+ "test/client_test.rb",
50
+ "test/mock_client_test.rb",
51
+ "test/mock_worker_test.rb",
52
+ "test/worker_test.rb"
53
+ ]
54
+ s.has_rdoc = true
55
+ s.homepage = %q{http://github.com/xing/gearman-ruby}
56
+ s.rdoc_options = ["--charset=UTF-8"]
57
+ s.require_paths = ["lib"]
58
+ s.rubygems_version = %q{1.3.1}
59
+ s.summary = %q{Library for the Gearman distributed job system}
60
+ s.test_files = [
61
+ "test/client_test.rb",
62
+ "test/mock_client_test.rb",
63
+ "test/mock_worker_test.rb",
64
+ "test/worker_test.rb",
65
+ "examples/client.rb",
66
+ "examples/scale_image.rb",
67
+ "examples/scale_image_worker.rb",
68
+ "examples/server.rb",
69
+ "examples/worker.rb"
70
+ ]
71
+
72
+ if s.respond_to? :specification_version then
73
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
74
+ s.specification_version = 2
75
+
76
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
77
+ else
78
+ end
79
+ else
80
+ end
81
+ end