├── src ├── Connectors │ └── GearmanConnector.php ├── Commands │ └── NodesCommand.php ├── Jobs │ └── GearmanJob.php ├── GearmanQueue.php └── GearmanServiceProvider.php └── README.md /src/Connectors/GearmanConnector.php: -------------------------------------------------------------------------------- 1 | addServer($config['host'], (int) $config['port']); 16 | $this->setTimeout($client, $config); 17 | $worker = new GearmanWorker; 18 | $worker->addServer($config['host'], (int) $config['port']); 19 | return new GearmanQueue ($client, $worker, $config['queue']); 20 | } 21 | 22 | private function setTimeout(GearmanClient $client, array $config) { 23 | if(isset ($config['timeout']) && is_numeric($config['timeout'])) { 24 | $client->setTimeout($config['timeout']); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Nodes Gearman 2 | 3 | Laravel 5 package to integrate Laravel Queue to Gearman 4 | 5 | ## How to use 6 | 7 | Start by creating a Queue script. This is the script gearman should run. Here is an example file you can use in app/Commands/QueueTest.php 8 | 9 | ```php 10 | data = $data; 35 | } 36 | 37 | /** 38 | * Execute the command. 39 | * 40 | * @return void 41 | */ 42 | public function handle() 43 | { 44 | \Log::error('Some error'); 45 | 46 | \Log::info('Processing id: ' . $this->data['id']); 47 | } 48 | } 49 | ``` 50 | 51 | To run the command from your code use: 52 | 53 | ```php 54 | \Queue::push(new QueueTest(['id' => 1])); 55 | ``` 56 | If you just want your command to run a function in a repository or other class. You can use NodesCommand 57 | Example 58 | 59 | ```php 60 | \Queue::push(new NodesCommand([ 61 | 'class' => 'Oxcept\Models\ChatUser\ChatUserRepository', 62 | 'action' => 'run', 63 | 'params' => [ 64 | 'id' => 1, 65 | 'name' => 'Casper is cool' 66 | ] 67 | ])); 68 | ``` 69 | 70 | If you integrate other files in your QueueTest.php you can print output by using Laravel log handler. 71 | 72 | ```php 73 | \Log::info('Information from another file'); 74 | ``` 75 | 76 | This will be catched and outputtet in the queue:listen function. 77 | -------------------------------------------------------------------------------- /src/Commands/NodesCommand.php: -------------------------------------------------------------------------------- 1 | data = $data; 34 | } 35 | 36 | /** 37 | * Execute the command. 38 | * 39 | * @return void 40 | */ 41 | public function handle() 42 | { 43 | try { 44 | \Log::info('Processing NodesCommand with data: ' . is_array($this->data) ? json_encode($this->data) : ' unknown '); 45 | $function = $this->data['action']; 46 | $param = !empty($this->data['params']) ? $this->data['params'] : false; 47 | $result = App::make($this->data['class'])->$function($param); 48 | \Log::info('Done Processing NodesCommand with data: ' . json_encode($this->data) . ' result: ' . json_encode($result)); 49 | } catch(\Exception $e) { 50 | try { 51 | return \Log::error('Error Processing NodesCommand with data: ' . is_array($this->data) ? json_encode($this->data) : ' unknown ' . ' result: ' . $e->getMessage()); 52 | } catch(\Exception $e) { 53 | return \Log::error('Error Processing NodesCommand'); 54 | } 55 | } 56 | 57 | } 58 | } -------------------------------------------------------------------------------- /src/Jobs/GearmanJob.php: -------------------------------------------------------------------------------- 1 | worker = $worker; 23 | $this->job = $job; 24 | $this->queue = $queue; 25 | $this->container = $container; 26 | 27 | $this->attempts = $this->attempts + 1; 28 | 29 | $this->worker->addFunction($queue, [$this, 'onGearmanJob']); 30 | } 31 | 32 | /** 33 | * Fire the job. 34 | * 35 | * @return void 36 | */ 37 | public function fire() 38 | { 39 | \Log::listen(function($level, $message, $context) 40 | { 41 | print '[' . $level . '] ' . $message; 42 | print "\n"; 43 | }); 44 | 45 | while($this->worker->work() || $this->worker->returnCode() == GEARMAN_TIMEOUT) { 46 | 47 | } 48 | } 49 | 50 | /** 51 | * Get the raw body string for the job. 52 | * 53 | * @return string 54 | */ 55 | public function getRawBody() 56 | { 57 | return $this->rawPayload; 58 | } 59 | 60 | /** 61 | * Delete the job from the queue. 62 | * 63 | * @return void 64 | */ 65 | public function delete() 66 | { 67 | parent::delete(); 68 | } 69 | 70 | /** 71 | * Release the job back into the queue. 72 | * 73 | * @todo missing implementation 74 | * 75 | * @param int $delay 76 | * @return void 77 | */ 78 | public function release($delay = 0) 79 | { 80 | parent::release($delay); 81 | } 82 | 83 | /** 84 | * Get the number of times the job has been attempted. 85 | * 86 | * @return int 87 | */ 88 | public function attempts() 89 | { 90 | return (int) $this->attempts; 91 | } 92 | 93 | /** 94 | * Get the job identifier. 95 | * 96 | * @return string 97 | */ 98 | public function getJobId() 99 | { 100 | return base64_encode($this->job); 101 | } 102 | 103 | /** 104 | * Get the IoC container instance. 105 | * 106 | * @return \Illuminate\Container\Container 107 | */ 108 | public function getContainer() 109 | { 110 | return $this->container; 111 | } 112 | 113 | public function getGearmanWorker() { 114 | return $this->worker; 115 | } 116 | 117 | public function onGearmanJob(\GearmanJob $job) { 118 | $this->rawPayload = $job->workload(); 119 | 120 | $this->resolveAndFire(json_decode($this->rawPayload, true)); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/GearmanQueue.php: -------------------------------------------------------------------------------- 1 | client = $client; 43 | $this->worker = $worker; 44 | $this->queue = $queue; 45 | } 46 | /** 47 | * Push job to the queue 48 | * 49 | * @param string $job 50 | * @param string $data 51 | * @param string|null $queue 52 | * @return int|mixed Return gearman code 53 | */ 54 | public function push($job, $data = '', $queue = null) 55 | { 56 | if(!$queue) { 57 | $queue = $this->queue; 58 | } 59 | $payload = $this->createPayload($job, $data); 60 | $this->doBackgroundAndHandleException($queue, $payload); 61 | return $this->client->returnCode(); 62 | } 63 | /** 64 | * Do the actual handling from the gearmand worker. On error it throws an exception 65 | * 66 | * @param $queue 67 | * @param $payload 68 | * 69 | * @throws GearmanException 70 | */ 71 | private function doBackgroundAndHandleException($queue, $payload) 72 | { 73 | try { 74 | $this->client->doBackground($queue, $payload); 75 | } catch (Exception $e) { 76 | throw new GearmanException($e); 77 | } 78 | } 79 | /** 80 | * It is not supported from the gearmand driver 81 | * 82 | * @param $delay 83 | * @param $job 84 | * @param string $data 85 | * @param null $queue 86 | * 87 | * @throws Exception 88 | */ 89 | public function later($delay, $job, $data = '', $queue = null) 90 | { 91 | throw new Exception('Gearman driver do not support the method later'); 92 | } 93 | /** 94 | * take a job from the queue 95 | * 96 | * @param null $queue 97 | * @return \Illuminate\Queue\Jobs\Job|\Illuminate\Queue\null|GearmanJob 98 | */ 99 | public function pop($queue = null) 100 | { 101 | if(!$queue) { 102 | $queue = $this->queue; 103 | } 104 | $job = []; 105 | 106 | return new GearmanJob($this->container, $this->worker, $queue, $job); 107 | } 108 | /** 109 | * It is not supported from the gearmand driver 110 | * 111 | * @param string $payload 112 | * @param string $queue 113 | * @param array $options 114 | * @throws \Exception 115 | * @return mixed 116 | */ 117 | public function pushRaw($payload, $queue = null, array $options = array()) 118 | { 119 | throw new Exception('Gearman driver do not support the method pushRaw'); 120 | } 121 | } -------------------------------------------------------------------------------- /src/GearmanServiceProvider.php: -------------------------------------------------------------------------------- 1 | registerManager(); 38 | 39 | $this->registerWorker(); 40 | 41 | $this->registerListener(); 42 | 43 | $this->registerSubscriber(); 44 | 45 | $this->registerFailedJobServices(); 46 | 47 | $this->registerQueueClosure(); 48 | } 49 | 50 | /** 51 | * Register the queue manager. 52 | * 53 | * @return void 54 | */ 55 | protected function registerManager() 56 | { 57 | $this->app->singleton('queue', function($app) 58 | { 59 | $manager = new QueueManager($app); 60 | 61 | $this->registerConnectors($manager); 62 | 63 | return $manager; 64 | }); 65 | 66 | $this->app->singleton('queue.connection', function($app) 67 | { 68 | return $app['queue']->connection(); 69 | }); 70 | } 71 | 72 | /** 73 | * Register the queue worker. 74 | * 75 | * @return void 76 | */ 77 | protected function registerWorker() 78 | { 79 | $this->registerWorkCommand(); 80 | 81 | $this->registerRestartCommand(); 82 | 83 | $this->app->singleton('queue.worker', function($app) 84 | { 85 | return new Worker($app['queue'], $app['queue.failer'], $app['events']); 86 | }); 87 | } 88 | 89 | /** 90 | * Register the queue worker console command. 91 | * 92 | * @return void 93 | */ 94 | protected function registerWorkCommand() 95 | { 96 | $this->app->singleton('command.queue.work', function($app) 97 | { 98 | return new WorkCommand($app['queue.worker']); 99 | }); 100 | 101 | $this->commands('command.queue.work'); 102 | } 103 | 104 | /** 105 | * Register the queue listener. 106 | * 107 | * @return void 108 | */ 109 | protected function registerListener() 110 | { 111 | $this->registerListenCommand(); 112 | 113 | $this->app->singleton('queue.listener', function($app) 114 | { 115 | return new Listener($app['path.base']); 116 | }); 117 | } 118 | 119 | /** 120 | * Register the queue listener console command. 121 | * 122 | * @return void 123 | */ 124 | protected function registerListenCommand() 125 | { 126 | $this->app->singleton('command.queue.listen', function($app) 127 | { 128 | return new ListenCommand($app['queue.listener']); 129 | }); 130 | 131 | $this->commands('command.queue.listen'); 132 | } 133 | 134 | /** 135 | * Register the queue restart console command. 136 | * 137 | * @return void 138 | */ 139 | public function registerRestartCommand() 140 | { 141 | $this->app->singleton('command.queue.restart', function() 142 | { 143 | return new RestartCommand; 144 | }); 145 | 146 | $this->commands('command.queue.restart'); 147 | } 148 | 149 | /** 150 | * Register the push queue subscribe command. 151 | * 152 | * @return void 153 | */ 154 | protected function registerSubscriber() 155 | { 156 | $this->app->singleton('command.queue.subscribe', function() 157 | { 158 | return new SubscribeCommand; 159 | }); 160 | 161 | $this->commands('command.queue.subscribe'); 162 | } 163 | 164 | /** 165 | * Register the connectors on the queue manager. 166 | * 167 | * @param \Illuminate\Queue\QueueManager $manager 168 | * @return void 169 | */ 170 | public function registerConnectors($manager) 171 | { 172 | foreach (['Null', 'Sync', 'Database', 'Beanstalkd', 'Redis', 'Sqs', 'Iron', 'Gearman'] as $connector) 173 | { 174 | $this->{"register{$connector}Connector"}($manager); 175 | } 176 | } 177 | 178 | /** 179 | * Register the Null queue connector. 180 | * 181 | * @param \Illuminate\Queue\QueueManager $manager 182 | * @return void 183 | */ 184 | protected function registerNullConnector($manager) 185 | { 186 | $manager->addConnector('null', function() 187 | { 188 | return new NullConnector; 189 | }); 190 | } 191 | 192 | /** 193 | * Register the Sync queue connector. 194 | * 195 | * @param \Illuminate\Queue\QueueManager $manager 196 | * @return void 197 | */ 198 | protected function registerSyncConnector($manager) 199 | { 200 | $manager->addConnector('sync', function() 201 | { 202 | return new SyncConnector; 203 | }); 204 | } 205 | 206 | /** 207 | * Register the Beanstalkd queue connector. 208 | * 209 | * @param \Illuminate\Queue\QueueManager $manager 210 | * @return void 211 | */ 212 | protected function registerBeanstalkdConnector($manager) 213 | { 214 | $manager->addConnector('beanstalkd', function() 215 | { 216 | return new BeanstalkdConnector; 217 | }); 218 | } 219 | 220 | /** 221 | * Register the database queue connector. 222 | * 223 | * @param \Illuminate\Queue\QueueManager $manager 224 | * @return void 225 | */ 226 | protected function registerDatabaseConnector($manager) 227 | { 228 | $manager->addConnector('database', function() 229 | { 230 | return new DatabaseConnector($this->app['db']); 231 | }); 232 | } 233 | 234 | /** 235 | * Register the Redis queue connector. 236 | * 237 | * @param \Illuminate\Queue\QueueManager $manager 238 | * @return void 239 | */ 240 | protected function registerRedisConnector($manager) 241 | { 242 | $app = $this->app; 243 | 244 | $manager->addConnector('redis', function() use ($app) 245 | { 246 | return new RedisConnector($app['redis']); 247 | }); 248 | } 249 | 250 | /** 251 | * Register the Amazon SQS queue connector. 252 | * 253 | * @param \Illuminate\Queue\QueueManager $manager 254 | * @return void 255 | */ 256 | protected function registerSqsConnector($manager) 257 | { 258 | $manager->addConnector('sqs', function() 259 | { 260 | return new SqsConnector; 261 | }); 262 | } 263 | 264 | /** 265 | * Register the IronMQ queue connector. 266 | * 267 | * @param \Illuminate\Queue\QueueManager $manager 268 | * @return void 269 | */ 270 | protected function registerIronConnector($manager) 271 | { 272 | $app = $this->app; 273 | 274 | $manager->addConnector('iron', function() use ($app) 275 | { 276 | return new IronConnector($app['encrypter'], $app['request']); 277 | }); 278 | 279 | $this->registerIronRequestBinder(); 280 | } 281 | 282 | /** 283 | * Register the request rebinding event for the Iron queue. 284 | * 285 | * @return void 286 | */ 287 | protected function registerIronRequestBinder() 288 | { 289 | $this->app->rebinding('request', function($app, $request) 290 | { 291 | if ($app['queue']->connected('iron')) 292 | { 293 | $app['queue']->connection('iron')->setRequest($request); 294 | } 295 | }); 296 | } 297 | 298 | public function registerGearmanConnector($manager) { 299 | $manager->addConnector('gearman', function() 300 | { 301 | return new GearmanConnector(); 302 | }); 303 | } 304 | 305 | /** 306 | * Register the failed job services. 307 | * 308 | * @return void 309 | */ 310 | protected function registerFailedJobServices() 311 | { 312 | $this->app->singleton('queue.failer', function($app) 313 | { 314 | $config = $app['config']['queue.failed']; 315 | 316 | return new DatabaseFailedJobProvider($app['db'], $config['database'], $config['table']); 317 | }); 318 | } 319 | 320 | /** 321 | * Register the Illuminate queued closure job. 322 | * 323 | * @return void 324 | */ 325 | protected function registerQueueClosure() 326 | { 327 | $this->app->singleton('IlluminateQueueClosure', function($app) 328 | { 329 | return new IlluminateQueueClosure($app['encrypter']); 330 | }); 331 | } 332 | 333 | /** 334 | * Get the services provided by the provider. 335 | * 336 | * @return array 337 | */ 338 | public function provides() 339 | { 340 | return [ 341 | 'queue', 'queue.worker', 'queue.listener', 'queue.failer', 342 | 'command.queue.work', 'command.queue.listen', 'command.queue.restart', 343 | 'command.queue.subscribe', 'queue.connection', 344 | ]; 345 | } 346 | 347 | } 348 | --------------------------------------------------------------------------------