Author: bicou
Date: 2010-05-16 23:12:31 +0200 (Sun, 16 May 2010)
New Revision: 29485

Modified:
   plugins/sfGearmanPlugin/trunk/README
   plugins/sfGearmanPlugin/trunk/config/gearman.yml
Log:
[sfGearmanPlugin] doc

Modified: plugins/sfGearmanPlugin/trunk/README
===================================================================
--- plugins/sfGearmanPlugin/trunk/README        2010-05-16 21:12:20 UTC (rev 
29484)
+++ plugins/sfGearmanPlugin/trunk/README        2010-05-16 21:12:31 UTC (rev 
29485)
@@ -0,0 +1,407 @@
+sfGearmanPlugin
+===============
+
+The sfGearman plugin provides a symfony wrapper to gearman pecl module.
+
+Features:
+
+* configuration of servers and workers in a yaml config file
+* run workers in a symfony task
+* auto (un)serialization of job workloads/results
+* a simple message queue manager
+* a Doctrine Template to trigger tasks on record/table events
+* a worker for gearman jobs based on MySQL TRIGGER (gearman UDF)
+
+
+Installation
+------------
+
+First you need to install the gearman pecl module, version 0.6.0 minimum.
+
+Then you can install this plugin the usual way (RTFM), or if you want to work 
with the trunk:
+
+    $ cd plugins
+    $ svn co http://svn.symfony-project.com/plugins/sfGearmanPlugin/trunk/ 
sfGearmanPlugin
+
+Then activate the plugin in the `config/ProjectConfiguration.class.php` file.
+
+
+Configuration
+-------------
+
+By default, there is a connection named "default" which targets a local 
gearman server.
+
+Edit or create `config/gearman.yml` to suit your gearman server installation :
+
+    [yml]
+    all:
+      server:
+        default:
+          host: 192.168.0.1
+          port: 4730
+
+You can also use host:port based notation :
+
+    [yml]
+    all:
+      server:
+        default: 127.0.0.1:4730
+
+If you have more than one gearman job server, you can list them and mix 
notations this way :
+
+    [yml]
+    all:
+      server:
+        default:
+          - 192.168.0.1:4730
+          - { host: 192.168.0.2, port: 4730 }
+
+
+Create a worker
+---------------
+
+Edit `config/gearman.yml` to define worker functions and callbacks, grouped by 
a key name :
+
+    [yml]
+    all:
+      worker:
+        example1:
+          reverse: [Worker1, reverse]
+
+We defined a worker named "example1" registering gearman function "reverse" 
with `Worker1::reverse()` callback.
+
+You can register multiple function for one worker :
+
+    [yml]
+    all:
+      worker:
+        example1:
+          reverse: [Worker1, reverse]
+          hash: [Worker1, hash]
+
+
+Next implement you callback:
+
+    [php]
+    /**
+     * Gearman worker example1
+     */
+    class Worker1
+    {
+      /**
+       * reverse work handler
+       *
+       * @param GearmanJob $job Gearman job
+       * @return string         Result sent to client
+       */
+      public static function reverse($job)
+      {
+        return strrev($job->workload());
+      }
+    }
+
+
+To understand `GearmanJob` and `$job->workload()`, read [gearman php module 
documentation](http://php.net/gearman).
+
+To start your worker, use the symfony task `gearman:worker` with 
`--config=example1` :
+
+    $ symfony gearman:worker --config=example1
+
+
+This command starts a gearman worker, and exit after processing 100 jobs or 
waiting 20 secs for a job.
+You can tweak this with `--count=100` and `--timeout=20` options (use 0 for 
count and a negative value for timeout to never end worker).
+
+If you want your worker to restart automatically, use 
[supervisord](http://supervisord.org/) or 
[daemon-tools](http://cr.yp.to/daemontools.html), or any process control tool.
+
+To see what happens, use `--verbose` option :
+
+    $ symfony gearman:worker --config=example1 --verbose
+
+
+See all options with :
+
+    $ symfony help gearman:worker
+
+
+If you want to trace jobs and workloads as well, you need to notify symfony 
that a job is processed :
+
+    [php]
+    /**
+     * Gearman worker example1
+     */
+    class Worker1
+    {
+      /**
+       * reverse work handler
+       *
+       * @param GearmanJob      $job    Gearman job
+       * @param sfGearmanWorker $worker sfGearmanWorker
+       * @return string                 Result sent to client
+       */
+      public static function reverse($job, $worker)
+      {
+        // sfGearman worker is passed as the 2nd parameter of the method
+        // notifyEventJob() displays a trace in symfony task output
+        // if --verbose is set, workload is logged too
+        $worker->notifyEventJob($job);
+
+        return strrev($job->workload());
+      }
+    }
+
+
+Gearman protocol only handles strings in workloads, if you need to return an 
array or object as a worker result, use `sfGearman::serialize` :
+
+    [php]
+    /**
+     * Gearman worker example1
+     */
+    class Worker1
+    {
+      /**
+       * reverse work handler
+       *
+       * @param GearmanJob      $job    Gearman job
+       * @param sfGearmanWorker $worker sfGearmanWorker
+       * @return string                 Result sent to client
+       */
+      public static function hash($job, $worker)
+      {
+        $worker->notifyEventJob($job);
+
+        $workload = $job->workload();
+
+        $result = array(md5($workload), sha1($workload));
+
+        return sfGearman::serialize($result);
+      }
+    }
+
+The sfGearmanClient will automatically unserialize the result if needed.
+
+
+Use a client
+------------
+
+To create a gearman client, use `sfGearmanClient::getInstance` :
+
+    [php]
+    // client connecting to default server
+    $client = sfGearmanClient::getInstance();
+
+    // client connecting to a different server defined in gearman.yml
+    $client = sfGearmanClient::getInstance('local');
+
+
+You have 2 shorthands methods to send a job to gearman server : 
`task('function' [, 'workload'])` and `background('function' [, 'workload'])`, 
example:
+
+    [php]
+    // this blocks until a worker do the job and return result
+    $result = sfGearmanClient::getInstance()->task('reverse', 'Hello!');
+    // $result == '!olleH'
+
+    // this sends an asynchronous job to gearman server, the return value is a 
gearman handle
+    $handle = sfGearmanClient::getInstance()->background('async');
+    // $handle == 'H:host:id'
+
+
+If you need priorities for your jobs, pass as 3rd parameter the level you want 
:
+
+    [php]
+    // this job has high priority
+    $result = sfGearmanClient::getInstance()->task('reverse', 'Hello!', 
sfGearman::HIGH);
+
+    // this job has low priority
+    $result = sfGearmanClient::getInstance()->task('reverse', 'Hello!', 
sfGearman::LOW);
+
+
+Message queue manager
+---------------------
+
+The plugin provides a `sfGearmanQueue` class to put and get messages in 
queues, usage :
+
+    [php]
+    // put a message in a queue named "q1"
+    sfGearmanQueue::put('q1', 'a message');
+
+    // later or elsewhere, get a message from queue
+    $message = sfGearmanQueue::get('q1');
+
+    // put a message with high priority (will be fetched first)
+    sfGearmanQueue::put('q1', 'urgent', sfGearman::HIGH);
+
+    // ::get() blocks forever until a message arrives, if you want to timeout, 
use 2nd parameter (in ms)
+    try
+    {
+      $message = sfGearmanQueue::get('q1', 10000);
+    }
+    catch(sfGearmanTimeoutException $e)
+    {
+      // waited 10 secs but no message in queue
+    }
+
+
+Internally, this sends messages as serialized workloads of "queue.%name%" jobs.
+
+
+Doctrine integration
+--------------------
+
+The sfGearmanPlugin provides a Doctrine Template which listens to 
insert/update/delete events and sends background jobs to gearman server.
+
+Add the Gearmanable template to `doctrine/schema.yml`, for example we want to 
listen to the update events of articles:
+
+    [yml]
+    Article:
+      actAs:
+        Gearmanable: {events: [update]}
+      columns:
+        title:  string(200)
+
+Update your models, then configure `gearman.yml` to create a doctrine worker :
+
+    [yml]
+    all:
+      doctrine:
+        example2:
+          Article: ~
+
+Unlike the classic worker configuration, the doctrine one is made of the model 
name as key and the list of events as value, ~ is an alias to all events 
defined in `schema.yml`.
+
+Then implement worker callback, they need to be located in the model class and 
named "trigger%Event%" (to avoid overlapping), so :
+
+    [php]
+    class Article extends BaseArticle
+    {
+      public function triggerUpdate($modified)
+      {
+        if (in_array('title', $modified))
+        {
+          // update a search index, refresh symfony cache, ...
+        }
+      }
+    }
+
+Note that the only parameter for doctrine gearman work handler is an array of 
modified properties.
+
+Then launches a doctrine worker with symfony `gearman:worker-doctrine` task :
+
+    $ symfony gearman:worker-doctrine --config=example2
+
+You could omit the `--config=` option, this loads all doctrine models and 
register all events defined in `schema.yml`, but this merge all jobs in same 
workers.
+
+
+Then save as usual your records :
+
+    [php]
+    $article = Doctrine_Core::getTable('Article')->find($id);
+    $article->title = 'new title';
+    $article->save();
+
+This is what happens :
+
+1. The `->save()` sends a background job to gearman server containing 
serialized record
+2. The gearman server sends the job to the worker
+3. The worker unserializes the record and call the trigger
+
+Note:
+
+The object transits through gearman server, and the trigger is called in 
another php process.
+
+So when the record arrives to symfony worker task, it may not exists anymore 
in the database, or may be out-of-date.
+
+If you want a fresh copy, use doctrine `refresh()` in the handler :
+
+    [php]
+    class Article extends BaseArticle
+    {
+      public function triggerUpdate($modified)
+      {
+        try { $this->refresh(); }
+        catch (Doctrine_Record_Exception $e) { return; }
+
+        // here the record is reloaded from db
+      }
+    }
+
+Don't use the previous snippet in `triggerDelete()` because what you have in 
the worker task is only a ghost of your record.
+
+
+To access the gearman job object, use the method `->getGearmanJob()` :
+
+    [php]
+    class Article extends BaseArticle
+    {
+      public function triggerUpdate($modified)
+      {
+        $job = $this->getGearmanJob();
+        $job->sendFail();
+      }
+    }
+
+
+Custom doctrine jobs
+--------------------
+
+You can have custom jobs for Doctrine records, register them in `gearman.yml`:
+
+    [yml]
+    all:
+      doctrine:
+        example2:
+          Article: [publish, ~]
+
+Implement them in your model class:
+
+    [php]
+    class Article extends BaseArticle
+    {
+      public function publish($tweet, $ping)
+      {
+        try { $this->refresh(); }
+        catch (Doctrine_Record_Exception $e) { return; }
+
+        // heavy code to publish your article
+      }
+    }
+
+Reload your worker task to work this new function.
+
+Then launch tasks with `->task('function' [, ...])` for synchronous jobs, or 
`->taskBackground('function' [, ...])` for asynchronous ones.
+
+    [php]
+    $article = Doctrine_Core::getTable('Article')->find($id);
+    $article->taskBackground('publish', false, true);
+    // this returns immediately and let the symfony task do the heavy code for 
->publish(false, true)
+
+
+Doctrine table jobs
+-------------------
+
+You can have function for Doctrine table, example :
+
+    [yml]
+    all:
+      doctrine:
+        example2:
+          Article: [buildFeed, publish, ~]
+
+
+Define the job handler in the table class :
+
+    [php]
+    class TestArticleTable extends Doctrine_Table
+    {
+      public function buildFeed()
+      {
+        // build the feeds
+      }
+    }
+
+
+Call `task()` or `taskBackground()` on the table :
+
+    [php]
+    Doctrine_Core::getTable('Article')->taskBackground('buildFeed');
+
+

Modified: plugins/sfGearmanPlugin/trunk/config/gearman.yml
===================================================================
--- plugins/sfGearmanPlugin/trunk/config/gearman.yml    2010-05-16 21:12:20 UTC 
(rev 29484)
+++ plugins/sfGearmanPlugin/trunk/config/gearman.yml    2010-05-16 21:12:31 UTC 
(rev 29485)
@@ -1,3 +1,5 @@
+# default server configuration
 all:
   server:
-    default: ~
+    default: ~ # = GEARMAN_DEFAULT_TCP_HOST:GEARMAN_DEFAULT_TCP_PORT
+

-- 
You received this message because you are subscribed to the Google Groups 
"symfony SVN" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/symfony-svn?hl=en.

Reply via email to