├── BeSimpleGearmanBundle.php ├── Command └── RunWorkerCommand.php ├── DependencyInjection ├── BeSimpleGearmanExtension.php └── Configuration.php ├── Gearman ├── Client.php ├── Exception │ ├── ClientException.php │ ├── TimeoutException.php │ └── WorkerException.php ├── Gearman.php ├── Worker.php └── WorkerInterface.php ├── README.markdown └── Resources └── config └── servers.xml /BeSimpleGearmanBundle.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | class BeSimpleGearmanBundle extends Bundle 11 | { 12 | } 13 | -------------------------------------------------------------------------------- /Command/RunWorkerCommand.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | class RunWorkerCommand extends ContainerAwareCommand 14 | { 15 | /** 16 | * @see Command 17 | */ 18 | protected function configure() 19 | { 20 | $this 21 | ->setName('gearman:run-worker') 22 | ->setDefinition(array( 23 | new InputArgument('worker', InputArgument::REQUIRED, 'The gearman worker service'), 24 | )) 25 | ->setDescription('Run a gearman worker') 26 | ->setHelp(<<gearman:run-worker worker.service.name run a gearman worker. 28 | 29 | ./app/console run:worker worker.service.name 30 | EOF 31 | ) 32 | ; 33 | } 34 | 35 | /** 36 | * {@inheritdoc} 37 | */ 38 | protected function execute(InputInterface $input, OutputInterface $output) 39 | { 40 | $worker = $this->getContainer()->get($input->getArgument('worker')); 41 | $worker->execute(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /DependencyInjection/BeSimpleGearmanExtension.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | class BeSimpleGearmanExtension extends Extension 15 | { 16 | public function load(array $configs, ContainerBuilder $container) 17 | { 18 | $processor = new Processor(); 19 | $configuration = new Configuration(); 20 | 21 | $config = $processor->process($configuration->getConfigTree(), $configs); 22 | 23 | $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); 24 | $loader->load('servers.xml'); 25 | 26 | $container->setParameter('besimple.gearman.timeout', $config['timeout']); 27 | 28 | $this->remapServers($config, $container); 29 | } 30 | 31 | protected function remapServers(array $config, ContainerBuilder $container) 32 | { 33 | $workerServers = array(); 34 | $clientServers = array(); 35 | 36 | foreach ($config['servers'] as $server) { 37 | $clientServers[] = $server['host'].($server['port'] ? ':'.$server['port'] : ''); 38 | 39 | if (true === $server['active']['worker']) { 40 | $workerServers[] = $server['host'].($server['port'] ? ':'.$server['port'] : ''); 41 | } 42 | } 43 | 44 | $container->setParameter('besimple.gearman.servers.client', implode(',', $clientServers)); 45 | $container->setParameter('besimple.gearman.servers.worker', implode(',', $workerServers)); 46 | } 47 | } -------------------------------------------------------------------------------- /DependencyInjection/Configuration.php: -------------------------------------------------------------------------------- 1 | 10 | */ 11 | class Configuration 12 | { 13 | /** 14 | * Generates the configuration tree. 15 | * 16 | * @return \Symfony\Component\DependencyInjection\Configuration\NodeInterface 17 | */ 18 | public function getConfigTree() 19 | { 20 | $treeBuilder = new TreeBuilder(); 21 | $rootNode = $treeBuilder->root('be_simple_gearman'); 22 | 23 | $rootNode 24 | ->children() 25 | ->scalarNode('timeout')->defaultValue(-1)->end() 26 | ->end() 27 | ; 28 | 29 | $this->addServersSection($rootNode); 30 | 31 | return $treeBuilder->buildTree(); 32 | } 33 | 34 | private function addServersSection(ArrayNodeDefinition $node) 35 | { 36 | $node 37 | ->children() 38 | ->arrayNode('servers') 39 | ->requiresAtLeastOneElement() 40 | ->useAttributeAsKey('name') 41 | ->prototype('array') 42 | ->addDefaultsIfNotSet() 43 | ->children() 44 | ->scalarNode('host')->end() 45 | ->scalarNode('port')->defaultNull()->end() 46 | ->arrayNode('active') 47 | ->isRequired() 48 | ->children() 49 | ->booleanNode('worker')->isRequired()->end() 50 | ->end() 51 | ->end() 52 | ->end() 53 | ->end() 54 | ->end() 55 | ; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Gearman/Client.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | class Client extends \GearmanClient 11 | { 12 | protected $options = array( 13 | Gearman::OPTION_RUN_TYPE => Gearman::RUN_AND_WAIT, 14 | Gearman::OPTION_PRIORITY => Gearman::PRIORITY_NORMAL, 15 | ); 16 | 17 | public function put($function, $workload, array $options = array()) 18 | { 19 | $options = array_merge($this->options, $options); 20 | 21 | if ($diff = array_diff_key($options, $this->options)) { 22 | throw new \InvalidArgumentException(sprintf('%s does not support the following options: "%s".', get_class($this), implode('", "', array_keys($diff)))); 23 | } 24 | 25 | $method = 'do'; 26 | 27 | switch($options[Gearman::OPTION_PRIORITY]) { 28 | case Gearman::PRIORITY_LOW: 29 | $method .= 'Low'; 30 | break; 31 | case Gearman::PRIORITY_HIGH: 32 | $method .= 'High'; 33 | break; 34 | } 35 | 36 | if (Gearman::RUN_BACKGROUND === $options[Gearman::OPTION_RUN_TYPE]) { 37 | $method .= 'Background'; 38 | } 39 | 40 | return $this->run($method, $function, $workload); 41 | } 42 | 43 | public function run($method, $function, $workload) 44 | { 45 | do { 46 | $result = $this->$method($function, Gearman::serialize($workload)); 47 | 48 | switch($this->returnCode()) { 49 | case \GEARMAN_SUCCESS: 50 | return Gearman::unserialize($result); 51 | break; 52 | 53 | case \GEARMAN_WORK_DATA: 54 | $data = $result; 55 | break; 56 | 57 | case \GEARMAN_WORK_STATUS: 58 | case \GEARMAN_WORK_WARNING: 59 | break; 60 | 61 | case \GEARMAN_WORK_FAIL: 62 | throw new ClientException(sprintf('Worker failed "%s" (function: "%s")', $this->doJobHandle(), $function)); 63 | break; 64 | 65 | default: 66 | throw new ClientException(sprintf('Client error "%s" (code: %d) (ret: %d) (function: "%s")', $this->error(), $this->getErrno(), $this->returnCode(), $function)); 67 | } 68 | } while ($this->returnCode() !== \GEARMAN_SUCCESS); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Gearman/Exception/ClientException.php: -------------------------------------------------------------------------------- 1 | 7 | */ 8 | class ClientException extends \Exception 9 | { 10 | } -------------------------------------------------------------------------------- /Gearman/Exception/TimeoutException.php: -------------------------------------------------------------------------------- 1 | 7 | */ 8 | class TimeoutException extends \Exception 9 | { 10 | } -------------------------------------------------------------------------------- /Gearman/Exception/WorkerException.php: -------------------------------------------------------------------------------- 1 | 7 | */ 8 | class WorkerException extends \Exception 9 | { 10 | } -------------------------------------------------------------------------------- /Gearman/Gearman.php: -------------------------------------------------------------------------------- 1 | 7 | */ 8 | class Gearman 9 | { 10 | const OPTION_RUN_TYPE = 'run'; 11 | const OPTION_PRIORITY = 'priority'; 12 | 13 | const RUN_AND_WAIT = 1; 14 | const RUN_BACKGROUND = 2; 15 | 16 | const PRIORITY_LOW = 1; 17 | const PRIORITY_NORMAL = 2; 18 | const PRIORITY_HIGH = 3; 19 | 20 | static public function serialize($data) 21 | { 22 | return is_scalar($data) ? $data : serialize($data); 23 | } 24 | 25 | static public function unserialize($data) 26 | { 27 | $r = @unserialize($data); 28 | 29 | if ($r !== false || $data === 'b:0;') { 30 | return $r; 31 | } 32 | 33 | return $data; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Gearman/Worker.php: -------------------------------------------------------------------------------- 1 | 10 | */ 11 | abstract class Worker extends \GearmanWorker implements WorkerInterface 12 | { 13 | public function loop($maxIteration = null) 14 | { 15 | $i = 0; 16 | 17 | do { 18 | $i++; 19 | 20 | @$this->work(); 21 | 22 | $this->checkReturn(); 23 | } while (!$maxIteration || $i < $maxIteration); 24 | } 25 | 26 | public function checkReturn() 27 | { 28 | switch ($this->returnCode()) { 29 | case \GEARMAN_TIMEOUT: 30 | throw new TimeoutException(sprintf('Worker error "%s" (code: %d)', $this->error(), $this->returnCode())); 31 | break; 32 | 33 | case \GEARMAN_SUCCESS: 34 | break; 35 | 36 | default: 37 | throw new WorkerException(sprintf('Worker error "%s" (code: %d)', $this->error(), $this->returnCode())); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Gearman/WorkerInterface.php: -------------------------------------------------------------------------------- 1 | 7 | */ 8 | interface WorkerInterface 9 | { 10 | function setFunctions(); 11 | 12 | function execute(); 13 | } 14 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BeSimple/GearmanBundle/96c2ea36fb553324ce71d1f5e1b13f9f682288d2/README.markdown -------------------------------------------------------------------------------- /Resources/config/servers.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | BeSimple\GearmanBundle\Gearman\Client 9 | BeSimple\GearmanBundle\Gearman\Worker 10 | 11 | 12 | 13 | 14 | 15 | %besimple.gearman.servers.client% 16 | 17 | 18 | %besimple.gearman.timeout% 19 | 20 | 21 | 22 | 23 | 24 | %besimple.gearman.servers.worker% 25 | 26 | 27 | %besimple.gearman.timeout% 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | --------------------------------------------------------------------------------