diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..072705c --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.idea/ +vendor/ +composer.lock diff --git a/README.md b/README.md new file mode 100644 index 0000000..ee41b9e --- /dev/null +++ b/README.md @@ -0,0 +1,40 @@ +## Features + +This package provides tools for the following, and more: + +- Add jobs to queue + +## Installation + +Via composer + +``` bash +$ composer require hlgrrnhrdt/laravel-resque +``` + + + +Copy the config the file ```config/resque.php``` from the package to your config folder. + +### Laravel + + +``` php +'providers' => [ + Hlgrrnhrdt\Resque\ResqueServiceProvider::class +] +``` + +### Lumen + +Open ```bootstrap/app.php``` and register the required service provider + +``` php +$app->register(Hlgrrnhrdt\Resque\ResqueServiceProvider::class); +``` + +and load the config with +``` php + +$app->configure('resque'); +``` diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..570bf22 --- /dev/null +++ b/composer.json @@ -0,0 +1,22 @@ +{ + "name": "hlgrrnhrdt/laravel-resque", + "authors": [ + { + "name": "Holger Reinhardt", + "email": "hlgrrnhrdt@gmail.com" + } + ], + "require": { + "illuminate/console": "^5.2", + "illuminate/config": "^5.2", + "danhunsaker/php-resque": "^1.3" + }, + "require-dev": { + "phpunit/phpunit": "^5.4" + }, + "autoload": { + "psr-4": { + "Hlgrrnhrdt\\Resque\\": "src/" + } + } +} diff --git a/config/resque.php b/config/resque.php new file mode 100644 index 0000000..76bd51a --- /dev/null +++ b/config/resque.php @@ -0,0 +1,27 @@ + [ + 'host' => env('RESQUE_REDIS_HOST', 'localhost'), + 'port' => env('RESQUE_REDIS_PORT', 6379), + 'database' => env('RESQUE_REDIS_DATABASE', 0), + ], + + /* + |-------------------------------------------------------------------------- + | Track Status + |-------------------------------------------------------------------------- + | + */ + + 'prefix' => env('RESQUE_PREFIX', 'resque'), + +]; diff --git a/src/Console/WorkCommand.php b/src/Console/WorkCommand.php new file mode 100644 index 0000000..9b01c38 --- /dev/null +++ b/src/Console/WorkCommand.php @@ -0,0 +1,82 @@ + + */ +class WorkCommand extends IlluminateCommand +{ + /** + * The console command name. + * + * @var string + */ + protected $name = 'resque:work'; + + /** + * The console command description. + * + * @var string + */ + protected $description = 'Run a resque worker'; + + /** + * @var \Hlgrrnhrdt\Resque\Resque + */ + private $resque; + + /** + * @param \Hlgrrnhrdt\Resque\Resque $resque + */ + public function __construct(Resque $resque) + { + parent::__construct(); + $this->resque = $resque; + } + + /** + * Execute the console command. + * + * @return int + */ + public function fire() + { + $queue = $this->option('queue'); + $interval = (int)$this->option('interval'); + + $queues = explode(',', $queue); + + $this->startWorker($queues, $interval); + + return 0; + } + + /** + * @param array $queues + * @param int $interval + */ + private function startWorker(array $queues, $interval = 5) + { + $worker = new Resque_Worker($queues); + $this->info(\sprintf('Starting worker %s', $worker)); + $worker->work($interval); + } + + /** + * {@inheritdoc} + */ + protected function getOptions() + { + return [ + ['queue', null, InputOption::VALUE_OPTIONAL, 'The queue to work on', 'default'], + ['interval', null, InputOption::VALUE_OPTIONAL, 'Amount of time to delay failed jobs', 5], + ]; + } +} diff --git a/src/Job.php b/src/Job.php new file mode 100644 index 0000000..6a63bbc --- /dev/null +++ b/src/Job.php @@ -0,0 +1,72 @@ + + */ +abstract class Job +{ + /** + * @var \Resque_Job + */ + public $job; + + /** + * @var string + */ + public $queue = 'default'; + + /** + * @var array + */ + public $args = []; + + /** + * @return mixed + */ + public function queue() + { + return $this->queue; + } + + /** + * @return array + */ + public function arguments() + { + return $this->args ?: []; + } + + /** + * @return string + */ + public function name() + { + return \get_class($this); + } + + /** + * @param string $queue + * + * @return Job + */ + public function onQueue($queue) + { + $this->queue = $queue; + return $this; + } + + /** + * @param Job $job + * + * @return bool + */ + public function equals(Job $job) + { + return $this->name() === $job->name() && $this->arguments() === $job->arguments(); + } + + abstract public function perform(); +} diff --git a/src/Queue.php b/src/Queue.php new file mode 100644 index 0000000..b386d32 --- /dev/null +++ b/src/Queue.php @@ -0,0 +1,53 @@ + + */ +class Queue +{ + /** + * @var string + */ + protected $name; + + /** + * @param string $name + */ + public function __construct($name) + { + $this->name = $name; + } + + /** + * @return string + */ + public function name() + { + return $this->name; + } + + /** + * @return int + */ + public function size() + { + return \Resque::size($this->name); + } + + /** + * @return Job[] + */ + public function jobs() + { + $result = \Resque::redis()->lrange('queue:' . $this->name, 0, -1); + $jobs = []; + foreach ($result as $job) { + $jobs[] = (new \Resque_Job($this->name, \json_decode($job, true)))->getInstance(); + } + + return $jobs; + } +} diff --git a/src/Resque.php b/src/Resque.php new file mode 100644 index 0000000..2dd5b26 --- /dev/null +++ b/src/Resque.php @@ -0,0 +1,87 @@ + + */ +class Resque +{ + /** + * @var string + */ + protected $prefix; + + /** + * @var bool + */ + protected $trackStatus = false; + + /** + * @param string $prefix + * + * @return Resque + */ + public function setPrefix($prefix) + { + \Resque_Redis::prefix($prefix); + return $this; + } + + /** + * @param Job $job + * @param bool $trackStatus + * + * @return null|\Resque_Job_Status + */ + public function enqueue(Job $job, $trackStatus = false) + { + $id = \Resque::enqueue($job->queue(), $job->name(), $job->arguments(), $trackStatus); + + if (true === $trackStatus) { + return new \Resque_Job_Status($id); + } + + return null; + } + + /** + * @param Job $job + * @param bool $trackStatus + * + * @return null|\Resque_Job_Status + */ + public function enqueueOnce(Job $job, $trackStatus = false) + { + $queue = new Queue($job->queue()); + + foreach ($queue->jobs() as $queuedJob) { + if (true === $job->equals($queuedJob)) { + return ($trackStatus) ? new \Resque_Job_Status($queuedJob->job->payload['id']) : null; + } + } + + return $this->enqueue($job, $trackStatus); + } + + /** + * @return \Resque_Redis + */ + public function redis() + { + return \Resque::redis(); + } + + /** + * @return int + * + * @throws RuntimeException + */ + public function fork() + { + return \Resque::fork(); + } +} diff --git a/src/ResqueServiceProvider.php b/src/ResqueServiceProvider.php new file mode 100644 index 0000000..16ae019 --- /dev/null +++ b/src/ResqueServiceProvider.php @@ -0,0 +1,61 @@ + + */ +class ResqueServiceProvider extends ServiceProvider +{ + /** + * + */ + public function boot() + { + $this->setRedisConfig(); + } + + /** + * Register the service provider. + * + * @return void + */ + public function register() + { + $this->registerResque(); + $this->registerWorkCommand(); + } + + protected function registerResque() + { + $this->app->singleton(Resque::class, function () { + $prefix = $this->app['config']['resque.prefix']; + return (new Resque())->setPrefix($prefix ?: 'resque'); + }); + } + + protected function registerWorkCommand() + { + $this->app->singleton('command.resque.work', function () { + return new WorkCommand($this->app->make(Resque::class)); + }); + $this->commands('command.resque.work'); + } + + protected function setRedisConfig() + { + $config = $this->app['config']['resque.connection']; + + $host = isset($config['host']) ? $config['host'] : 'localhost'; + $port = isset($config['port']) ? $config['port'] : 6379; + $database = isset($config['database']) ? $config['database'] : 0; + + $server = implode(':', [$host, $port]); + + \Resque::setBackend($server, $database); + } +} diff --git a/src/Worker.php b/src/Worker.php new file mode 100644 index 0000000..2c281d5 --- /dev/null +++ b/src/Worker.php @@ -0,0 +1,52 @@ + + */ +class Worker +{ + /** + * @var \Resque_Worker + */ + private $worker; + + /** + * @param \Resque_Worker $worker + */ + public function __construct(\Resque_Worker $worker) + { + $this->worker = $worker; + } + + /** + * @return string + */ + public function id() + { + return (string)$this->worker; + } + + /** + * @return bool + */ + public function stop() + { + list(, $pid,) = \explode(':', $this->id()); + return \posix_kill($pid, 3); + } + + /** + * @return Queue[] + */ + public function queues() + { + $queues = \array_map(function ($queue) { + return new Queue($queue); + }, $this->worker->queues()); + + return $queues; + } +}