From b2edaad23da3fadd7d61be5fba01e15110ed7cdc Mon Sep 17 00:00:00 2001 From: Frederic Guillot Date: Sun, 1 May 2016 22:03:21 -0400 Subject: [PATCH] Added Beanstalkd producer/worker --- common.php | 4 + composer.json | 3 +- cronjob.php | 2 - producer.php | 13 + vendor/composer/autoload_classmap.php | 44 ++ vendor/composer/autoload_psr4.php | 1 + vendor/composer/installed.json | 52 +++ vendor/pda/pheanstalk/.gitattributes | 4 + vendor/pda/pheanstalk/.gitignore | 8 + vendor/pda/pheanstalk/LICENSE | 22 + vendor/pda/pheanstalk/README.md | 135 ++++++ vendor/pda/pheanstalk/composer.json | 32 ++ vendor/pda/pheanstalk/scripts/build_phar.php | 57 +++ vendor/pda/pheanstalk/src/Command.php | 61 +++ .../src/Command/AbstractCommand.php | 74 +++ .../pheanstalk/src/Command/BuryCommand.php | 62 +++ .../pheanstalk/src/Command/DeleteCommand.php | 53 +++ .../pheanstalk/src/Command/IgnoreCommand.php | 54 +++ .../pheanstalk/src/Command/KickCommand.php | 48 ++ .../pheanstalk/src/Command/KickJobCommand.php | 59 +++ .../src/Command/ListTubeUsedCommand.php | 34 ++ .../src/Command/ListTubesCommand.php | 35 ++ .../src/Command/ListTubesWatchedCommand.php | 35 ++ .../src/Command/PauseTubeCommand.php | 62 +++ .../pheanstalk/src/Command/PeekCommand.php | 93 ++++ .../pda/pheanstalk/src/Command/PutCommand.php | 113 +++++ .../pheanstalk/src/Command/ReleaseCommand.php | 72 +++ .../pheanstalk/src/Command/ReserveCommand.php | 62 +++ .../pheanstalk/src/Command/StatsCommand.php | 35 ++ .../src/Command/StatsJobCommand.php | 45 ++ .../src/Command/StatsTubeCommand.php | 45 ++ .../pheanstalk/src/Command/TouchCommand.php | 58 +++ .../pda/pheanstalk/src/Command/UseCommand.php | 52 +++ .../pheanstalk/src/Command/WatchCommand.php | 44 ++ vendor/pda/pheanstalk/src/Connection.php | 212 +++++++++ vendor/pda/pheanstalk/src/Exception.php | 15 + .../src/Exception/ClientException.php | 17 + .../src/Exception/CommandException.php | 15 + .../src/Exception/ConnectionException.php | 23 + .../Exception/ServerBadFormatException.php | 15 + .../src/Exception/ServerDrainingException.php | 15 + .../src/Exception/ServerException.php | 17 + .../ServerInternalErrorException.php | 15 + .../Exception/ServerOutOfMemoryException.php | 15 + .../ServerUnknownCommandException.php | 15 + .../src/Exception/SocketException.php | 15 + vendor/pda/pheanstalk/src/Job.php | 49 ++ vendor/pda/pheanstalk/src/Pheanstalk.php | 436 ++++++++++++++++++ .../pheanstalk/src/PheanstalkInterface.php | 301 ++++++++++++ vendor/pda/pheanstalk/src/Response.php | 46 ++ .../pheanstalk/src/Response/ArrayResponse.php | 69 +++ vendor/pda/pheanstalk/src/ResponseParser.php | 21 + vendor/pda/pheanstalk/src/Socket.php | 41 ++ .../pheanstalk/src/Socket/NativeSocket.php | 130 ++++++ .../pheanstalk/src/Socket/StreamFunctions.php | 99 ++++ .../pheanstalk/src/Socket/WriteHistory.php | 64 +++ .../pda/pheanstalk/src/YamlResponseParser.php | 83 ++++ worker.php | 14 + 58 files changed, 3312 insertions(+), 3 deletions(-) create mode 100644 producer.php create mode 100644 vendor/pda/pheanstalk/.gitattributes create mode 100644 vendor/pda/pheanstalk/.gitignore create mode 100644 vendor/pda/pheanstalk/LICENSE create mode 100644 vendor/pda/pheanstalk/README.md create mode 100644 vendor/pda/pheanstalk/composer.json create mode 100755 vendor/pda/pheanstalk/scripts/build_phar.php create mode 100644 vendor/pda/pheanstalk/src/Command.php create mode 100644 vendor/pda/pheanstalk/src/Command/AbstractCommand.php create mode 100644 vendor/pda/pheanstalk/src/Command/BuryCommand.php create mode 100644 vendor/pda/pheanstalk/src/Command/DeleteCommand.php create mode 100644 vendor/pda/pheanstalk/src/Command/IgnoreCommand.php create mode 100644 vendor/pda/pheanstalk/src/Command/KickCommand.php create mode 100644 vendor/pda/pheanstalk/src/Command/KickJobCommand.php create mode 100644 vendor/pda/pheanstalk/src/Command/ListTubeUsedCommand.php create mode 100644 vendor/pda/pheanstalk/src/Command/ListTubesCommand.php create mode 100644 vendor/pda/pheanstalk/src/Command/ListTubesWatchedCommand.php create mode 100644 vendor/pda/pheanstalk/src/Command/PauseTubeCommand.php create mode 100644 vendor/pda/pheanstalk/src/Command/PeekCommand.php create mode 100644 vendor/pda/pheanstalk/src/Command/PutCommand.php create mode 100644 vendor/pda/pheanstalk/src/Command/ReleaseCommand.php create mode 100644 vendor/pda/pheanstalk/src/Command/ReserveCommand.php create mode 100644 vendor/pda/pheanstalk/src/Command/StatsCommand.php create mode 100644 vendor/pda/pheanstalk/src/Command/StatsJobCommand.php create mode 100644 vendor/pda/pheanstalk/src/Command/StatsTubeCommand.php create mode 100644 vendor/pda/pheanstalk/src/Command/TouchCommand.php create mode 100644 vendor/pda/pheanstalk/src/Command/UseCommand.php create mode 100644 vendor/pda/pheanstalk/src/Command/WatchCommand.php create mode 100644 vendor/pda/pheanstalk/src/Connection.php create mode 100644 vendor/pda/pheanstalk/src/Exception.php create mode 100644 vendor/pda/pheanstalk/src/Exception/ClientException.php create mode 100644 vendor/pda/pheanstalk/src/Exception/CommandException.php create mode 100644 vendor/pda/pheanstalk/src/Exception/ConnectionException.php create mode 100644 vendor/pda/pheanstalk/src/Exception/ServerBadFormatException.php create mode 100644 vendor/pda/pheanstalk/src/Exception/ServerDrainingException.php create mode 100644 vendor/pda/pheanstalk/src/Exception/ServerException.php create mode 100644 vendor/pda/pheanstalk/src/Exception/ServerInternalErrorException.php create mode 100644 vendor/pda/pheanstalk/src/Exception/ServerOutOfMemoryException.php create mode 100644 vendor/pda/pheanstalk/src/Exception/ServerUnknownCommandException.php create mode 100644 vendor/pda/pheanstalk/src/Exception/SocketException.php create mode 100644 vendor/pda/pheanstalk/src/Job.php create mode 100644 vendor/pda/pheanstalk/src/Pheanstalk.php create mode 100644 vendor/pda/pheanstalk/src/PheanstalkInterface.php create mode 100644 vendor/pda/pheanstalk/src/Response.php create mode 100644 vendor/pda/pheanstalk/src/Response/ArrayResponse.php create mode 100644 vendor/pda/pheanstalk/src/ResponseParser.php create mode 100644 vendor/pda/pheanstalk/src/Socket.php create mode 100644 vendor/pda/pheanstalk/src/Socket/NativeSocket.php create mode 100644 vendor/pda/pheanstalk/src/Socket/StreamFunctions.php create mode 100644 vendor/pda/pheanstalk/src/Socket/WriteHistory.php create mode 100644 vendor/pda/pheanstalk/src/YamlResponseParser.php create mode 100644 worker.php diff --git a/common.php b/common.php index 05c89bb..13f5d26 100644 --- a/common.php +++ b/common.php @@ -42,6 +42,10 @@ defined('RULES_DIRECTORY') or define('RULES_DIRECTORY', ROOT_DIRECTORY.DIRECTORY defined('ENABLE_HSTS') or define('ENABLE_HSTS', true); +defined('BEANSTALKD_HOST') or define('BEANSTALKD_HOST', '127.0.0.1'); +defined('BEANSTALKD_QUEUE') or define('BEANSTALKD_QUEUE', 'feeds'); +defined('BEANSTALKD_TTL') or define('BEANSTALKD_TTL', 120); + require __DIR__.'/check_setup.php'; PicoDb\Database::setInstance('db', function() { diff --git a/composer.json b/composer.json index 26e2ac8..417e793 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,8 @@ "fguillot/simple-validator": "v1.0.0", "fguillot/json-rpc": "v1.0.2", "fguillot/picodb": "v1.0.2", - "fguillot/picofeed": "v0.1.23" + "fguillot/picofeed": "v0.1.23", + "pda/pheanstalk": "v3.1.0" }, "require-dev": { "phpunit/phpunit": "4.8.3", diff --git a/cronjob.php b/cronjob.php index 7989f52..7026eef 100644 --- a/cronjob.php +++ b/cronjob.php @@ -3,7 +3,6 @@ require __DIR__.'/common.php'; if (php_sapi_name() === 'cli') { - $options = getopt('', array( 'limit::', 'call-interval::', @@ -12,7 +11,6 @@ if (php_sapi_name() === 'cli') { )); } else { - $options = $_GET; } diff --git a/producer.php b/producer.php new file mode 100644 index 0000000..e2f53e8 --- /dev/null +++ b/producer.php @@ -0,0 +1,13 @@ +useTube(BEANSTALKD_QUEUE) + ->put($feed_id, Pheanstalk::DEFAULT_PRIORITY, Pheanstalk::DEFAULT_DELAY, BEANSTALKD_TTL); +} diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php index 67e7ac6..abefef8 100644 --- a/vendor/composer/autoload_classmap.php +++ b/vendor/composer/autoload_classmap.php @@ -15,6 +15,50 @@ return array( 'JsonRPC\\ResponseException' => $vendorDir . '/fguillot/json-rpc/src/JsonRPC/ResponseException.php', 'JsonRPC\\Server' => $vendorDir . '/fguillot/json-rpc/src/JsonRPC/Server.php', 'JsonRPC\\ServerErrorException' => $vendorDir . '/fguillot/json-rpc/src/JsonRPC/Client.php', + 'Pheanstalk\\Command' => $vendorDir . '/pda/pheanstalk/src/Command.php', + 'Pheanstalk\\Command\\AbstractCommand' => $vendorDir . '/pda/pheanstalk/src/Command/AbstractCommand.php', + 'Pheanstalk\\Command\\BuryCommand' => $vendorDir . '/pda/pheanstalk/src/Command/BuryCommand.php', + 'Pheanstalk\\Command\\DeleteCommand' => $vendorDir . '/pda/pheanstalk/src/Command/DeleteCommand.php', + 'Pheanstalk\\Command\\IgnoreCommand' => $vendorDir . '/pda/pheanstalk/src/Command/IgnoreCommand.php', + 'Pheanstalk\\Command\\KickCommand' => $vendorDir . '/pda/pheanstalk/src/Command/KickCommand.php', + 'Pheanstalk\\Command\\KickJobCommand' => $vendorDir . '/pda/pheanstalk/src/Command/KickJobCommand.php', + 'Pheanstalk\\Command\\ListTubeUsedCommand' => $vendorDir . '/pda/pheanstalk/src/Command/ListTubeUsedCommand.php', + 'Pheanstalk\\Command\\ListTubesCommand' => $vendorDir . '/pda/pheanstalk/src/Command/ListTubesCommand.php', + 'Pheanstalk\\Command\\ListTubesWatchedCommand' => $vendorDir . '/pda/pheanstalk/src/Command/ListTubesWatchedCommand.php', + 'Pheanstalk\\Command\\PauseTubeCommand' => $vendorDir . '/pda/pheanstalk/src/Command/PauseTubeCommand.php', + 'Pheanstalk\\Command\\PeekCommand' => $vendorDir . '/pda/pheanstalk/src/Command/PeekCommand.php', + 'Pheanstalk\\Command\\PutCommand' => $vendorDir . '/pda/pheanstalk/src/Command/PutCommand.php', + 'Pheanstalk\\Command\\ReleaseCommand' => $vendorDir . '/pda/pheanstalk/src/Command/ReleaseCommand.php', + 'Pheanstalk\\Command\\ReserveCommand' => $vendorDir . '/pda/pheanstalk/src/Command/ReserveCommand.php', + 'Pheanstalk\\Command\\StatsCommand' => $vendorDir . '/pda/pheanstalk/src/Command/StatsCommand.php', + 'Pheanstalk\\Command\\StatsJobCommand' => $vendorDir . '/pda/pheanstalk/src/Command/StatsJobCommand.php', + 'Pheanstalk\\Command\\StatsTubeCommand' => $vendorDir . '/pda/pheanstalk/src/Command/StatsTubeCommand.php', + 'Pheanstalk\\Command\\TouchCommand' => $vendorDir . '/pda/pheanstalk/src/Command/TouchCommand.php', + 'Pheanstalk\\Command\\UseCommand' => $vendorDir . '/pda/pheanstalk/src/Command/UseCommand.php', + 'Pheanstalk\\Command\\WatchCommand' => $vendorDir . '/pda/pheanstalk/src/Command/WatchCommand.php', + 'Pheanstalk\\Connection' => $vendorDir . '/pda/pheanstalk/src/Connection.php', + 'Pheanstalk\\Exception' => $vendorDir . '/pda/pheanstalk/src/Exception.php', + 'Pheanstalk\\Exception\\ClientException' => $vendorDir . '/pda/pheanstalk/src/Exception/ClientException.php', + 'Pheanstalk\\Exception\\CommandException' => $vendorDir . '/pda/pheanstalk/src/Exception/CommandException.php', + 'Pheanstalk\\Exception\\ConnectionException' => $vendorDir . '/pda/pheanstalk/src/Exception/ConnectionException.php', + 'Pheanstalk\\Exception\\ServerBadFormatException' => $vendorDir . '/pda/pheanstalk/src/Exception/ServerBadFormatException.php', + 'Pheanstalk\\Exception\\ServerDrainingException' => $vendorDir . '/pda/pheanstalk/src/Exception/ServerDrainingException.php', + 'Pheanstalk\\Exception\\ServerException' => $vendorDir . '/pda/pheanstalk/src/Exception/ServerException.php', + 'Pheanstalk\\Exception\\ServerInternalErrorException' => $vendorDir . '/pda/pheanstalk/src/Exception/ServerInternalErrorException.php', + 'Pheanstalk\\Exception\\ServerOutOfMemoryException' => $vendorDir . '/pda/pheanstalk/src/Exception/ServerOutOfMemoryException.php', + 'Pheanstalk\\Exception\\ServerUnknownCommandException' => $vendorDir . '/pda/pheanstalk/src/Exception/ServerUnknownCommandException.php', + 'Pheanstalk\\Exception\\SocketException' => $vendorDir . '/pda/pheanstalk/src/Exception/SocketException.php', + 'Pheanstalk\\Job' => $vendorDir . '/pda/pheanstalk/src/Job.php', + 'Pheanstalk\\Pheanstalk' => $vendorDir . '/pda/pheanstalk/src/Pheanstalk.php', + 'Pheanstalk\\PheanstalkInterface' => $vendorDir . '/pda/pheanstalk/src/PheanstalkInterface.php', + 'Pheanstalk\\Response' => $vendorDir . '/pda/pheanstalk/src/Response.php', + 'Pheanstalk\\ResponseParser' => $vendorDir . '/pda/pheanstalk/src/ResponseParser.php', + 'Pheanstalk\\Response\\ArrayResponse' => $vendorDir . '/pda/pheanstalk/src/Response/ArrayResponse.php', + 'Pheanstalk\\Socket' => $vendorDir . '/pda/pheanstalk/src/Socket.php', + 'Pheanstalk\\Socket\\NativeSocket' => $vendorDir . '/pda/pheanstalk/src/Socket/NativeSocket.php', + 'Pheanstalk\\Socket\\StreamFunctions' => $vendorDir . '/pda/pheanstalk/src/Socket/StreamFunctions.php', + 'Pheanstalk\\Socket\\WriteHistory' => $vendorDir . '/pda/pheanstalk/src/Socket/WriteHistory.php', + 'Pheanstalk\\YamlResponseParser' => $vendorDir . '/pda/pheanstalk/src/YamlResponseParser.php', 'PicoDb\\Condition' => $vendorDir . '/fguillot/picodb/lib/PicoDb/Condition.php', 'PicoDb\\Database' => $vendorDir . '/fguillot/picodb/lib/PicoDb/Database.php', 'PicoDb\\Driver\\Base' => $vendorDir . '/fguillot/picodb/lib/PicoDb/Driver/Base.php', diff --git a/vendor/composer/autoload_psr4.php b/vendor/composer/autoload_psr4.php index b265c64..85e294e 100644 --- a/vendor/composer/autoload_psr4.php +++ b/vendor/composer/autoload_psr4.php @@ -6,4 +6,5 @@ $vendorDir = dirname(dirname(__FILE__)); $baseDir = dirname($vendorDir); return array( + 'Pheanstalk\\' => array($vendorDir . '/pda/pheanstalk/src'), ); diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index 66309ea..204683f 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -210,5 +210,57 @@ ], "description": "Modern library to handle RSS/Atom feeds", "homepage": "https://github.com/fguillot/picoFeed" + }, + { + "name": "pda/pheanstalk", + "version": "v3.1.0", + "version_normalized": "3.1.0.0", + "source": { + "type": "git", + "url": "https://github.com/pda/pheanstalk.git", + "reference": "430e77c551479aad0c6ada0450ee844cf656a18b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/pda/pheanstalk/zipball/430e77c551479aad0c6ada0450ee844cf656a18b", + "reference": "430e77c551479aad0c6ada0450ee844cf656a18b", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "time": "2015-08-07 21:42:41", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Pheanstalk\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paul Annesley", + "email": "paul@annesley.cc", + "homepage": "http://paul.annesley.cc/", + "role": "Developer" + } + ], + "description": "PHP client for beanstalkd queue", + "homepage": "https://github.com/pda/pheanstalk", + "keywords": [ + "beanstalkd" + ] } ] diff --git a/vendor/pda/pheanstalk/.gitattributes b/vendor/pda/pheanstalk/.gitattributes new file mode 100644 index 0000000..dcdb62d --- /dev/null +++ b/vendor/pda/pheanstalk/.gitattributes @@ -0,0 +1,4 @@ +tests/ export-ignore +phpunit.xml.dist export-ignore +doc/ export-ignore +.travis.yml export-ignore diff --git a/vendor/pda/pheanstalk/.gitignore b/vendor/pda/pheanstalk/.gitignore new file mode 100644 index 0000000..c0f3779 --- /dev/null +++ b/vendor/pda/pheanstalk/.gitignore @@ -0,0 +1,8 @@ +pheanstalk.phar + +# Composer lock file; do not commit, this is a library not an app. +# See: http://yehudakatz.com/2010/12/16/clarifying-the-roles-of-the-gemspec-and-gemfile/ +/composer.lock + +# Composer installs dependencies here. +vendor/ diff --git a/vendor/pda/pheanstalk/LICENSE b/vendor/pda/pheanstalk/LICENSE new file mode 100644 index 0000000..69f3394 --- /dev/null +++ b/vendor/pda/pheanstalk/LICENSE @@ -0,0 +1,22 @@ +The MIT License + +Copyright (c) 2008–2015 Paul Annesley + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/vendor/pda/pheanstalk/README.md b/vendor/pda/pheanstalk/README.md new file mode 100644 index 0000000..845ac3c --- /dev/null +++ b/vendor/pda/pheanstalk/README.md @@ -0,0 +1,135 @@ +Pheanstalk +========== + +[![Build Status](https://travis-ci.org/pda/pheanstalk.png?branch=master)](https://travis-ci.org/pda/pheanstalk) + +Pheanstalk is a pure PHP 5.3+ client for the [beanstalkd workqueue][1]. It has +been actively developed, and used in production by many, since late 2008. + +Created by [Paul Annesley][2], Pheanstalk is rigorously unit tested and written +using encapsulated, maintainable object oriented design. Community feedback, +bug reports and patches has led to a stable 1.0 release in 2010, a 2.0 release +in 2013, and a 3.0 release in 2014. + +Pheanstalk 3.0 introduces PHP namespaces, PSR-1 and PSR-2 coding standards, +and PSR-4 autoloader standard. + +beanstalkd up to the latest version 1.4 is supported. All commands and +responses specified in the [protocol documentation][3] for beanstalkd 1.3 are +implemented. + + [1]: http://xph.us/software/beanstalkd/ + [2]: http://paul.annesley.cc/ + [3]: http://github.com/kr/beanstalkd/tree/v1.3/doc/protocol.txt?raw=true + +Installation with Composer +------------- + +Install pheanstalk as a dependency with composer: + +```bash +composer require pda/pheanstalk +``` + + +Usage Example +------------- + +```php +useTube('testtube') + ->put("job payload goes here\n"); + +// ---------------------------------------- +// worker (performs jobs) + +$job = $pheanstalk + ->watch('testtube') + ->ignore('default') + ->reserve(); + +echo $job->getData(); + +$pheanstalk->delete($job); + +// ---------------------------------------- +// check server availability + +$pheanstalk->getConnection()->isServiceListening(); // true or false + +``` + + +Running the tests +----------------- + +There is a section of the test suite which depends on a running beanstalkd +at 127.0.0.1:11300, which was previously opt-in via `--with-server`. +Since porting to PHPUnit, all tests are run at once. Feel free to submit +a pull request to rectify this. + +``` +# ensure you have Composer set up +$ wget http://getcomposer.org/composer.phar +$ php composer.phar install + +# ensure you have PHPUnit +$ composer install --dev + +$ ./vendor/bin/phpunit +PHPUnit 4.0.19 by Sebastian Bergmann. + +Configuration read from /Users/pda/code/pheanstalk/phpunit.xml.dist + +................................................................. 65 / 83 ( 78%) +.................. + +Time: 239 ms, Memory: 6.00Mb + +OK (83 tests, 378 assertions) +``` + + +Contributors +------------ + + * [Paul Annesley](https://github.com/pda) + * [Lachlan Donald](https://github.com/lox) + * [Joakim Bick](https://github.com/minimoe) + * [Vyacheslav](https://github.com/SlNPacifist) + * [leprechaun](https://github.com/leprechaun) + * [Peter McArthur](https://github.com/ptrmcrthr) + * [robbiehudson](https://github.com/robbiehudson) + * [Geoff Catlin](https://github.com/gcatlin) + * [Steven Lewis](https://github.com/srjlewis) + * [Lars Yencken](https://github.com/larsyencken) + * [Josh Butts](https://github.com/jimbojsb) + * [Henry Smith](https://github.com/h2s) + * [Javier Spagnoletti](https://github.com/phansys) + * [Graham Campbell](https://github.com/GrahamCampbell) + * [Thomas Tourlourat](https://github.com/armetiz) + * [Matthieu Napoli](https://github.com/mnapoli) + * [Christoph](https://github.com/xrstf) + * [James Hamilton](https://github.com/mrjameshamilton) + * [Hannes Van De Vreken](https://github.com/hannesvdvreken) + * [Yaniv Davidovitch](https://github.com/YanivD) + * .. [more?](https://github.com/pda/pheanstalk/contributors) Let me know if you're missing. + + +License +------- + +© Paul Annesley + +Released under the [The MIT License](http://www.opensource.org/licenses/mit-license.php) diff --git a/vendor/pda/pheanstalk/composer.json b/vendor/pda/pheanstalk/composer.json new file mode 100644 index 0000000..be10e25 --- /dev/null +++ b/vendor/pda/pheanstalk/composer.json @@ -0,0 +1,32 @@ +{ + "name": "pda/pheanstalk", + "type": "library", + "description": "PHP client for beanstalkd queue", + "keywords": ["beanstalkd"], + "homepage": "https://github.com/pda/pheanstalk", + "license": "MIT", + "authors": [ + { + "name": "Paul Annesley", + "email": "paul@annesley.cc", + "homepage": "http://paul.annesley.cc/", + "role": "Developer" + } + ], + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "autoload": { + "psr-4": { + "Pheanstalk\\": "src/" + } + }, + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + } +} diff --git a/vendor/pda/pheanstalk/scripts/build_phar.php b/vendor/pda/pheanstalk/scripts/build_phar.php new file mode 100755 index 0000000..41c7bc6 --- /dev/null +++ b/vendor/pda/pheanstalk/scripts/build_phar.php @@ -0,0 +1,57 @@ +#!/usr/bin/env php +buildFromDirectory(BASE_DIR); + $phar->setStub( + $phar->createDefaultStub("vendor/autoload.php") + ); +} + +function verify_pheanstalk_phar() +{ + $phar = new Phar(PHAR_FULLPATH); + printf("- %s built with %d files.\n", PHAR_FILENAME, $phar->count()); +} diff --git a/vendor/pda/pheanstalk/src/Command.php b/vendor/pda/pheanstalk/src/Command.php new file mode 100644 index 0000000..798db22 --- /dev/null +++ b/vendor/pda/pheanstalk/src/Command.php @@ -0,0 +1,61 @@ +getCommandLine(); + } + + // ---------------------------------------- + // protected + + /** + * Creates a Response for the given data + * @param array + * @return object Response + */ + protected function _createResponse($name, $data = array()) + { + return new Response\ArrayResponse($name, $data); + } +} diff --git a/vendor/pda/pheanstalk/src/Command/BuryCommand.php b/vendor/pda/pheanstalk/src/Command/BuryCommand.php new file mode 100644 index 0000000..d16a4bb --- /dev/null +++ b/vendor/pda/pheanstalk/src/Command/BuryCommand.php @@ -0,0 +1,62 @@ +_job = $job; + $this->_priority = $priority; + } + + /* (non-phpdoc) + * @see Command::getCommandLine() + */ + public function getCommandLine() + { + return sprintf( + 'bury %u %u', + $this->_job->getId(), + $this->_priority + ); + } + + /* (non-phpdoc) + * @see ResponseParser::parseResponse() + */ + public function parseResponse($responseLine, $responseData) + { + if ($responseLine == Response::RESPONSE_NOT_FOUND) { + throw new Exception\ServerException(sprintf( + '%s: Job %u is not reserved or does not exist.', + $responseLine, + $this->_job->getId() + )); + } elseif ($responseLine == Response::RESPONSE_BURIED) { + return $this->_createResponse(Response::RESPONSE_BURIED); + } else { + throw new Exception('Unhandled response: '.$responseLine); + } + } +} diff --git a/vendor/pda/pheanstalk/src/Command/DeleteCommand.php b/vendor/pda/pheanstalk/src/Command/DeleteCommand.php new file mode 100644 index 0000000..fd75843 --- /dev/null +++ b/vendor/pda/pheanstalk/src/Command/DeleteCommand.php @@ -0,0 +1,53 @@ +_job = $job; + } + + /* (non-phpdoc) + * @see Command::getCommandLine() + */ + public function getCommandLine() + { + return 'delete '.$this->_job->getId(); + } + + /* (non-phpdoc) + * @see ResponseParser::parseResponse() + */ + public function parseResponse($responseLine, $responseData) + { + if ($responseLine == Response::RESPONSE_NOT_FOUND) { + throw new Exception\ServerException(sprintf( + 'Cannot delete job %u: %s', + $this->_job->getId(), + $responseLine + )); + } + + return $this->_createResponse($responseLine); + } +} diff --git a/vendor/pda/pheanstalk/src/Command/IgnoreCommand.php b/vendor/pda/pheanstalk/src/Command/IgnoreCommand.php new file mode 100644 index 0000000..d596adb --- /dev/null +++ b/vendor/pda/pheanstalk/src/Command/IgnoreCommand.php @@ -0,0 +1,54 @@ +_tube = $tube; + } + + /* (non-phpdoc) + * @see Command::getCommandLine() + */ + public function getCommandLine() + { + return 'ignore '.$this->_tube; + } + + /* (non-phpdoc) + * @see ResponseParser::parseResponse() + */ + public function parseResponse($responseLine, $responseData) + { + if (preg_match('#^WATCHING (\d+)$#', $responseLine, $matches)) { + return $this->_createResponse('WATCHING', array( + 'count' => (int) $matches[1] + )); + } elseif ($responseLine == Response::RESPONSE_NOT_IGNORED) { + throw new Exception\ServerException($responseLine . + ': cannot ignore last tube in watchlist'); + } else { + throw new Exception('Unhandled response: '.$responseLine); + } + } +} diff --git a/vendor/pda/pheanstalk/src/Command/KickCommand.php b/vendor/pda/pheanstalk/src/Command/KickCommand.php new file mode 100644 index 0000000..83aba80 --- /dev/null +++ b/vendor/pda/pheanstalk/src/Command/KickCommand.php @@ -0,0 +1,48 @@ +_max = (int) $max; + } + + /* (non-phpdoc) + * @see Command::getCommandLine() + */ + public function getCommandLine() + { + return 'kick '.$this->_max; + } + + /* (non-phpdoc) + * @see ResponseParser::parseResponse() + */ + public function parseResponse($responseLine, $responseData) + { + list($code, $count) = explode(' ', $responseLine); + + return $this->_createResponse($code, array( + 'kicked' => (int) $count, + )); + } +} diff --git a/vendor/pda/pheanstalk/src/Command/KickJobCommand.php b/vendor/pda/pheanstalk/src/Command/KickJobCommand.php new file mode 100644 index 0000000..e376754 --- /dev/null +++ b/vendor/pda/pheanstalk/src/Command/KickJobCommand.php @@ -0,0 +1,59 @@ +_job = $job; + } + + /* (non-phpdoc) + * @see Command::getCommandLine() + */ + public function getCommandLine() + { + return 'kick-job '.$this->_job->getId(); + } + + /* (non-phpdoc) + * @see ResponseParser::parseResponse() + */ + public function parseResponse($responseLine, $responseData) + { + if ($responseLine == Response::RESPONSE_NOT_FOUND) { + throw new Exception\ServerException(sprintf( + '%s: Job %d does not exist or is not in a kickable state.', + $responseLine, + $this->_job->getId() + )); + } elseif ($responseLine == Response::RESPONSE_KICKED) { + return $this->_createResponse(Response::RESPONSE_KICKED); + } else { + throw new Exception('Unhandled response: '.$responseLine); + } + } +} diff --git a/vendor/pda/pheanstalk/src/Command/ListTubeUsedCommand.php b/vendor/pda/pheanstalk/src/Command/ListTubeUsedCommand.php new file mode 100644 index 0000000..55b100f --- /dev/null +++ b/vendor/pda/pheanstalk/src/Command/ListTubeUsedCommand.php @@ -0,0 +1,34 @@ +_createResponse('USING', array( + 'tube' => preg_replace('#^USING (.+)$#', '$1', $responseLine) + )); + } +} diff --git a/vendor/pda/pheanstalk/src/Command/ListTubesCommand.php b/vendor/pda/pheanstalk/src/Command/ListTubesCommand.php new file mode 100644 index 0000000..f0ea5a1 --- /dev/null +++ b/vendor/pda/pheanstalk/src/Command/ListTubesCommand.php @@ -0,0 +1,35 @@ +_tube = $tube; + $this->_delay = $delay; + } + + /* (non-phpdoc) + * @see Command::getCommandLine() + */ + public function getCommandLine() + { + return sprintf( + 'pause-tube %s %u', + $this->_tube, + $this->_delay + ); + } + + /* (non-phpdoc) + * @see ResponseParser::parseResponse() + */ + public function parseResponse($responseLine, $responseData) + { + if ($responseLine == Response::RESPONSE_NOT_FOUND) { + throw new Exception\ServerException(sprintf( + '%s: tube %s does not exist.', + $responseLine, + $this->_tube + )); + } elseif ($responseLine == Response::RESPONSE_PAUSED) { + return $this->_createResponse(Response::RESPONSE_PAUSED); + } else { + throw new Exception('Unhandled response: '.$responseLine); + } + } +} diff --git a/vendor/pda/pheanstalk/src/Command/PeekCommand.php b/vendor/pda/pheanstalk/src/Command/PeekCommand.php new file mode 100644 index 0000000..b76c7ec --- /dev/null +++ b/vendor/pda/pheanstalk/src/Command/PeekCommand.php @@ -0,0 +1,93 @@ +_jobId = $peekSubject; + } elseif (in_array($peekSubject, $this->_subcommands)) { + $this->_subcommand = $peekSubject; + } else { + throw new Exception\CommandException(sprintf( + 'Invalid peek subject: %s', $peekSubject + )); + } + } + + /* (non-phpdoc) + * @see Command::getCommandLine() + */ + public function getCommandLine() + { + return isset($this->_jobId) ? + sprintf('peek %u', $this->_jobId) : + sprintf('peek-%s', $this->_subcommand); + } + + /* (non-phpdoc) + * @see ResponseParser::parseResponse() + */ + public function parseResponse($responseLine, $responseData) + { + if ($responseLine == Response::RESPONSE_NOT_FOUND) { + if (isset($this->_jobId)) { + $message = sprintf( + '%s: Job %u does not exist.', + $responseLine, + $this->_jobId + ); + } else { + $message = sprintf( + "%s: There are no jobs in the '%s' status", + $responseLine, + $this->_subcommand + ); + } + + throw new Exception\ServerException($message); + } elseif (preg_match('#^FOUND (\d+) \d+$#', $responseLine, $matches)) { + return $this->_createResponse( + Response::RESPONSE_FOUND, + array( + 'id' => (int) $matches[1], + 'jobdata' => $responseData, + ) + ); + } + } +} diff --git a/vendor/pda/pheanstalk/src/Command/PutCommand.php b/vendor/pda/pheanstalk/src/Command/PutCommand.php new file mode 100644 index 0000000..1e61c2c --- /dev/null +++ b/vendor/pda/pheanstalk/src/Command/PutCommand.php @@ -0,0 +1,113 @@ +_data = $data; + $this->_priority = $priority; + $this->_delay = $delay; + $this->_ttr = $ttr; + } + + /* (non-phpdoc) + * @see Command::getCommandLine() + */ + public function getCommandLine() + { + return sprintf( + 'put %u %u %u %u', + $this->_priority, + $this->_delay, + $this->_ttr, + $this->getDataLength() + ); + } + + /* (non-phpdoc) + * @see Command::hasData() + */ + public function hasData() + { + return true; + } + + /* (non-phpdoc) + * @see Command::getData() + */ + public function getData() + { + return $this->_data; + } + + /* (non-phpdoc) + * @see Command::getDataLength() + */ + public function getDataLength() + { + if (function_exists('mb_strlen')) { + return mb_strlen($this->_data, "latin1"); + } else { + return strlen($this->_data); + } + } + + /* (non-phpdoc) + * @see ResponseParser::parseResponse() + */ + public function parseResponse($responseLine, $responseData) + { + if (preg_match('#^INSERTED (\d+)$#', $responseLine, $matches)) { + return $this->_createResponse('INSERTED', array( + 'id' => (int) $matches[1] + )); + } elseif (preg_match('#^BURIED (\d)+$#', $responseLine, $matches)) { + throw new Exception(sprintf( + '%s: server ran out of memory trying to grow the priority queue data structure.', + $responseLine + )); + } elseif (preg_match('#^JOB_TOO_BIG$#', $responseLine)) { + throw new Exception(sprintf( + '%s: job data exceeds server-enforced limit', + $responseLine + )); + } elseif (preg_match('#^EXPECTED_CRLF#', $responseLine)) { + throw new Exception(sprintf( + '%s: CRLF expected', + $responseLine + )); + } else { + throw new Exception(sprintf( + 'Unhandled response: %s', + $responseLine + )); + } + } +} diff --git a/vendor/pda/pheanstalk/src/Command/ReleaseCommand.php b/vendor/pda/pheanstalk/src/Command/ReleaseCommand.php new file mode 100644 index 0000000..33161a0 --- /dev/null +++ b/vendor/pda/pheanstalk/src/Command/ReleaseCommand.php @@ -0,0 +1,72 @@ +_job = $job; + $this->_priority = $priority; + $this->_delay = $delay; + } + + /* (non-phpdoc) + * @see Command::getCommandLine() + */ + public function getCommandLine() + { + return sprintf( + 'release %u %u %u', + $this->_job->getId(), + $this->_priority, + $this->_delay + ); + } + + /* (non-phpdoc) + * @see ResponseParser::parseResponse() + */ + public function parseResponse($responseLine, $responseData) + { + if ($responseLine == Response::RESPONSE_BURIED) { + throw new Exception\ServerException(sprintf( + 'Job %u %s: out of memory trying to grow data structure', + $this->_job->getId(), + $responseLine + )); + } + + if ($responseLine == Response::RESPONSE_NOT_FOUND) { + throw new Exception\ServerException(sprintf( + 'Job %u %s: does not exist or is not reserved by client', + $this->_job->getId(), + $responseLine + )); + } + + return $this->_createResponse($responseLine); + } +} diff --git a/vendor/pda/pheanstalk/src/Command/ReserveCommand.php b/vendor/pda/pheanstalk/src/Command/ReserveCommand.php new file mode 100644 index 0000000..9d4ccc8 --- /dev/null +++ b/vendor/pda/pheanstalk/src/Command/ReserveCommand.php @@ -0,0 +1,62 @@ +_timeout = $timeout; + } + + /* (non-phpdoc) + * @see Command::getCommandLine() + */ + public function getCommandLine() + { + return isset($this->_timeout) ? + sprintf('reserve-with-timeout %s', $this->_timeout) : + 'reserve'; + } + + /* (non-phpdoc) + * @see ResponseParser::parseResponse() + */ + public function parseResponse($responseLine, $responseData) + { + if ($responseLine === Response::RESPONSE_DEADLINE_SOON || + $responseLine === Response::RESPONSE_TIMED_OUT) + { + return $this->_createResponse($responseLine); + } + + list($code, $id) = explode(' ', $responseLine); + + return $this->_createResponse($code, array( + 'id' => (int) $id, + 'jobdata' => $responseData, + )); + } +} diff --git a/vendor/pda/pheanstalk/src/Command/StatsCommand.php b/vendor/pda/pheanstalk/src/Command/StatsCommand.php new file mode 100644 index 0000000..907613a --- /dev/null +++ b/vendor/pda/pheanstalk/src/Command/StatsCommand.php @@ -0,0 +1,35 @@ +_jobId = is_object($job) ? $job->getId() : $job; + } + + /* (non-phpdoc) + * @see Command::getCommandLine() + */ + public function getCommandLine() + { + return sprintf('stats-job %u', $this->_jobId); + } + + /* (non-phpdoc) + * @see Command::getResponseParser() + */ + public function getResponseParser() + { + return new YamlResponseParser( + YamlResponseParser::MODE_DICT + ); + } +} diff --git a/vendor/pda/pheanstalk/src/Command/StatsTubeCommand.php b/vendor/pda/pheanstalk/src/Command/StatsTubeCommand.php new file mode 100644 index 0000000..d0711fa --- /dev/null +++ b/vendor/pda/pheanstalk/src/Command/StatsTubeCommand.php @@ -0,0 +1,45 @@ +_tube = $tube; + } + + /* (non-phpdoc) + * @see Command::getCommandLine() + */ + public function getCommandLine() + { + return sprintf('stats-tube %s', $this->_tube); + } + + /* (non-phpdoc) + * @see Command::getResponseParser() + */ + public function getResponseParser() + { + return new YamlResponseParser( + YamlResponseParser::MODE_DICT + ); + } +} diff --git a/vendor/pda/pheanstalk/src/Command/TouchCommand.php b/vendor/pda/pheanstalk/src/Command/TouchCommand.php new file mode 100644 index 0000000..89b9eb5 --- /dev/null +++ b/vendor/pda/pheanstalk/src/Command/TouchCommand.php @@ -0,0 +1,58 @@ +_job = $job; + } + + /* (non-phpdoc) + * @see Command::getCommandLine() + */ + public function getCommandLine() + { + return sprintf('touch %u', $this->_job->getId()); + } + + /* (non-phpdoc) + * @see ResponseParser::parseResponse() + */ + public function parseResponse($responseLine, $responseData) + { + if ($responseLine == Response::RESPONSE_NOT_FOUND) { + throw new Exception\ServerException(sprintf( + 'Job %u %s: does not exist or is not reserved by client', + $this->_job->getId(), + $responseLine + )); + } + + return $this->_createResponse($responseLine); + } +} diff --git a/vendor/pda/pheanstalk/src/Command/UseCommand.php b/vendor/pda/pheanstalk/src/Command/UseCommand.php new file mode 100644 index 0000000..5e5ba70 --- /dev/null +++ b/vendor/pda/pheanstalk/src/Command/UseCommand.php @@ -0,0 +1,52 @@ +_tube = $tube; + } + + /* (non-phpdoc) + * @see Command::getCommandLine() + */ + public function getCommandLine() + { + return 'use '.$this->_tube; + } + + /* (non-phpdoc) + * @see ResponseParser::parseResponse() + */ + public function parseResponse($responseLine, $responseData) + { + return $this->_createResponse('USING', array( + 'tube' => preg_replace('#^USING (.+)$#', '$1', $responseLine) + )); + } +} diff --git a/vendor/pda/pheanstalk/src/Command/WatchCommand.php b/vendor/pda/pheanstalk/src/Command/WatchCommand.php new file mode 100644 index 0000000..07dca67 --- /dev/null +++ b/vendor/pda/pheanstalk/src/Command/WatchCommand.php @@ -0,0 +1,44 @@ +_tube = $tube; + } + + /* (non-phpdoc) + * @see Command::getCommandLine() + */ + public function getCommandLine() + { + return 'watch '.$this->_tube; + } + + /* (non-phpdoc) + * @see ResponseParser::parseResponse() + */ + public function parseResponse($responseLine, $responseData) + { + return $this->_createResponse('WATCHING', array( + 'count' => preg_replace('#^WATCHING (.+)$#', '$1', $responseLine) + )); + } +} diff --git a/vendor/pda/pheanstalk/src/Connection.php b/vendor/pda/pheanstalk/src/Connection.php new file mode 100644 index 0000000..5e7ccd3 --- /dev/null +++ b/vendor/pda/pheanstalk/src/Connection.php @@ -0,0 +1,212 @@ + 'OutOfMemory', + Response::RESPONSE_INTERNAL_ERROR => 'InternalError', + Response::RESPONSE_DRAINING => 'Draining', + Response::RESPONSE_BAD_FORMAT => 'BadFormat', + Response::RESPONSE_UNKNOWN_COMMAND => 'UnknownCommand', + ); + + // responses which are followed by data + private static $_dataResponses = array( + Response::RESPONSE_RESERVED, + Response::RESPONSE_FOUND, + Response::RESPONSE_OK, + ); + + private $_socket; + private $_hostname; + private $_port; + private $_connectTimeout; + private $_connectPersistent; + + /** + * @param string $hostname + * @param int $port + * @param float $connectTimeout + * @param bool $connectPersistent + */ + public function __construct($hostname, $port, $connectTimeout = null, $connectPersistent = false) + { + if (is_null($connectTimeout) || !is_numeric($connectTimeout)) { + $connectTimeout = self::DEFAULT_CONNECT_TIMEOUT; + } + + $this->_hostname = $hostname; + $this->_port = $port; + $this->_connectTimeout = $connectTimeout; + $this->_connectPersistent = $connectPersistent; + } + + /** + * Sets a manually created socket, used for unit testing. + * + * @param Socket $socket + * @return $this + */ + public function setSocket(Socket $socket) + { + $this->_socket = $socket; + + return $this; + } + + /** + * @return bool + */ + public function hasSocket() + { + return isset($this->_socket); + } + + /** + * Disconnect the socket. + * Subsequent socket operations will create a new connection. + */ + public function disconnect() + { + $this->_getSocket()->disconnect(); + $this->_socket = null; + } + + /** + * @param object $command Command + * @return object Response + * @throws Exception\ClientException + */ + public function dispatchCommand($command) + { + $socket = $this->_getSocket(); + + $to_send = $command->getCommandLine().self::CRLF; + + if ($command->hasData()) { + $to_send .= $command->getData().self::CRLF; + } + + $socket->write($to_send); + + $responseLine = $socket->getLine(); + $responseName = preg_replace('#^(\S+).*$#s', '$1', $responseLine); + + if (isset(self::$_errorResponses[$responseName])) { + $exception = sprintf( + '\Pheanstalk\Exception\Server%sException', + self::$_errorResponses[$responseName] + ); + + throw new $exception(sprintf( + "%s in response to '%s'", + $responseName, + $command + )); + } + + if (in_array($responseName, self::$_dataResponses)) { + $dataLength = preg_replace('#^.*\b(\d+)$#', '$1', $responseLine); + $data = $socket->read($dataLength); + + $crlf = $socket->read(self::CRLF_LENGTH); + if ($crlf !== self::CRLF) { + throw new Exception\ClientException(sprintf( + 'Expected %u bytes of CRLF after %u bytes of data', + self::CRLF_LENGTH, + $dataLength + )); + } + } else { + $data = null; + } + + return $command + ->getResponseParser() + ->parseResponse($responseLine, $data); + } + + /** + * Returns the connect timeout for this connection. + * + * @return float + */ + public function getConnectTimeout() + { + return $this->_connectTimeout; + } + + /** + * Returns the host for this connection. + * + * @return string + */ + public function getHost() + { + return $this->_hostname; + } + + /** + * Returns the port for this connection. + * + * @return int + */ + public function getPort() + { + return $this->_port; + } + + // ---------------------------------------- + + /** + * Socket handle for the connection to beanstalkd + * + * @return Socket + * @throws Exception\ConnectionException + */ + private function _getSocket() + { + if (!isset($this->_socket)) { + $this->_socket = new NativeSocket( + $this->_hostname, + $this->_port, + $this->_connectTimeout, + $this->_connectPersistent + ); + } + + return $this->_socket; + } + + /** + * Checks connection to the beanstalkd socket + * + * @return true|false + */ + public function isServiceListening() + { + try { + $this->_getSocket(); + + return true; + } catch (Exception\ConnectionException $e) { + return false; + } + } +} diff --git a/vendor/pda/pheanstalk/src/Exception.php b/vendor/pda/pheanstalk/src/Exception.php new file mode 100644 index 0000000..80acd6d --- /dev/null +++ b/vendor/pda/pheanstalk/src/Exception.php @@ -0,0 +1,15 @@ +_id = (int) $id; + $this->_data = $data; + } + + /** + * The job ID, unique on the beanstalkd server. + * @return int + */ + public function getId() + { + return $this->_id; + } + + /** + * The job data. + * @return string + */ + public function getData() + { + return $this->_data; + } +} diff --git a/vendor/pda/pheanstalk/src/Pheanstalk.php b/vendor/pda/pheanstalk/src/Pheanstalk.php new file mode 100644 index 0000000..ee83553 --- /dev/null +++ b/vendor/pda/pheanstalk/src/Pheanstalk.php @@ -0,0 +1,436 @@ + true); + + /** + * @param string $host + * @param int $port + * @param int $connectTimeout + * @param bool $connectPersistent + */ + public function __construct($host, $port = PheanstalkInterface::DEFAULT_PORT, $connectTimeout = null, $connectPersistent = false) + { + $this->setConnection(new Connection($host, $port, $connectTimeout, $connectPersistent)); + } + + /** + * {@inheritdoc} + */ + public function setConnection(Connection $connection) + { + $this->_connection = $connection; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getConnection() + { + return $this->_connection; + } + + // ---------------------------------------- + + /** + * {@inheritdoc} + */ + public function bury($job, $priority = PheanstalkInterface::DEFAULT_PRIORITY) + { + $this->_dispatch(new Command\BuryCommand($job, $priority)); + } + + /** + * {@inheritdoc} + */ + public function delete($job) + { + $this->_dispatch(new Command\DeleteCommand($job)); + + return $this; + } + + /** + * {@inheritdoc} + */ + public function ignore($tube) + { + if (isset($this->_watching[$tube])) { + $this->_dispatch(new Command\IgnoreCommand($tube)); + unset($this->_watching[$tube]); + } + + return $this; + } + + /** + * {@inheritdoc} + */ + public function kick($max) + { + $response = $this->_dispatch(new Command\KickCommand($max)); + + return $response['kicked']; + } + + /** + * {@inheritdoc} + */ + public function kickJob($job) + { + $this->_dispatch(new Command\KickJobCommand($job)); + + return $this; + } + + /** + * {@inheritdoc} + */ + public function listTubes() + { + return (array) $this->_dispatch( + new Command\ListTubesCommand() + ); + } + + /** + * {@inheritdoc} + */ + public function listTubesWatched($askServer = false) + { + if ($askServer) { + $response = (array) $this->_dispatch( + new Command\ListTubesWatchedCommand() + ); + $this->_watching = array_fill_keys($response, true); + } + + return array_keys($this->_watching); + } + + /** + * {@inheritdoc} + */ + public function listTubeUsed($askServer = false) + { + if ($askServer) { + $response = $this->_dispatch( + new Command\ListTubeUsedCommand() + ); + $this->_using = $response['tube']; + } + + return $this->_using; + } + + /** + * {@inheritdoc} + */ + public function pauseTube($tube, $delay) + { + $this->_dispatch(new Command\PauseTubeCommand($tube, $delay)); + + return $this; + } + + /** + * {@inheritdoc} + */ + public function resumeTube($tube) + { + // Pause a tube with zero delay will resume the tube + $this->pauseTube($tube, 0); + + return $this; + } + + /** + * {@inheritdoc} + */ + public function peek($jobId) + { + $response = $this->_dispatch( + new Command\PeekCommand($jobId) + ); + + return new Job($response['id'], $response['jobdata']); + } + + /** + * {@inheritdoc} + */ + public function peekReady($tube = null) + { + if ($tube !== null) { + $this->useTube($tube); + } + + $response = $this->_dispatch( + new Command\PeekCommand(Command\PeekCommand::TYPE_READY) + ); + + return new Job($response['id'], $response['jobdata']); + } + + /** + * {@inheritdoc} + */ + public function peekDelayed($tube = null) + { + if ($tube !== null) { + $this->useTube($tube); + } + + $response = $this->_dispatch( + new Command\PeekCommand(Command\PeekCommand::TYPE_DELAYED) + ); + + return new Job($response['id'], $response['jobdata']); + } + + /** + * {@inheritdoc} + */ + public function peekBuried($tube = null) + { + if ($tube !== null) { + $this->useTube($tube); + } + + $response = $this->_dispatch( + new Command\PeekCommand(Command\PeekCommand::TYPE_BURIED) + ); + + return new Job($response['id'], $response['jobdata']); + } + + /** + * {@inheritdoc} + */ + public function put( + $data, + $priority = PheanstalkInterface::DEFAULT_PRIORITY, + $delay = PheanstalkInterface::DEFAULT_DELAY, + $ttr = PheanstalkInterface::DEFAULT_TTR + ) + { + $response = $this->_dispatch( + new Command\PutCommand($data, $priority, $delay, $ttr) + ); + + return $response['id']; + } + + /** + * {@inheritdoc} + */ + public function putInTube( + $tube, + $data, + $priority = PheanstalkInterface::DEFAULT_PRIORITY, + $delay = PheanstalkInterface::DEFAULT_DELAY, + $ttr = PheanstalkInterface::DEFAULT_TTR + ) + { + $this->useTube($tube); + + return $this->put($data, $priority, $delay, $ttr); + } + + /** + * {@inheritdoc} + */ + public function release( + $job, + $priority = PheanstalkInterface::DEFAULT_PRIORITY, + $delay = PheanstalkInterface::DEFAULT_DELAY + ) + { + $this->_dispatch( + new Command\ReleaseCommand($job, $priority, $delay) + ); + + return $this; + } + + /** + * {@inheritdoc} + */ + public function reserve($timeout = null) + { + $response = $this->_dispatch( + new Command\ReserveCommand($timeout) + ); + + $falseResponses = array( + Response::RESPONSE_DEADLINE_SOON, + Response::RESPONSE_TIMED_OUT, + ); + + if (in_array($response->getResponseName(), $falseResponses)) { + return false; + } else { + return new Job($response['id'], $response['jobdata']); + } + } + + /** + * {@inheritdoc} + */ + public function reserveFromTube($tube, $timeout = null) + { + $this->watchOnly($tube); + + return $this->reserve($timeout); + } + + /** + * {@inheritdoc} + */ + public function statsJob($job) + { + return $this->_dispatch(new Command\StatsJobCommand($job)); + } + + /** + * {@inheritdoc} + */ + public function statsTube($tube) + { + return $this->_dispatch(new Command\StatsTubeCommand($tube)); + } + + /** + * {@inheritdoc} + */ + public function stats() + { + return $this->_dispatch(new Command\StatsCommand()); + } + + /** + * {@inheritdoc} + */ + public function touch($job) + { + $this->_dispatch(new Command\TouchCommand($job)); + + return $this; + } + + /** + * {@inheritdoc} + */ + public function useTube($tube) + { + if ($this->_using != $tube) { + $this->_dispatch(new Command\UseCommand($tube)); + $this->_using = $tube; + } + + return $this; + } + + /** + * {@inheritdoc} + */ + public function watch($tube) + { + if (!isset($this->_watching[$tube])) { + $this->_dispatch(new Command\WatchCommand($tube)); + $this->_watching[$tube] = true; + } + + return $this; + } + + /** + * {@inheritdoc} + */ + public function watchOnly($tube) + { + $this->watch($tube); + + $ignoreTubes = array_diff_key($this->_watching, array($tube => true)); + foreach ($ignoreTubes as $ignoreTube => $true) { + $this->ignore($ignoreTube); + } + + return $this; + } + + // ---------------------------------------- + + /** + * Dispatches the specified command to the connection object. + * + * If a SocketException occurs, the connection is reset, and the command is + * re-attempted once. + * + * @param Command $command + * @return Response + */ + private function _dispatch($command) + { + try { + $response = $this->_connection->dispatchCommand($command); + } catch (Exception\SocketException $e) { + $this->_reconnect(); + $response = $this->_connection->dispatchCommand($command); + } + + return $response; + } + + /** + * Creates a new connection object, based on the existing connection object, + * and re-establishes the used tube and watchlist. + */ + private function _reconnect() + { + $new_connection = new Connection( + $this->_connection->getHost(), + $this->_connection->getPort(), + $this->_connection->getConnectTimeout() + ); + + $this->setConnection($new_connection); + + if ($this->_using != PheanstalkInterface::DEFAULT_TUBE) { + $tube = $this->_using; + $this->_using = null; + $this->useTube($tube); + } + + foreach ($this->_watching as $tube => $true) { + if ($tube != PheanstalkInterface::DEFAULT_TUBE) { + unset($this->_watching[$tube]); + $this->watch($tube); + } + } + + if (!isset($this->_watching[PheanstalkInterface::DEFAULT_TUBE])) { + $this->ignore(PheanstalkInterface::DEFAULT_TUBE); + } + } +} diff --git a/vendor/pda/pheanstalk/src/PheanstalkInterface.php b/vendor/pda/pheanstalk/src/PheanstalkInterface.php new file mode 100644 index 0000000..3e17dda --- /dev/null +++ b/vendor/pda/pheanstalk/src/PheanstalkInterface.php @@ -0,0 +1,301 @@ +value data + * + * @author Paul Annesley + * @package Pheanstalk + * @license http://www.opensource.org/licenses/mit-license.php + */ +class ArrayResponse + extends \ArrayObject + implements Response +{ + private $_name; + + /** + * @param string $name + * @param array $data + */ + public function __construct($name, $data) + { + $this->_name = $name; + parent::__construct($data); + } + + /* (non-phpdoc) + * @see Response::getResponseName() + */ + public function getResponseName() + { + return $this->_name; + } + + /** + * Object property access to ArrayObject data. + */ + public function __get($property) + { + $key = $this->_transformPropertyName($property); + + return isset($this[$key]) ? $this[$key] : null; + } + + /** + * Object property access to ArrayObject data. + */ + public function __isset($property) + { + $key = $this->_transformPropertyName($property); + + return isset($this[$key]); + } + + // ---------------------------------------- + + /** + * Tranform underscored property name to hyphenated array key. + * @param string + * @return string + */ + private function _transformPropertyName($propertyName) + { + return str_replace('_', '-', $propertyName); + } +} diff --git a/vendor/pda/pheanstalk/src/ResponseParser.php b/vendor/pda/pheanstalk/src/ResponseParser.php new file mode 100644 index 0000000..c166330 --- /dev/null +++ b/vendor/pda/pheanstalk/src/ResponseParser.php @@ -0,0 +1,21 @@ +_socket = $this->_wrapper() + ->pfsockopen($host, $port, $errno, $errstr, $connectTimeout, $connectPersistent); + } else { + $this->_socket = $this->_wrapper() + ->fsockopen($host, $port, $errno, $errstr, $connectTimeout, $connectPersistent); + } + + if (!$this->_socket) { + throw new Exception\ConnectionException($errno, $errstr . " (connecting to $host:$port)"); + } + + $this->_wrapper() + ->stream_set_timeout($this->_socket, self::SOCKET_TIMEOUT); + } + + /* (non-phpdoc) + * @see Socket::write() + */ + public function write($data) + { + $history = new WriteHistory(self::WRITE_RETRIES); + + for ($written = 0, $fwrite = 0; $written < strlen($data); $written += $fwrite) { + $fwrite = $this->_wrapper() + ->fwrite($this->_socket, substr($data, $written)); + + $history->log($fwrite); + + if ($history->isFullWithNoWrites()) { + throw new Exception\SocketException(sprintf( + 'fwrite() failed to write data after %u tries', + self::WRITE_RETRIES + )); + } + } + } + + /* (non-phpdoc) + * @see Socket::write() + */ + public function read($length) + { + $read = 0; + $parts = ''; + + while ($read < $length && !$this->_wrapper()->feof($this->_socket)) { + $data = $this->_wrapper() + ->fread($this->_socket, $length - $read); + + if ($data === false) { + throw new Exception\SocketException('fread() returned false'); + } + + $read += strlen($data); + $parts .= $data; + } + + return $parts; + } + + /* (non-phpdoc) + * @see Socket::write() + */ + public function getLine($length = null) + { + do { + $data = isset($length) ? + $this->_wrapper()->fgets($this->_socket, $length) : + $this->_wrapper()->fgets($this->_socket); + + if ($this->_wrapper()->feof($this->_socket)) { + throw new Exception\SocketException("Socket closed by server!"); + } + } while ($data === false); + + return rtrim($data); + } + + public function disconnect() + { + $this->_wrapper()->fclose($this->_socket); + } + + // ---------------------------------------- + + /** + * Wrapper class for all stream functions. + * Facilitates mocking/stubbing stream operations in unit tests. + */ + private function _wrapper() + { + return StreamFunctions::instance(); + } +} diff --git a/vendor/pda/pheanstalk/src/Socket/StreamFunctions.php b/vendor/pda/pheanstalk/src/Socket/StreamFunctions.php new file mode 100644 index 0000000..6f793f8 --- /dev/null +++ b/vendor/pda/pheanstalk/src/Socket/StreamFunctions.php @@ -0,0 +1,99 @@ +_limit = $limit; + } + + /** + * Whether the history has reached its limit of entries. + */ + public function isFull() + { + return count($this->_data) >= $this->_limit; + } + + public function hasWrites() + { + return (bool) array_sum($this->_data); + } + + public function isFullWithNoWrites() + { + return $this->isFull() && !$this->hasWrites(); + } + + /** + * Logs the return value from a write call. + * Returns the input value. + */ + public function log($write) + { + if ($this->isFull()) { + array_shift($this->_data); + } + + $this->_data[] = (int) $write; + + return $write; + } +} diff --git a/vendor/pda/pheanstalk/src/YamlResponseParser.php b/vendor/pda/pheanstalk/src/YamlResponseParser.php new file mode 100644 index 0000000..9f0a1d3 --- /dev/null +++ b/vendor/pda/pheanstalk/src/YamlResponseParser.php @@ -0,0 +1,83 @@ +_mode = $mode; + } + + /* (non-phpdoc) + * @see ResponseParser::parseResponse() + */ + public function parseResponse($responseLine, $responseData) + { + if ($responseLine == Response::RESPONSE_NOT_FOUND) { + throw new Exception\ServerException(sprintf( + 'Server reported %s', + $responseLine + )); + } + + if (!preg_match('#^OK \d+$#', $responseLine)) { + throw new Exception\ServerException(sprintf( + 'Unhandled response: %s', + $responseLine + )); + } + + $dataLines = preg_split("#[\r\n]+#", rtrim($responseData)); + if (isset($dataLines[0]) && $dataLines[0] == '---') { + array_shift($dataLines); // discard header line + } + + $data = array_map(array($this, '_mapYamlList'), $dataLines); + + if ($this->_mode == self::MODE_DICT) { + // TODO: do this better. + $array = array(); + foreach ($data as $line) { + if (!preg_match('#(\S+):\s*(.*)#', $line, $matches)) { + throw new Exception("YAML parse error for line: $line"); + } + + list(, $key, $value) = $matches; + + $array[$key] = $value; + } + $data = $array; + } + + return new Response\ArrayResponse('OK', $data); + } + + /** + * Callback for array_map to process YAML lines. + * @param string $line + * @return string + */ + private function _mapYamlList($line) + { + return ltrim($line, '- '); + } +} diff --git a/worker.php b/worker.php new file mode 100644 index 0000000..433193f --- /dev/null +++ b/worker.php @@ -0,0 +1,14 @@ +reserveFromTube(BEANSTALKD_QUEUE)) { + $feed_id = $job->getData(); + echo 'Processing feed_id='.$feed_id.PHP_EOL; + Model\Feed\refresh($feed_id); + $connection->delete($job); +}