horizon: Timeout for long running task

Hi, I have a task that will take a few minutes to complete. I’ve already set the retry_after value in the config/queue.php to 3600 but my task is still canceled after 60 seconds.

I don’t get an error message or something like this. The task just stops working after 60 seconds and keeps marked as running in the dashboard.

Is there a way to increase the timeout for a task?

Maybe this issue is related to #254

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 4
  • Comments: 18 (4 by maintainers)

Most upvoted comments

I already found a solution to my problem.

In the config/horizon.php file I created a second supervisor for long running tasks and set the timeout for this supervisor to 900 seconds (15 minutes). Then I created a new queue config with a retry_after value of 1200 seconds (20 minutes). I also configured the supervisor to use this redis queue config.

To be more specific my config files now look like this:

config/horizon.php

...
'environments' => [
        'production' => [
            'supervisor-1' => [
                'connection' => 'redis',
                'queue' => [
                    'default'
                ],
                'balance' => 'simple',
                'processes' => 9,
                'tries' => 2,
            ],
            'supervisor-long-running' => [
                'connection' => 'redis-long-running',
                'queue' => [
                    'long-running-queue'
                ],
                'balance' => 'simple',
                'processes' => 9,
                'tries' => 2,
                'timeout' => 900,
            ],
        ],
]
...

config/queue.php

...
'connections' => [
        ...
        'redis' => [
            'driver' => 'redis',
            'connection' => 'default',
            'queue' => 'default',
            'retry_after' => 60,
        ],
        'redis-long-running' => [
            'driver' => 'redis',
            'connection' => 'default',
            'queue' => 'default',
            'retry_after' => 1200,
        ],
    ],
...

With this configuration my long running tasks works. All tasks are will be done within a few (milli)seconds will be processed using the default queue and therefore the default timeout.

@squatto I think your assumption is valid. Check the Laravel Documentation section Connections Vs. Queues:

Before getting started with Laravel queues, it is important to understand the distinction between “connections” and “queues”. In your config/queue.php configuration file, there is a connections configuration option. This option defines a particular connection to a backend service such as Amazon SQS, Beanstalk, or Redis. However, any given queue connection may have multiple “queues” which may be thought of as different stacks or piles of queued jobs.

Also, note that Horizon has a Queue Wait Time Thresholds setting called waits in config/horizon.php where it says:

Every connection / queue combination may have its own, unique threshold (in seconds) before this event is fired.

    /*
    |--------------------------------------------------------------------------
    | Queue Wait Time Thresholds
    |--------------------------------------------------------------------------
    |
    | This option allows you to configure when the LongWaitDetected event
    | will be fired. Every connection / queue combination may have its
    | own, unique threshold (in seconds) before this event is fired.
    |
    */
    'waits' => [
        'redis:default' => 60,
    ],

As I understand it:

  • Laravel can have multiple connections (like Amazon SQS, Beanstalk, or Redis)
  • Each connection has at least one queue, but can also have more
  • Horizon can have multiple queue workers
  • Each queue worker uses one (and only one) connection
  • Each queue worker works on at least one (but can be more) of the queues that are associated with the connection
  • retry_after is a parameter for the connection
  • timeout is a parameter for the queue
  • retry_after must always be larger than the timeout

If I define $timeout on the job Class itself — will it override connection/queue settings?

@bilfeldt You can do this using the onQueue('long-running-queue') method you can call on the result you get from the dispatch method.

A full example would be MyDispatchableClass::dispatch($event)->onQueue('long-running-queue').

so, basically adding the “timeout” key in horizon.php should be enough

so, basically adding the “timeout” key in horizon.php should be enough

While technically enough, yes, you run the risk of masking problems with your jobs that should run quickly. That’s why it’s good to split them out into your regular queue and your long running queue: long running jobs are given plenty of time to run, and regular jobs still fail if they go beyond the default timeout.

Replying to @bilfeldt:

My understanding is that your proposal will run the job on the queue='long-running-queue' but not on the connection redis-long-running or am I mistaken?

If I’m understanding this correctly, as he has it configured, his redis connection handles default queue jobs, and his redis-long-running connection handles long-running-queue queue jobs. That’s why you don’t have to specify the connection when you queue the job - you’re specifying a queue that’s only being handled by that specific connection. You would need to specify the connection if you had queues with the same names on both connections. I think 😉 I’m still not 100% sure I grok the connection-vs-queue concept either, especially when you throw Horizon into the mix.