Dashboard and code-driven configuration for Laravel queues.

Overview

Build Status Total Downloads Latest Stable Version License

Introduction

Horizon provides a beautiful dashboard and code-driven configuration for your Laravel powered Redis queues. Horizon allows you to easily monitor key metrics of your queue system such as job throughput, runtime, and job failures.

All of your worker configuration is stored in a single, simple configuration file, allowing your configuration to stay in source control where your entire team can collaborate.

Official Documentation

Documentation for Horizon can be found on the Laravel website.

Contributing

Thank you for considering contributing to Horizon! The contribution guide can be found in the Laravel documentation.

Code of Conduct

In order to ensure that the Laravel community is welcoming to all, please review and abide by the Code of Conduct.

Security Vulnerabilities

Please review our security policy on how to report security vulnerabilities.

License

Laravel Horizon is open-sourced software licensed under the MIT license.

Comments
  • Horizon Orphan Process

    Horizon Orphan Process

    I'm running horizon on a latest forge machine as documented... the daemon with php artisan horizon and on deployments php artisan horizon:terminate but time to time i need to manually run php artisan horizon:purge.

    This is the output i just got after after hours of last release:

    $ php artisan horizon:purge
    Observed Orphan: 17043
    Observed Orphan: 30634
    Observed Orphan: 31084
    Observed Orphan: 31085
    

    I can confirm it's orphans by running htop on tree mode (press f5) and i see these process as root process, not inside the master php artisan horizon process.


    And also, every time i run purge, it ALWAYS wrongly see 1 process as orphan:

    $ php artisan horizon:purge
    Observed Orphan: 17059
    

    I haven't found a pattern yet why this is happening.

    opened by dbpolito 59
  • Reconnecting to redis (after short unavailability), not working with password protected redis instance

    Reconnecting to redis (after short unavailability), not working with password protected redis instance

    • Horizon Version: v3.4.4
    • Laravel Version: v6.9.0
    • PHP Version: 7.4.0
    • Redis Driver & Version: phpredis 5.1.1

    Description:

    This issue has been haunting us a long time now. Initially we did not know why this was randomly happening (Issue #708 ) later we found out that the re-connecting in general was not working (Issue #716 ) which was fixed by taylor (thank you!) but this only is now working correctly for redis instances that are not password protected.

    In a situation where horizon is running against a redis instances that is password protected, and redis is shortly (or long) unavailable, even after redis is back, horizon will not recover spitting out NOAUTH errors like this one:

    ERROR: NOAUTH Authentication required. {"exception":"[object] (RedisException(code: 0): NOAUTH Authentication required. at /var/www/vendor/laravel/framework/src/Illuminate/Redis/Connections/Connection.php:111)
    [stacktrace]
    #0 /var/www/vendor/laravel/framework/src/Illuminate/Redis/Connections/Connection.php(111): Redis->lLen('commands:master...')
    #1 /var/www/vendor/laravel/framework/src/Illuminate/Redis/Connections/PhpRedisConnection.php(440): Illuminate\\Redis\\Connections\\Connection->command('llen', Array)
    #2 /var/www/vendor/laravel/framework/src/Illuminate/Redis/Connections/Connection.php(211): Illuminate\\Redis\\Connections\\PhpRedisConnection->command('llen', Array)
    #3 /var/www/vendor/laravel/framework/src/Illuminate/Redis/Connections/PhpRedisConnection.php(482): Illuminate\\Redis\\Connections\\Connection->__call('llen', Array)
    #4 /var/www/vendor/laravel/horizon/src/RedisHorizonCommandQueue.php(51): Illuminate\\Redis\\Connections\\PhpRedisConnection->__call('llen', Array)
    #5 /var/www/vendor/laravel/horizon/src/MasterSupervisor.php(263): Laravel\\Horizon\\RedisHorizonCommandQueue->pending('master:d4711be9...')
    #6 /var/www/vendor/laravel/horizon/src/MasterSupervisor.php(240): Laravel\\Horizon\\MasterSupervisor->processPendingCommands()
    #7 /var/www/vendor/laravel/horizon/src/MasterSupervisor.php(213): Laravel\\Horizon\\MasterSupervisor->loop()
    #8 /var/www/vendor/laravel/horizon/src/Console/HorizonCommand.php(63): Laravel\\Horizon\\MasterSupervisor->monitor()
    #9 [internal function]: Laravel\\Horizon\\Console\\HorizonCommand->handle(Object(Laravel\\Horizon\\Repositories\\RedisMasterSupervisorRepository))
    #10 /var/www/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(32): call_user_func_array(Array, Array)
    #11 /var/www/vendor/laravel/framework/src/Illuminate/Container/Util.php(36): Illuminate\\Container\\BoundMethod::Illuminate\\Container\\{closure}()
    #12 /var/www/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(90): Illuminate\\Container\\Util::unwrapIfClosure(Object(Closure))
    #13 /var/www/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(34): Illuminate\\Container\\BoundMethod::callBoundMethod(Object(App\\Extensions\\Illuminate\\Foundation\\Application), Array, Object(Closure))
    #14 /var/www/vendor/laravel/framework/src/Illuminate/Container/Container.php(590): Illuminate\\Container\\BoundMethod::call(Object(App\\Extensions\\Illuminate\\Foundation\\Application), Array, Array, NULL)
    #15 /var/www/vendor/laravel/framework/src/Illuminate/Console/Command.php(202): Illuminate\\Container\\Container->call(Array)
    #16 /var/www/vendor/symfony/console/Command/Command.php(255): Illuminate\\Console\\Command->execute(Object(Symfony\\Component\\Console\\Input\\ArgvInput), Object(Illuminate\\Console\\OutputStyle))
    #17 /var/www/vendor/laravel/framework/src/Illuminate/Console/Command.php(189): Symfony\\Component\\Console\\Command\\Command->run(Object(Symfony\\Component\\Console\\Input\\ArgvInput), Object(Illuminate\\Console\\OutputStyle))
    #18 /var/www/vendor/symfony/console/Application.php(1011): Illuminate\\Console\\Command->run(Object(Symfony\\Component\\Console\\Input\\ArgvInput), Object(Symfony\\Component\\Console\\Output\\ConsoleOutput))
    #19 /var/www/vendor/symfony/console/Application.php(272): Symfony\\Component\\Console\\Application->doRunCommand(Object(Laravel\\Horizon\\Console\\HorizonCommand), Object(Symfony\\Component\\Console\\Input\\ArgvInput), Object(Symfony\\Component\\Console\\Output\\ConsoleOutput))
    #20 /var/www/vendor/symfony/console/Application.php(148): Symfony\\Component\\Console\\Application->doRun(Object(Symfony\\Component\\Console\\Input\\ArgvInput), Object(Symfony\\Component\\Console\\Output\\ConsoleOutput))
    #21 /var/www/vendor/laravel/framework/src/Illuminate/Console/Application.php(93): Symfony\\Component\\Console\\Application->run(Object(Symfony\\Component\\Console\\Input\\ArgvInput), Object(Symfony\\Component\\Console\\Output\\ConsoleOutput))
    #22 /var/www/vendor/laravel/framework/src/Illuminate/Foundation/Console/Kernel.php(131): Illuminate\\Console\\Application->run(Object(Symfony\\Component\\Console\\Input\\ArgvInput), Object(Symfony\\Component\\Console\\Output\\ConsoleOutput))
    #23 /var/www/artisan(37): Illuminate\\Foundation\\Console\\Kernel->handle(Object(Symfony\\Component\\Console\\Input\\ArgvInput), Object(Symfony\\Component\\Console\\Output\\ConsoleOutput))
    #24 {main}
    

    Important. This ONLY happens with the phpredis driver, predis is not affected.

    Steps To Reproduce:

    • Have a fresh (or not fresh) laravel installation with horizon.
    • Have a redis instance that is password protected (for example running it from this dockerfile)
    • configure your database.php in laravel accordingly to have correct redis password set
    FROM redis:5.0.2
    COPY redis.conf /usr/local/etc/redis/redis.conf
    CMD [ "redis-server", "/usr/local/etc/redis/redis.conf" ]
    

    where the redis.conf looks like this

    requirepass testpassword
    
    • Then start horizon, let it warm up
    • turn off your redis instance or break the connection between horizon & redis somehow.
    • turn on redis instance again (or enable connection between horizon & redis again)
    • horizon will continuously spit out errors as specified above (NOAUTH)
    bug help wanted 
    opened by graemlourens 40
  • Multiple horizon instances on one server not working

    Multiple horizon instances on one server not working

    I have a server with 4 horizon instances (all running under another prefix), Job insertion always goes to the right horizon instance, but it is like a lottery which worker handles the job, which is really confusing to work with.

    opened by johannessmit 40
  • Jobs seems to be picked up by multiple worker

    Jobs seems to be picked up by multiple worker

    I am running horizon on horizontal scale setup with multiple server running a same instance. I found that once in a while there are jobs that's being processed multiple times and somehow passed my constraint checking.

    I suspect this could be cause by that job being processed by multiple workers at the same time, hence it manage to pass the constraint check I have on the job handle() function.

    So my question, is horizon are fully compatible to run on horizontal scaling setup?

    opened by azrulamir 37
  • Jobs get processed multiple times

    Jobs get processed multiple times

    I have a job that gets dispatched to a queue inside a supervisor that has 20 workers assigned to it to handle large concurrency. There seems to be an issue (race condition maybe?) whereby a single dispatched job gets picked up by multiple horizon workers and processed multiple times. This causes problems because the job can only be processed once or it will fail.

    I added a bunch of info logs in various places, including the job itself, the code that dispatches the job, and Repositories/RedisJobRepository.php inside Horizon. Here is what I found.

    First the logs:

    1. "dispatching job" right before the call to dispatch(new MyJob())
    2. "enter job constructor" inside the job's constructor
    3. "executing job " inside the job's execute method
    4. "returning from job " at the very end of the job's execute method
    5. "reserving job " inside RedisJobRepository::reserved
    6. "completed job " inside RedisJobRepository::completed

    Then the output:

    [2017-10-17 20:15:38] pre.INFO: dispatching job
    [2017-10-17 20:15:38] pre.INFO: enter job constructor 27262
    [2017-10-17 20:15:38] pre.INFO: reserving job 202 3316
    [2017-10-17 20:15:38] pre.INFO: executing job 3316
    [2017-10-17 20:15:43] pre.INFO: reserving job 202 3307
    [2017-10-17 20:15:43] pre.INFO: executing job 3307
    [2017-10-17 20:15:45] pre.INFO: returning from job 3316
    [2017-10-17 20:15:45] pre.INFO: completed job 202 3316
    [2017-10-17 20:15:48] pre.INFO: reserving job 202 3323
    [2017-10-17 20:15:48] pre.INFO: executing job 3323
    [2017-10-17 20:15:48] pre.INFO: completed job 202 3323
    [2017-10-17 20:15:48] pre.ERROR: <exception thrown from job because it already ran>
    [2017-10-17 20:15:50] pre.INFO: returning from job 3307
    [2017-10-17 20:15:50] pre.INFO: completed job 202 3307
    

    Note that only a single job was constructed and dispatched, but the same job got reserved 3 times by 3 different horizon workers, and executed 3 times. I'm not quite sure how 2 jobs managed to succeed while the 3rd one failed; according to the code, it is supposed to clean up a temp file that is required in the job, but perhaps the jobs from processes 3316 and 3307 both managed to load the file for processing before one or the other deleted it.

    The above output is quite consistent and reproducible, obviously with different ids each time. I tried to set 'tries' => 1 in my horizon config for this supervisor and ended up with a different set of consistently reproducible logs:

    [2017-10-17 20:20:55] pre.INFO: dispatching job  
    [2017-10-17 20:20:55] pre.INFO: enter job constructor 28229  
    [2017-10-17 20:20:55] pre.INFO: reserving job 204 4358  
    [2017-10-17 20:20:55] pre.INFO: executing job 4358  
    [2017-10-17 20:21:00] pre.INFO: reserving job 204 4369  
    [2017-10-17 20:21:00] pre.INFO: completed job 204 4369  
    [2017-10-17 20:21:01] pre.ERROR: A queued job has been attempted too many times or run too long. The job may have previously timed out. {"exception":"[object] (Illuminate\\Queue\\MaxAttemptsExceededException(code: 0): A queued job has been attempted too many times or run too long. The job may have previously timed out. at /opt/www/pre/site/vendor/laravel/framework/src/Illuminate/Queue/Worker.php:394)
    [2017-10-17 20:21:02] pre.INFO: returning from job 4358  
    [2017-10-17 20:21:02] pre.INFO: completed job 204 4358
    

    Now, it only reserves the job twice on two workers, and instead of getting my "file not found" exception inside the job, it throws the MaxAttemptsExceededException.

    I would be happy to try anything and provide more details as needed!

    Laravel: 5.5.14 Horizon: 1.0.4

    Horizon supervisor config:

                'high-concurrency' => [
                    'connection' => 'redis',
                    'queue' => ['a', 'bunch', 'of', 'queues''],
                    'balance' => 'false',
                    'processes' => 20, 
                    'tries' => 1, // or 3
                    'timeout' => 300,
                ],
    

    config/queue.php:

            'redis' => [
                'driver' => 'redis',
                'connection' => 'default',
                'queue'  => env('REDIS_QUEUE', 'default'), // set to "pre"
                'retry_after' => 5,
            ],
    

    config/database.php:

        'redis' => [
    
            'client' => 'predis',
    
            'default' => [
                'host' => env('REDIS_HOST', 'localhost'),
                'password' => env('REDIS_PASSWORD', null),
                'port' => env('REDIS_PORT', 6379),
                'database' => env('REDIS_DATABASE', 0), // not set in the .env
            ],
    
        ],
    
    opened by elynnaie 35
  • Trying to access array offset on value of type null

    Trying to access array offset on value of type null

    • Horizon Version: 5.4.0
    • Laravel Version: 8.13.0
    • PHP Version: 7.4.3
    • Redis Driver & Version: phpredis 5.3.0
    • Database Driver & Version: MySQL 8.0.22

    Description:

    Horizon is working nicely for few days, and next I woke up in the morning and see all my Jobs are failed. When I check the logs, I got these:

    [2020-11-09 10:27:37] production.ERROR: Trying to access array offset on value of type null {"exception":"[object] (ErrorException(code: 0): Trying to access array offset on value of type null at /var/www/laravel-api/production/vendor/laravel/horizon/src/JobPayload.php:48)
    [stacktrace]
    #0 /var/www/laravel-api/production/vendor/laravel/horizon/src/JobPayload.php(48): Illuminate\\Foundation\\Bootstrap\\HandleExceptions->handleError()
    #1 /var/www/laravel-api/production/vendor/laravel/horizon/src/Repositories/RedisJobRepository.php(428): Laravel\\Horizon\\JobPayload->id()
    #2 /var/www/laravel-api/production/vendor/laravel/framework/src/Illuminate/Support/helpers.php(263): Laravel\\Horizon\\Repositories\\RedisJobRepository->Laravel\\Horizon\\Repositories\\{closure}()
    #3 /var/www/laravel-api/production/vendor/laravel/framework/src/Illuminate/Redis/Connections/PhpRedisConnection.php(406): tap()
    #4 /var/www/laravel-api/production/vendor/laravel/horizon/src/Repositories/RedisJobRepository.php(435): Illuminate\\Redis\\Connections\\PhpRedisConnection->pipeline()
    #5 /var/www/laravel-api/production/vendor/laravel/horizon/src/Listeners/MarkJobsAsMigrated.php(36): Laravel\\Horizon\\Repositories\\RedisJobRepository->migrated()
    #6 /var/www/laravel-api/production/vendor/laravel/framework/src/Illuminate/Events/Dispatcher.php(411): Laravel\\Horizon\\Listeners\\MarkJobsAsMigrated->handle()
    #7 /var/www/laravel-api/production/vendor/laravel/framework/src/Illuminate/Events/Dispatcher.php(236): Illuminate\\Events\\Dispatcher->Illuminate\\Events\\{closure}()
    #8 /var/www/laravel-api/production/vendor/laravel/horizon/src/RedisQueue.php(174): Illuminate\\Events\\Dispatcher->dispatch()
    #9 /var/www/laravel-api/production/vendor/laravel/horizon/src/RedisQueue.php(128): Laravel\\Horizon\\RedisQueue->event()
    #10 /var/www/laravel-api/production/vendor/laravel/framework/src/Illuminate/Support/helpers.php(263): Laravel\\Horizon\\RedisQueue->Laravel\\Horizon\\{closure}()
    #11 /var/www/laravel-api/production/vendor/laravel/horizon/src/RedisQueue.php(129): tap()
    #12 /var/www/laravel-api/production/vendor/laravel/framework/src/Illuminate/Queue/RedisQueue.php(211): Laravel\\Horizon\\RedisQueue->migrateExpiredJobs()
    #13 /var/www/laravel-api/production/vendor/laravel/framework/src/Illuminate/Queue/RedisQueue.php(187): Illuminate\\Queue\\RedisQueue->migrate()
    #14 /var/www/laravel-api/production/vendor/laravel/horizon/src/RedisQueue.php(111): Illuminate\\Queue\\RedisQueue->pop()
    #15 /var/www/laravel-api/production/vendor/laravel/framework/src/Illuminate/Queue/Worker.php(323): Laravel\\Horizon\\RedisQueue->pop()
    #16 /var/www/laravel-api/production/vendor/laravel/framework/src/Illuminate/Queue/Worker.php(332): Illuminate\\Queue\\Worker->Illuminate\\Queue\\{closure}()
    #17 /var/www/laravel-api/production/vendor/laravel/framework/src/Illuminate/Queue/Worker.php(145): Illuminate\\Queue\\Worker->getNextJob()
    #18 /var/www/laravel-api/production/vendor/laravel/framework/src/Illuminate/Queue/Console/WorkCommand.php(116): Illuminate\\Queue\\Worker->daemon()
    #19 /var/www/laravel-api/production/vendor/laravel/framework/src/Illuminate/Queue/Console/WorkCommand.php(100): Illuminate\\Queue\\Console\\WorkCommand->runWorker()
    #20 /var/www/laravel-api/production/vendor/laravel/horizon/src/Console/WorkCommand.php(50): Illuminate\\Queue\\Console\\WorkCommand->handle()
    #21 /var/www/laravel-api/production/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(36): Laravel\\Horizon\\Console\\WorkCommand->handle()
    #22 /var/www/laravel-api/production/vendor/laravel/framework/src/Illuminate/Container/Util.php(40): Illuminate\\Container\\BoundMethod::Illuminate\\Container\\{closure}()
    #23 /var/www/laravel-api/production/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(93): Illuminate\\Container\\Util::unwrapIfClosure()
    #24 /var/www/laravel-api/production/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(37): Illuminate\\Container\\BoundMethod::callBoundMethod()
    #25 /var/www/laravel-api/production/vendor/laravel/framework/src/Illuminate/Container/Container.php(596): Illuminate\\Container\\BoundMethod::call()
    #26 /var/www/laravel-api/production/vendor/laravel/framework/src/Illuminate/Console/Command.php(136): Illuminate\\Container\\Container->call()
    #27 /var/www/laravel-api/production/vendor/symfony/console/Command/Command.php(258): Illuminate\\Console\\Command->execute()
    #28 /var/www/laravel-api/production/vendor/laravel/framework/src/Illuminate/Console/Command.php(121): Symfony\\Component\\Console\\Command\\Command->run()
    #29 /var/www/laravel-api/production/vendor/symfony/console/Application.php(920): Illuminate\\Console\\Command->run()
    #30 /var/www/laravel-api/production/vendor/symfony/console/Application.php(266): Symfony\\Component\\Console\\Application->doRunCommand()
    #31 /var/www/laravel-api/production/vendor/symfony/console/Application.php(142): Symfony\\Component\\Console\\Application->doRun()
    #32 /var/www/laravel-api/production/vendor/laravel/framework/src/Illuminate/Console/Application.php(93): Symfony\\Component\\Console\\Application->run()
    #33 /var/www/laravel-api/production/vendor/laravel/framework/src/Illuminate/Foundation/Console/Kernel.php(129): Illuminate\\Console\\Application->run()
    #34 /var/www/laravel-api/production/artisan(37): Illuminate\\Foundation\\Console\\Kernel->handle()
    #35 {main}
    
    [2020-11-09 10:27:38] production.ERROR: Undefined offset: 1 {"exception":"[object] (ErrorException(code: 0): Undefined offset: 1 at /var/www/laravel-api/production/vendor/laravel/framework/src/Illuminate/Queue/RedisQueue.php:250)
    [stacktrace]
    #0 /var/www/laravel-api/production/vendor/laravel/framework/src/Illuminate/Queue/RedisQueue.php(250): Illuminate\\Foundation\\Bootstrap\\HandleExceptions->handleError()
    #1 /var/www/laravel-api/production/vendor/laravel/framework/src/Illuminate/Queue/RedisQueue.php(189): Illuminate\\Queue\\RedisQueue->retrieveNextJob()
    #2 /var/www/laravel-api/production/vendor/laravel/horizon/src/RedisQueue.php(111): Illuminate\\Queue\\RedisQueue->pop()
    #3 /var/www/laravel-api/production/vendor/laravel/framework/src/Illuminate/Queue/Worker.php(323): Laravel\\Horizon\\RedisQueue->pop()
    #4 /var/www/laravel-api/production/vendor/laravel/framework/src/Illuminate/Queue/Worker.php(332): Illuminate\\Queue\\Worker->Illuminate\\Queue\\{closure}()
    #5 /var/www/laravel-api/production/vendor/laravel/framework/src/Illuminate/Queue/Worker.php(145): Illuminate\\Queue\\Worker->getNextJob()
    #6 /var/www/laravel-api/production/vendor/laravel/framework/src/Illuminate/Queue/Console/WorkCommand.php(116): Illuminate\\Queue\\Worker->daemon()
    #7 /var/www/laravel-api/production/vendor/laravel/framework/src/Illuminate/Queue/Console/WorkCommand.php(100): Illuminate\\Queue\\Console\\WorkCommand->runWorker()
    #8 /var/www/laravel-api/production/vendor/laravel/horizon/src/Console/WorkCommand.php(50): Illuminate\\Queue\\Console\\WorkCommand->handle()
    #9 /var/www/laravel-api/production/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(36): Laravel\\Horizon\\Console\\WorkCommand->handle()
    #10 /var/www/laravel-api/production/vendor/laravel/framework/src/Illuminate/Container/Util.php(40): Illuminate\\Container\\BoundMethod::Illuminate\\Container\\{closure}()
    #11 /var/www/laravel-api/production/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(93): Illuminate\\Container\\Util::unwrapIfClosure()
    #12 /var/www/laravel-api/production/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(37): Illuminate\\Container\\BoundMethod::callBoundMethod()
    #13 /var/www/laravel-api/production/vendor/laravel/framework/src/Illuminate/Container/Container.php(596): Illuminate\\Container\\BoundMethod::call()
    #14 /var/www/laravel-api/production/vendor/laravel/framework/src/Illuminate/Console/Command.php(136): Illuminate\\Container\\Container->call()
    #15 /var/www/laravel-api/production/vendor/symfony/console/Command/Command.php(258): Illuminate\\Console\\Command->execute()
    #16 /var/www/laravel-api/production/vendor/laravel/framework/src/Illuminate/Console/Command.php(121): Symfony\\Component\\Console\\Command\\Command->run()
    #17 /var/www/laravel-api/production/vendor/symfony/console/Application.php(920): Illuminate\\Console\\Command->run()
    #18 /var/www/laravel-api/production/vendor/symfony/console/Application.php(266): Symfony\\Component\\Console\\Application->doRunCommand()
    #19 /var/www/laravel-api/production/vendor/symfony/console/Application.php(142): Symfony\\Component\\Console\\Application->doRun()
    #20 /var/www/laravel-api/production/vendor/laravel/framework/src/Illuminate/Console/Application.php(93): Symfony\\Component\\Console\\Application->run()
    #21 /var/www/laravel-api/production/vendor/laravel/framework/src/Illuminate/Foundation/Console/Kernel.php(129): Illuminate\\Console\\Application->run()
    #22 /var/www/laravel-api/production/artisan(37): Illuminate\\Foundation\\Console\\Kernel->handle()
    #23 {main}
    "} 
    

    config/horizon.php:

    <?php
    
    use Illuminate\Support\Str;
    
    return [
        'domain' => null,
        'path' => 'admin/horizon',
        'use' => 'default',
        'prefix' => env(
            'HORIZON_PREFIX',
            Str::slug(env('APP_NAME', 'laravel'), '_').'@'.env('APP_ENV').'_horizon:'
        ),
        'middleware' => ['web'],
        'waits' => [
            'redis:default' => 60,
        ],
        'trim' => [
            'recent' => 60,
            'pending' => 60,
            'completed' => 60,
            'recent_failed' => 10080,
            'failed' => 10080,
            'monitored' => 10080,
        ],
        'metrics' => [
            'trim_snapshots' => [
                'job' => 24,
                'queue' => 24,
            ],
        ],
        'fast_termination' => false,
        'memory_limit' => 64,
        'environments' => [
            'production' => [
                'supervisor-1' => [
                    'connection' => 'redis',
                    'queue' => ['default'],
                    'balance' => 'simple',
                    'processes' => 10,
                    'tries' => 1,
                    'timeout' => 600,
                ],
                'scrapper' => [
                    'connection' => 'redis',
                    'queue' => ['price'],
                    'balance' => 'simple',
                    'processes' => 1,
                    'tries' => 1,
                    'timeout' => 600,
                ],
                'scout' => [
                    'connection' => 'redis',
                    'queue' => ['scout'],
                    'balance' => 'simple',
                    'processes' => 1,
                    'tries' => 3,
                    'timeout' => 600,
                ],
            ],
    
            'development' => [
                'supervisor-1' => [
                    'connection' => 'redis',
                    'queue' => ['default'],
                    'balance' => 'simple',
                    'processes' => 2,
                    'tries' => 1,
                    'timeout' => 600,
                ],
                'scrapper' => [
                    'connection' => 'redis',
                    'queue' => ['price'],
                    'balance' => 'simple',
                    'processes' => 1,
                    'tries' => 1,
                    'timeout' => 600,
                ],
                'scout' => [
                    'connection' => 'redis',
                    'queue' => ['scout'],
                    'balance' => 'simple',
                    'processes' => 1,
                    'tries' => 1,
                    'timeout' => 600,
                ],
            ],
    
            'local' => [
                'supervisor-1' => [
                    'connection' => 'redis',
                    'queue' => ['default'],
                    'balance' => 'simple',
                    'processes' => 2,
                    'tries' => 1,
                ],
                'scrapper' => [
                    'connection' => 'redis',
                    'queue' => ['price'],
                    'balance' => 'simple',
                    'processes' => 1,
                    'tries' => 1,
                ],
                'scout' => [
                    'connection' => 'redis',
                    'queue' => ['scout'],
                    'balance' => 'simple',
                    'processes' => 1,
                    'tries' => 3,
                ],
            ],
        ],
    ];
    
    

    I had also this error on Laravel 7 / Horizon 4, so I upgrated to Laravel 8 / Horizon 5 with the hope that this error will disappear, in vain.

    needs more info 
    opened by dimzeta 33
  • Jobs marked as failed even if they are running correctly

    Jobs marked as failed even if they are running correctly

    I have a few queue jobs that needs some time to be run because they are encoding videos. They typically last a couple minutes.

    When I fire the job, it runs correctly and I can see that it's being executed in the "Recent Jobs" section of Horizon. I can see it running, then it gets a red cross icon as if it failed, and then immediately after it becomes green marking it as completed. The problem is that I can see it also in the "Failed" section, where it says that the job has failed throwing a "Illuminate\Queue\MaxAttemptsExceededException".

    At the moment I have 2 processes for the queue. If I set it to just 1 process, then the problem is not happening anymore.

    I also tried setting the "timeout" property for the job to 1800 seconds, but it looks like it doesn't care.

    Could it be that if I have 2 processes the second one tries to run the job even if the first one is still running it? Is there something I need to consider for especially long jobs? I have another queue with 10 processes running small tasks and that is not giving any problem at all.

    Thanks a lot for your help and congrats for the amazing library!!!

    opened by crash13override 33
  • Horizon wrong time displayed, errors in log for completed job and ignoring memory restrictions for hard tasks

    Horizon wrong time displayed, errors in log for completed job and ignoring memory restrictions for hard tasks

    • Horizon Version: 3.4.3
    • Laravel Version: 6.6.0
    • PHP Version: 7.2.24
    • Redis Driver & Version: phpredis 5.1.1
    • Database Driver & Version: mysql

    Description:

    When running

    Steps To Reproduce:

    • Create a job that needs more than 60 seconds and to run and uses a lot of memory (I generated 3,000,000 unique strings using $faker->unique()->regexify() for the sake of testing). I'll attach the job file.
    • (Re)start horizon
    • Queue the job

    What happens:

    • Despite the memory limit being specified as 64MB in config/horizon.php the worker threads are started with the option --memory=128 which is also ignored and the processes are allowed to consume nearly a whole gigabyte of resident memory without failing

    • Despite the job completing without issue, Laravel logs an exception (local.ERROR: ... attempted too many times or run too long. The job may have previously timed out. {"exception":"[object] (Illuminate\Queue\MaxAttemptsExceededException(code: 0): App\Jobs\SendOrderEmail ... at /work/jsong/vendor/laravel/framework/src/Illuminate/Queue/Worker.php:612...)

    • A job that took 1 minute and 36 seconds to complete is displayed in the horizon recent jobs list as having taken 3.63 seconds. Another that took 1m32s displays as 0.68s. Another that also took 1m32s displays as 0.18s.

    Looking at the timing of the exceptions and when the job was completed it seems that Horizon is logging the difference between when the exception was thrown and when the job was completed. I thought that perhaps this is more of a laravel issue than a horizon issue. But when I work the queue manually with php artisan queue:work or php artisan queue:work --deamon the exception is not thrown and the horizon interface reports time correctly

    SendOrderEmail.php.txt

    enhancement 
    opened by kaan-atakan 30
  • Database driver support

    Database driver support

    I know Horizon currently does not support the Database driver and that there are currently no plans for this. But are you open to a PR to add this? In that case, I would consider creating a proof-of-concept for the database.

    I can get Horizon working fine, by just adding the readyNow method to the driver, but would probably need to invest some more time for the actual jobs to show up.

    (Yes I know Redis is probably better, but I have a use-case with extra filtering using relations in the jobs which I can't really do with Redis)

    enhancement 
    opened by barryvdh 30
  • Delayed at is Wrong

    Delayed at is Wrong

    • Horizon Version: 3.7.1
    • Laravel Version: 5.8
    • PHP Version: 7.3
    • Redis Driver & Version: predis 5.2
    • Database Driver & Version: Mysql8.0

    Description:

    When we hover the mouse on a delayed tag to a delayed job, and when we click to see the detail of the job, the "Delayed Until" time is wrong.

    • Redis time is ok
    • Host time is ok
    • Laravel timezone is ok

    Steps To Reproduce:

    Launch job Go to horizon and check

    Screen : https://anopetia.tinytake.com/tt/NDA3NTQ4Nl8xMjUzNTMxMw

    needs more info 
    opened by Perh0rd 26
  • stats and metrics don't work at all

    stats and metrics don't work at all

    I'm using Horizon on multiple projects, I had to make them play nice so they all work side-by-side

    Perhaps as a result of this, I've never been able to get any of them to display proper stats. I have a cron job running that triggers the snapshot every 5 minutes.

    The metrics are empty: screenshot 2017-10-08 04 51 02

    The dashboard shows no data for most of the fields, on top of that I know the number of queued jobs to be way off

    screenshot 2017-10-08 04 50 40

    Even odder! There's nothing showing in the Recent Jobs.. even though it's processing ~20 jobs per minute for hours now

    What could be causing all this?

    opened by vesper8 26
  • Bump json5 from 1.0.1 to 1.0.2

    Bump json5 from 1.0.1 to 1.0.2

    Bumps json5 from 1.0.1 to 1.0.2.

    Release notes

    Sourced from json5's releases.

    v1.0.2

    • Fix: Properties with the name __proto__ are added to objects and arrays. (#199) This also fixes a prototype pollution vulnerability reported by Jonathan Gregson! (#295). This has been backported to v1. (#298)
    Changelog

    Sourced from json5's changelog.

    Unreleased [code, diff]

    v2.2.3 [code, diff]

    v2.2.2 [code, diff]

    • Fix: Properties with the name __proto__ are added to objects and arrays. (#199) This also fixes a prototype pollution vulnerability reported by Jonathan Gregson! (#295).

    v2.2.1 [code, diff]

    • Fix: Removed dependence on minimist to patch CVE-2021-44906. (#266)

    v2.2.0 [code, diff]

    • New: Accurate and documented TypeScript declarations are now included. There is no need to install @types/json5. (#236, #244)

    v2.1.3 [code, diff]

    • Fix: An out of memory bug when parsing numbers has been fixed. (#228, #229)

    v2.1.2 [code, diff]

    ... (truncated)

    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 1
  • With auto balance, most workers are assigned to the queue with the most pending jobs, not the one with the highest priority

    With auto balance, most workers are assigned to the queue with the most pending jobs, not the one with the highest priority

    • Horizon Version: v5.10.2
    • Laravel Version: v9.35.1
    • PHP Version: 8.1.10
    • Redis Driver & Version: ext-redis 5.3.7
    • Database Driver & Version: mysqlnd 81.10

    Description:

    Steps To Reproduce:

    1. In horizon.php configure Horizon like so:
         'defaults' => [
          'supervisor-1' => [
              'connection' => 'redis',
              'queue' => ['default', 'low'],
              'balance' => 'auto',
              'maxProcesses' => 10,
          ],
      ]
      
    2. Create 10 jobs on the default queue and 1.000 jobs on the low queue.

    Expected:

    Horizon assigns most workers to the default queue because it has the higher priority.

    Actual:

    Horizon assigns most workers to the low queue because it has more pending jobs: grafik

    help wanted 
    opened by georgms 1
Releases(v5.11.0)
Owner
The Laravel Framework
The Laravel Framework
A self-hosted metrics and notifications platform for Laravel apps

Larametrics A self-hosted metrics and notifications platform for Laravel apps, Larametrics records and notifies you of changes made to models, incomin

Andrew Schmelyun 582 Dec 27, 2022
The Prometheus monitoring system and time series database.

Prometheus Visit prometheus.io for the full documentation, examples and guides. Prometheus, a Cloud Native Computing Foundation project, is a systems

Prometheus 46.2k Jan 1, 2023
Faker-driven, configuration-based, platform-agnostic, locale-compatible data faker tool

Masquerade Faker-driven, platform-agnostic, locale-compatible data faker tool Point Masquerade to a database, give it a rule-set defined in YAML and M

elgentos ecommerce solutions 219 Dec 13, 2022
Simple Arabic Laravel Dashboard , has basic settings and a nice layout . to make it easy for you to create fast dashboard

Simple Arabic Laravel Dashboard ✅ Auto Seo ✅ Optimized Notifications With Images ✅ Smart Alerts ✅ Auto Js Validations ✅ Front End Alert ✅ Nice Image V

Peter Tharwat 254 Dec 19, 2022
A better way to create complex batch job queues in Laravel.

Relay A better way to create complex batch job queues in Laravel. Installation composer require agatanga/relay Usage Example Let's say you have the fo

Agatanga 10 Dec 22, 2022
Projeto feito em Laravel/Framework com o intuito de aprender usar as Queues para disparo de e-mails.

Filas do Laravel Projeto feito em Laravel/Framework com o intuito de aprender usar as Queues para disparo de e-mails. Bibliotecas usadas: Laravel pt-B

Junior Rodrigues 0 Dec 24, 2021
Durable workflow engine that allows users to write long running persistent distributed workflows in PHP powered by Laravel queues

Durable workflow engine that allows users to write long running persistent distributed workflows (orchestrations) in PHP powered by Laravel queues. Inspired by Temporal and Azure Durable Functions.

null 268 Dec 27, 2022
Load-Balance PaperCut ETP Print Queues using Postfix

ETP Load Balancing for PaperCut using Postfix This script is designed to allow you to load balance a single Email-To-Print address against multiple pr

Bottswana 1 Nov 12, 2021
ControlPanel's Dashboard is a dashboard application designed to offer clients a management tool to manage their pterodactyl servers.

Features PayPal Integration Email Verification Audit Log Admin Dashboard User/Server Management Store (credit system) Vouchers and so much more! Contr

ControlPanel.gg 223 Jan 5, 2023
Code Driven Reporting Platform for Laravel.

Laracube Code Driven Reporting Panel for Laravel. Documentation, Installation, and Usage Instructions Click Here for Documentation, Installation, and

null 25 Dec 26, 2022
Source Code for 'Domain-Driven Laravel' by Jesse Griffin

Apress Source Code This repository accompanies Domain-Driven Laravel by Jesse Griffin (Apress, 2020). Download the files as a zip using the green butt

Apress 63 Dec 17, 2022
GitHub action to setup PHP with required extensions, php.ini configuration, code-coverage support and various tools like composer...

Setup PHP in GitHub Actions Setup PHP with required extensions, php.ini configuration, code-coverage support and various tools like composer in GitHub

Shivam Mathur 2.4k Jan 6, 2023
GitHub action to setup PHP with required extensions, php.ini configuration, code-coverage support and various tools like composer...

Setup PHP in GitHub Actions Setup PHP with required extensions, php.ini configuration, code-coverage support and various tools like composer in GitHub

Shivam Mathur 2.4k Jan 6, 2023
Low code , Zero Configuration ORM that creates models, config, database and tables on the fly.

?? ARCA ORM ?? Low code , Zero Configuration ORM that creates models, config, database and tables on the fly. ?? ???? Made in India ???? Complete docu

Scrawler Labs 28 Dec 18, 2022
provides a nested object property based user interface for accessing this configuration data within application code

laminas-config This package is considered feature-complete, and is now in security-only maintenance mode, following a decision by the Technical Steeri

Laminas Project 43 Dec 26, 2022
🙈 Code style configuration for `php-cs-fixer` based on PSR-12.

php-code-style Code style configuration for friendsofphp/php-cs-fixer based on PSR-12. Installation Step 1 of 3 Install gomzyakov/php-code-style via c

Alexander Gomzyakov 5 Nov 27, 2022
Create and manage A Domain Driven Design (DDD) in your Laravel app, simply and efficiently.

Create and manage A Domain Driven Design (DDD) in your Laravel app, simply and efficiently.

Lucas Nepomuceno 4 Jun 11, 2022
Kit is a lightweight, high-performance and event-driven web services framework that provides core components such as config, container, http, log and route.

Kit What is it Kit is a lightweight, high-performance and event-driven web services framework that provides core components such as config, container,

null 2 Sep 23, 2022
Unmaintained: Laravel Searchy makes user driven searching easy with fuzzy search, basic string matching and more to come!

!! UNMAINTAINED !! This package is no longer maintained Please see Issue #117 Here are some links to alternatives that you may be able to use (I do no

Tom Lingham 533 Nov 25, 2022