├── .editorconfig ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── composer.json ├── phpunit.xml ├── src └── Schickling │ └── QueueChecker │ ├── Commands │ ├── QueueCheckerCommand.php │ └── QueueCheckerResetCommand.php │ ├── ErrorHandlers │ ├── ErrorHandlerInterface.php │ ├── Errors.php │ └── LogErrorHandler.php │ ├── Jobs │ └── QueueCheckerJob.php │ └── QueueCheckerServiceProvider.php └── tests ├── Commands ├── QueueCheckerCommandTest.php └── QueueCheckerResetCommandTest.php ├── ErrorHandlers └── LogErrorHandlerTest.php └── Jobs └── QueueCheckerJobTest.php /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | end_of_line = lf 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | 9 | [*.php] 10 | indent_style = space 11 | indent_size = 4 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | composer.phar 3 | composer.lock 4 | .DS_Store -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 5.4 5 | - 5.5 6 | 7 | before_script: 8 | - composer install --dev 9 | 10 | script: phpunit --coverage-text --coverage-clover ./build/logs/clover.xml 11 | 12 | after_script: php vendor/bin/coveralls 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 sub2home 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | laravel-queue-checker [![Build Status](https://travis-ci.org/schickling/laravel-queue-checker.png?branch=master)](https://travis-ci.org/schickling/laravel-queue-checker) [![Coverage Status](https://coveralls.io/repos/schickling/laravel-queue-checker/badge.png)](https://coveralls.io/r/schickling/laravel-queue-checker) [![Total Downloads](https://poser.pugx.org/schickling/queue-checker/downloads.png)](https://packagist.org/packages/schickling/queue-checker) 2 | ===================== 3 | 4 | Command to check the queue health status. Can be used with hosted monitoring systems. 5 | 6 | ## Installation 7 | 8 | 1. Add the following to your composer.json and run `composer update` 9 | 10 | ```json 11 | { 12 | "require": { 13 | "schickling/queue-checker": "dev-master" 14 | } 15 | } 16 | ``` 17 | 18 | 2. Add `Schickling\QueueChecker\QueueCheckerServiceProvider` to your config/app.php 19 | 20 | ## Usage 21 | 22 | ### Run as cronjob 23 | Run the following command as a cronjob (for example each minute). If the queue isn't connected or does not work (e.g. jammed), the binded `ErrorHandler` will be notified. The default `ErrorHandler` will log the incident. 24 | 25 | ```sh 26 | $ php artisan queue:check 27 | ``` 28 | 29 | ### Implement your own `ErrorHandler` 30 | You can for example write an `ErrorHandler` that sends a message to your system monitoring platform such as NewRelic. Simply create a class that implements the `Schickling\QueueChecker\ErrorHandlers\ErrorHandlerInterface` and bind your `ErrorHandler` with the following code: 31 | 32 | ```php 33 | App::bind('Schickling\QueueChecker\ErrorHandlers\ErrorHandlerInterface', 'App\MyCustomErrorHandler'); 34 | ``` 35 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "schickling/queue-checker", 3 | "description": "Command to check the queue health status", 4 | "licene": "MIT", 5 | "authors": [ 6 | { 7 | "name": "Johannes Schickling", 8 | "email": "schickling.j@gmail.com" 9 | } 10 | ], 11 | "require": { 12 | "php": ">=5.4.0" 13 | }, 14 | "require-dev": { 15 | "laravel/framework": "~4", 16 | "orchestra/testbench": "2.1.*", 17 | "satooshi/php-coveralls": "0.6.*", 18 | "mockery/mockery": "dev-master" 19 | }, 20 | "autoload": { 21 | "psr-0": { 22 | "Schickling\\QueueChecker": "src/" 23 | } 24 | }, 25 | "minimum-stability": "dev" 26 | } 27 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | ./tests/ 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/Schickling/QueueChecker/Commands/QueueCheckerCommand.php: -------------------------------------------------------------------------------- 1 | checkIfCacheWasInitialized(); 24 | 25 | $jobValue = Cache::get('queue-checker-job-value'); 26 | $queueValue = Cache::get('queue-checker-command-value'); 27 | 28 | if ($jobValue == $queueValue) 29 | { 30 | $jobValue++; 31 | $jobValue %= 1000000; 32 | Queue::push('Schickling\QueueChecker\Jobs\QueueCheckerJob', ['jobValue' => $jobValue]); 33 | Cache::put('queue-checker-command-value', $jobValue, 60); 34 | } 35 | else 36 | { 37 | $errorHandler = App::make('Schickling\QueueChecker\ErrorHandlers\ErrorHandlerInterface'); 38 | $errorHandler->handle(Errors::NOT_WORKING, 'Queue does not seem to be working.'); 39 | } 40 | } 41 | else 42 | { 43 | $errorHandler = App::make('Schickling\QueueChecker\ErrorHandlers\ErrorHandlerInterface'); 44 | $errorHandler->handle(Errors::NOT_CONNECTED, 'Queue is not connected.'); 45 | } 46 | 47 | } 48 | 49 | private function checkIfCacheWasInitialized() 50 | { 51 | if ( ! Cache::has('queue-checker-job-value')) 52 | { 53 | Cache::put('queue-checker-job-value', 0, 60); 54 | } 55 | 56 | if ( ! Cache::has('queue-checker-command-value')) 57 | { 58 | Cache::put('queue-checker-command-value', 0, 60); 59 | } 60 | } 61 | 62 | } -------------------------------------------------------------------------------- /src/Schickling/QueueChecker/Commands/QueueCheckerResetCommand.php: -------------------------------------------------------------------------------- 1 | delete(); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/Schickling/QueueChecker/QueueCheckerServiceProvider.php: -------------------------------------------------------------------------------- 1 | app->bind('Schickling\QueueChecker\ErrorHandlers\ErrorHandlerInterface', 'Schickling\QueueChecker\ErrorHandlers\LogErrorHandler'); 16 | 17 | 18 | $this->app['queue.check'] = $this->app->share(function($app) 19 | { 20 | return new Commands\QueueCheckerCommand(); 21 | }); 22 | 23 | $this->app['queue.reset-check'] = $this->app->share(function($app) 24 | { 25 | return new Commands\QueueCheckerResetCommand(); 26 | }); 27 | 28 | $this->commands( 29 | 'queue.check', 30 | 'queue.reset-check' 31 | ); 32 | } 33 | 34 | } -------------------------------------------------------------------------------- /tests/Commands/QueueCheckerCommandTest.php: -------------------------------------------------------------------------------- 1 | tester = new CommandTester($command); 23 | } 24 | 25 | public function tearDown() 26 | { 27 | m::close(); 28 | } 29 | 30 | public function testFailsForNotRunningQueue() 31 | { 32 | $errorHandlerMock = m::mock('Schickling\QueueChecker\ErrorHandlers\ErrorHandlerInterface'); 33 | $errorHandlerMock->shouldReceive('handle'); 34 | $this->app->instance('Schickling\QueueChecker\ErrorHandlers\ErrorHandlerInterface', $errorHandlerMock); 35 | 36 | Queue::shouldReceive('connected')->once()->andReturn(false); 37 | 38 | $this->tester->execute(array()); 39 | } 40 | 41 | public function testJobPushedToQueue() 42 | { 43 | Queue::shouldReceive('push')->with('Schickling\QueueChecker\Jobs\QueueCheckerJob', ['jobValue' => 1])->once(); 44 | Queue::shouldReceive('connected')->once()->andReturn(true); 45 | 46 | $this->tester->execute(array()); 47 | } 48 | 49 | public function testCacheGetsInitialized() 50 | { 51 | Queue::shouldReceive('push')->with('Schickling\QueueChecker\Jobs\QueueCheckerJob', ['jobValue' => 1])->once(); 52 | Queue::shouldReceive('connected')->once()->andReturn(true); 53 | 54 | $this->tester->execute(array()); 55 | 56 | $this->assertEquals(1, Cache::get('queue-checker-command-value')); 57 | $this->assertEquals(0, Cache::get('queue-checker-job-value')); 58 | } 59 | 60 | public function testQueueIncreaseValue() 61 | { 62 | Cache::put('queue-checker-command-value', 2, 0); 63 | Cache::put('queue-checker-job-value', 2, 0); 64 | Queue::shouldReceive('push')->with('Schickling\QueueChecker\Jobs\QueueCheckerJob', ['jobValue' => 3])->once(); 65 | Queue::shouldReceive('connected')->once()->andReturn(true); 66 | 67 | $this->tester->execute(array()); 68 | 69 | $this->assertEquals(3, Cache::get('queue-checker-command-value')); 70 | $this->assertEquals(2, Cache::get('queue-checker-job-value')); 71 | } 72 | 73 | public function testQueueIncreaseValueCyclic() 74 | { 75 | Cache::put('queue-checker-command-value', 999999, 0); 76 | Cache::put('queue-checker-job-value', 999999, 0); 77 | Queue::shouldReceive('push')->with('Schickling\QueueChecker\Jobs\QueueCheckerJob', ['jobValue' => 0])->once(); 78 | Queue::shouldReceive('connected')->once()->andReturn(true); 79 | 80 | $this->tester->execute(array()); 81 | 82 | $this->assertEquals(0, Cache::get('queue-checker-command-value')); 83 | $this->assertEquals(999999, Cache::get('queue-checker-job-value')); 84 | } 85 | 86 | public function testErrorHandlingWhenJobValueBiggerAsCommandValue() 87 | { 88 | $errorHandlerMock = m::mock('Schickling\QueueChecker\ErrorHandlers\ErrorHandlerInterface'); 89 | $errorHandlerMock->shouldReceive('handle'); 90 | $this->app->instance('Schickling\QueueChecker\ErrorHandlers\ErrorHandlerInterface', $errorHandlerMock); 91 | 92 | Cache::put('queue-checker-command-value', 2, 0); 93 | Cache::put('queue-checker-job-value', 3, 0); 94 | 95 | Queue::shouldReceive('connected')->once()->andReturn(true); 96 | 97 | $this->tester->execute(array()); 98 | } 99 | 100 | public function testErrorHandlingWhenCommandValueBiggerAsJobValue() 101 | { 102 | $errorHandlerMock = m::mock('Schickling\QueueChecker\ErrorHandlers\ErrorHandlerInterface'); 103 | $errorHandlerMock->shouldReceive('handle'); 104 | $this->app->instance('Schickling\QueueChecker\ErrorHandlers\ErrorHandlerInterface', $errorHandlerMock); 105 | 106 | Cache::put('queue-checker-command-value', 3, 0); 107 | Cache::put('queue-checker-job-value', 2, 0); 108 | 109 | Queue::shouldReceive('connected')->once()->andReturn(true); 110 | 111 | $this->tester->execute(array()); 112 | } 113 | 114 | } -------------------------------------------------------------------------------- /tests/Commands/QueueCheckerResetCommandTest.php: -------------------------------------------------------------------------------- 1 | tester = new CommandTester($command); 22 | } 23 | 24 | public function testResetQueueCheckValues() 25 | { 26 | $this->tester->execute(array()); 27 | 28 | $this->assertEquals(0, Cache::get('queue-checker-command-value')); 29 | $this->assertEquals(0, Cache::get('queue-checker-job-value')); 30 | } 31 | 32 | 33 | 34 | } -------------------------------------------------------------------------------- /tests/ErrorHandlers/LogErrorHandlerTest.php: -------------------------------------------------------------------------------- 1 | with('Error Code: 0. Message: test message')->once(); 21 | 22 | $logErrorHandler->handle(Errors::NOT_WORKING, 'test message'); 23 | } 24 | 25 | 26 | } -------------------------------------------------------------------------------- /tests/Jobs/QueueCheckerJobTest.php: -------------------------------------------------------------------------------- 1 | queueCheckerJob = new QueueCheckerJob(); 18 | 19 | $this->taskMock = m::mock(); 20 | $this->taskMock->shouldReceive('delete'); 21 | } 22 | 23 | public function tearDown() 24 | { 25 | m::close(); 26 | } 27 | 28 | public function testJobIncreaseValue() 29 | { 30 | Cache::put('queue-checker-job-value', 0, 0); 31 | 32 | $this->queueCheckerJob->fire($this->taskMock, ['jobValue' => 1]); 33 | 34 | $this->assertEquals(1, Cache::get('queue-checker-job-value')); 35 | } 36 | 37 | 38 | } --------------------------------------------------------------------------------