Subversion-Projekte lars-tiefland.laravel_shop

Revision

Zur aktuellen Revision | Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
 
3
namespace Illuminate\Queue;
4
 
5
use Illuminate\Contracts\Cache\Repository as CacheContract;
6
use Illuminate\Contracts\Debug\ExceptionHandler;
7
use Illuminate\Contracts\Events\Dispatcher;
8
use Illuminate\Contracts\Queue\Factory as QueueManager;
9
use Illuminate\Database\DetectsLostConnections;
10
use Illuminate\Queue\Events\JobExceptionOccurred;
11
use Illuminate\Queue\Events\JobProcessed;
12
use Illuminate\Queue\Events\JobProcessing;
13
use Illuminate\Queue\Events\JobReleasedAfterException;
14
use Illuminate\Queue\Events\Looping;
15
use Illuminate\Queue\Events\WorkerStopping;
16
use Illuminate\Support\Carbon;
17
use Throwable;
18
 
19
class Worker
20
{
21
    use DetectsLostConnections;
22
 
23
    const EXIT_SUCCESS = 0;
24
    const EXIT_ERROR = 1;
25
    const EXIT_MEMORY_LIMIT = 12;
26
 
27
    /**
28
     * The name of the worker.
29
     *
30
     * @var string
31
     */
32
    protected $name;
33
 
34
    /**
35
     * The queue manager instance.
36
     *
37
     * @var \Illuminate\Contracts\Queue\Factory
38
     */
39
    protected $manager;
40
 
41
    /**
42
     * The event dispatcher instance.
43
     *
44
     * @var \Illuminate\Contracts\Events\Dispatcher
45
     */
46
    protected $events;
47
 
48
    /**
49
     * The cache repository implementation.
50
     *
51
     * @var \Illuminate\Contracts\Cache\Repository
52
     */
53
    protected $cache;
54
 
55
    /**
56
     * The exception handler instance.
57
     *
58
     * @var \Illuminate\Contracts\Debug\ExceptionHandler
59
     */
60
    protected $exceptions;
61
 
62
    /**
63
     * The callback used to determine if the application is in maintenance mode.
64
     *
65
     * @var callable
66
     */
67
    protected $isDownForMaintenance;
68
 
69
    /**
70
     * The callback used to reset the application's scope.
71
     *
72
     * @var callable
73
     */
74
    protected $resetScope;
75
 
76
    /**
77
     * Indicates if the worker should exit.
78
     *
79
     * @var bool
80
     */
81
    public $shouldQuit = false;
82
 
83
    /**
84
     * Indicates if the worker is paused.
85
     *
86
     * @var bool
87
     */
88
    public $paused = false;
89
 
90
    /**
91
     * The callbacks used to pop jobs from queues.
92
     *
93
     * @var callable[]
94
     */
95
    protected static $popCallbacks = [];
96
 
97
    /**
98
     * Create a new queue worker.
99
     *
100
     * @param  \Illuminate\Contracts\Queue\Factory  $manager
101
     * @param  \Illuminate\Contracts\Events\Dispatcher  $events
102
     * @param  \Illuminate\Contracts\Debug\ExceptionHandler  $exceptions
103
     * @param  callable  $isDownForMaintenance
104
     * @param  callable|null  $resetScope
105
     * @return void
106
     */
107
    public function __construct(QueueManager $manager,
108
                                Dispatcher $events,
109
                                ExceptionHandler $exceptions,
110
                                callable $isDownForMaintenance,
111
                                callable $resetScope = null)
112
    {
113
        $this->events = $events;
114
        $this->manager = $manager;
115
        $this->exceptions = $exceptions;
116
        $this->isDownForMaintenance = $isDownForMaintenance;
117
        $this->resetScope = $resetScope;
118
    }
119
 
120
    /**
121
     * Listen to the given queue in a loop.
122
     *
123
     * @param  string  $connectionName
124
     * @param  string  $queue
125
     * @param  \Illuminate\Queue\WorkerOptions  $options
126
     * @return int
127
     */
128
    public function daemon($connectionName, $queue, WorkerOptions $options)
129
    {
130
        if ($supportsAsyncSignals = $this->supportsAsyncSignals()) {
131
            $this->listenForSignals();
132
        }
133
 
134
        $lastRestart = $this->getTimestampOfLastQueueRestart();
135
 
136
        [$startTime, $jobsProcessed] = [hrtime(true) / 1e9, 0];
137
 
138
        while (true) {
139
            // Before reserving any jobs, we will make sure this queue is not paused and
140
            // if it is we will just pause this worker for a given amount of time and
141
            // make sure we do not need to kill this worker process off completely.
142
            if (! $this->daemonShouldRun($options, $connectionName, $queue)) {
143
                $status = $this->pauseWorker($options, $lastRestart);
144
 
145
                if (! is_null($status)) {
146
                    return $this->stop($status, $options);
147
                }
148
 
149
                continue;
150
            }
151
 
152
            if (isset($this->resetScope)) {
153
                ($this->resetScope)();
154
            }
155
 
156
            // First, we will attempt to get the next job off of the queue. We will also
157
            // register the timeout handler and reset the alarm for this job so it is
158
            // not stuck in a frozen state forever. Then, we can fire off this job.
159
            $job = $this->getNextJob(
160
                $this->manager->connection($connectionName), $queue
161
            );
162
 
163
            if ($supportsAsyncSignals) {
164
                $this->registerTimeoutHandler($job, $options);
165
            }
166
 
167
            // If the daemon should run (not in maintenance mode, etc.), then we can run
168
            // fire off this job for processing. Otherwise, we will need to sleep the
169
            // worker so no more jobs are processed until they should be processed.
170
            if ($job) {
171
                $jobsProcessed++;
172
 
173
                $this->runJob($job, $connectionName, $options);
174
 
175
                if ($options->rest > 0) {
176
                    $this->sleep($options->rest);
177
                }
178
            } else {
179
                $this->sleep($options->sleep);
180
            }
181
 
182
            if ($supportsAsyncSignals) {
183
                $this->resetTimeoutHandler();
184
            }
185
 
186
            // Finally, we will check to see if we have exceeded our memory limits or if
187
            // the queue should restart based on other indications. If so, we'll stop
188
            // this worker and let whatever is "monitoring" it restart the process.
189
            $status = $this->stopIfNecessary(
190
                $options, $lastRestart, $startTime, $jobsProcessed, $job
191
            );
192
 
193
            if (! is_null($status)) {
194
                return $this->stop($status, $options);
195
            }
196
        }
197
    }
198
 
199
    /**
200
     * Register the worker timeout handler.
201
     *
202
     * @param  \Illuminate\Contracts\Queue\Job|null  $job
203
     * @param  \Illuminate\Queue\WorkerOptions  $options
204
     * @return void
205
     */
206
    protected function registerTimeoutHandler($job, WorkerOptions $options)
207
    {
208
        // We will register a signal handler for the alarm signal so that we can kill this
209
        // process if it is running too long because it has frozen. This uses the async
210
        // signals supported in recent versions of PHP to accomplish it conveniently.
211
        pcntl_signal(SIGALRM, function () use ($job, $options) {
212
            if ($job) {
213
                $this->markJobAsFailedIfWillExceedMaxAttempts(
214
                    $job->getConnectionName(), $job, (int) $options->maxTries, $e = $this->maxAttemptsExceededException($job)
215
                );
216
 
217
                $this->markJobAsFailedIfWillExceedMaxExceptions(
218
                    $job->getConnectionName(), $job, $e
219
                );
220
 
221
                $this->markJobAsFailedIfItShouldFailOnTimeout(
222
                    $job->getConnectionName(), $job, $e
223
                );
224
            }
225
 
226
            $this->kill(static::EXIT_ERROR, $options);
227
        });
228
 
229
        pcntl_alarm(
230
            max($this->timeoutForJob($job, $options), 0)
231
        );
232
    }
233
 
234
    /**
235
     * Reset the worker timeout handler.
236
     *
237
     * @return void
238
     */
239
    protected function resetTimeoutHandler()
240
    {
241
        pcntl_alarm(0);
242
    }
243
 
244
    /**
245
     * Get the appropriate timeout for the given job.
246
     *
247
     * @param  \Illuminate\Contracts\Queue\Job|null  $job
248
     * @param  \Illuminate\Queue\WorkerOptions  $options
249
     * @return int
250
     */
251
    protected function timeoutForJob($job, WorkerOptions $options)
252
    {
253
        return $job && ! is_null($job->timeout()) ? $job->timeout() : $options->timeout;
254
    }
255
 
256
    /**
257
     * Determine if the daemon should process on this iteration.
258
     *
259
     * @param  \Illuminate\Queue\WorkerOptions  $options
260
     * @param  string  $connectionName
261
     * @param  string  $queue
262
     * @return bool
263
     */
264
    protected function daemonShouldRun(WorkerOptions $options, $connectionName, $queue)
265
    {
266
        return ! ((($this->isDownForMaintenance)() && ! $options->force) ||
267
            $this->paused ||
268
            $this->events->until(new Looping($connectionName, $queue)) === false);
269
    }
270
 
271
    /**
272
     * Pause the worker for the current loop.
273
     *
274
     * @param  \Illuminate\Queue\WorkerOptions  $options
275
     * @param  int  $lastRestart
276
     * @return int|null
277
     */
278
    protected function pauseWorker(WorkerOptions $options, $lastRestart)
279
    {
280
        $this->sleep($options->sleep > 0 ? $options->sleep : 1);
281
 
282
        return $this->stopIfNecessary($options, $lastRestart);
283
    }
284
 
285
    /**
286
     * Determine the exit code to stop the process if necessary.
287
     *
288
     * @param  \Illuminate\Queue\WorkerOptions  $options
289
     * @param  int  $lastRestart
290
     * @param  int  $startTime
291
     * @param  int  $jobsProcessed
292
     * @param  mixed  $job
293
     * @return int|null
294
     */
295
    protected function stopIfNecessary(WorkerOptions $options, $lastRestart, $startTime = 0, $jobsProcessed = 0, $job = null)
296
    {
297
        return match (true) {
298
            $this->shouldQuit => static::EXIT_SUCCESS,
299
            $this->memoryExceeded($options->memory) => static::EXIT_MEMORY_LIMIT,
300
            $this->queueShouldRestart($lastRestart) => static::EXIT_SUCCESS,
301
            $options->stopWhenEmpty && is_null($job) => static::EXIT_SUCCESS,
302
            $options->maxTime && hrtime(true) / 1e9 - $startTime >= $options->maxTime => static::EXIT_SUCCESS,
303
            $options->maxJobs && $jobsProcessed >= $options->maxJobs => static::EXIT_SUCCESS,
304
            default => null
305
        };
306
    }
307
 
308
    /**
309
     * Process the next job on the queue.
310
     *
311
     * @param  string  $connectionName
312
     * @param  string  $queue
313
     * @param  \Illuminate\Queue\WorkerOptions  $options
314
     * @return void
315
     */
316
    public function runNextJob($connectionName, $queue, WorkerOptions $options)
317
    {
318
        $job = $this->getNextJob(
319
            $this->manager->connection($connectionName), $queue
320
        );
321
 
322
        // If we're able to pull a job off of the stack, we will process it and then return
323
        // from this method. If there is no job on the queue, we will "sleep" the worker
324
        // for the specified number of seconds, then keep processing jobs after sleep.
325
        if ($job) {
326
            return $this->runJob($job, $connectionName, $options);
327
        }
328
 
329
        $this->sleep($options->sleep);
330
    }
331
 
332
    /**
333
     * Get the next job from the queue connection.
334
     *
335
     * @param  \Illuminate\Contracts\Queue\Queue  $connection
336
     * @param  string  $queue
337
     * @return \Illuminate\Contracts\Queue\Job|null
338
     */
339
    protected function getNextJob($connection, $queue)
340
    {
341
        $popJobCallback = function ($queue) use ($connection) {
342
            return $connection->pop($queue);
343
        };
344
 
345
        try {
346
            if (isset(static::$popCallbacks[$this->name])) {
347
                return (static::$popCallbacks[$this->name])($popJobCallback, $queue);
348
            }
349
 
350
            foreach (explode(',', $queue) as $queue) {
351
                if (! is_null($job = $popJobCallback($queue))) {
352
                    return $job;
353
                }
354
            }
355
        } catch (Throwable $e) {
356
            $this->exceptions->report($e);
357
 
358
            $this->stopWorkerIfLostConnection($e);
359
 
360
            $this->sleep(1);
361
        }
362
    }
363
 
364
    /**
365
     * Process the given job.
366
     *
367
     * @param  \Illuminate\Contracts\Queue\Job  $job
368
     * @param  string  $connectionName
369
     * @param  \Illuminate\Queue\WorkerOptions  $options
370
     * @return void
371
     */
372
    protected function runJob($job, $connectionName, WorkerOptions $options)
373
    {
374
        try {
375
            return $this->process($connectionName, $job, $options);
376
        } catch (Throwable $e) {
377
            $this->exceptions->report($e);
378
 
379
            $this->stopWorkerIfLostConnection($e);
380
        }
381
    }
382
 
383
    /**
384
     * Stop the worker if we have lost connection to a database.
385
     *
386
     * @param  \Throwable  $e
387
     * @return void
388
     */
389
    protected function stopWorkerIfLostConnection($e)
390
    {
391
        if ($this->causedByLostConnection($e)) {
392
            $this->shouldQuit = true;
393
        }
394
    }
395
 
396
    /**
397
     * Process the given job from the queue.
398
     *
399
     * @param  string  $connectionName
400
     * @param  \Illuminate\Contracts\Queue\Job  $job
401
     * @param  \Illuminate\Queue\WorkerOptions  $options
402
     * @return void
403
     *
404
     * @throws \Throwable
405
     */
406
    public function process($connectionName, $job, WorkerOptions $options)
407
    {
408
        try {
409
            // First we will raise the before job event and determine if the job has already run
410
            // over its maximum attempt limits, which could primarily happen when this job is
411
            // continually timing out and not actually throwing any exceptions from itself.
412
            $this->raiseBeforeJobEvent($connectionName, $job);
413
 
414
            $this->markJobAsFailedIfAlreadyExceedsMaxAttempts(
415
                $connectionName, $job, (int) $options->maxTries
416
            );
417
 
418
            if ($job->isDeleted()) {
419
                return $this->raiseAfterJobEvent($connectionName, $job);
420
            }
421
 
422
            // Here we will fire off the job and let it process. We will catch any exceptions, so
423
            // they can be reported to the developer's logs, etc. Once the job is finished the
424
            // proper events will be fired to let any listeners know this job has completed.
425
            $job->fire();
426
 
427
            $this->raiseAfterJobEvent($connectionName, $job);
428
        } catch (Throwable $e) {
429
            $this->handleJobException($connectionName, $job, $options, $e);
430
        }
431
    }
432
 
433
    /**
434
     * Handle an exception that occurred while the job was running.
435
     *
436
     * @param  string  $connectionName
437
     * @param  \Illuminate\Contracts\Queue\Job  $job
438
     * @param  \Illuminate\Queue\WorkerOptions  $options
439
     * @param  \Throwable  $e
440
     * @return void
441
     *
442
     * @throws \Throwable
443
     */
444
    protected function handleJobException($connectionName, $job, WorkerOptions $options, Throwable $e)
445
    {
446
        try {
447
            // First, we will go ahead and mark the job as failed if it will exceed the maximum
448
            // attempts it is allowed to run the next time we process it. If so we will just
449
            // go ahead and mark it as failed now so we do not have to release this again.
450
            if (! $job->hasFailed()) {
451
                $this->markJobAsFailedIfWillExceedMaxAttempts(
452
                    $connectionName, $job, (int) $options->maxTries, $e
453
                );
454
 
455
                $this->markJobAsFailedIfWillExceedMaxExceptions(
456
                    $connectionName, $job, $e
457
                );
458
            }
459
 
460
            $this->raiseExceptionOccurredJobEvent(
461
                $connectionName, $job, $e
462
            );
463
        } finally {
464
            // If we catch an exception, we will attempt to release the job back onto the queue
465
            // so it is not lost entirely. This'll let the job be retried at a later time by
466
            // another listener (or this same one). We will re-throw this exception after.
467
            if (! $job->isDeleted() && ! $job->isReleased() && ! $job->hasFailed()) {
468
                $job->release($this->calculateBackoff($job, $options));
469
 
470
                $this->events->dispatch(new JobReleasedAfterException(
471
                    $connectionName, $job
472
                ));
473
            }
474
        }
475
 
476
        throw $e;
477
    }
478
 
479
    /**
480
     * Mark the given job as failed if it has exceeded the maximum allowed attempts.
481
     *
482
     * This will likely be because the job previously exceeded a timeout.
483
     *
484
     * @param  string  $connectionName
485
     * @param  \Illuminate\Contracts\Queue\Job  $job
486
     * @param  int  $maxTries
487
     * @return void
488
     *
489
     * @throws \Throwable
490
     */
491
    protected function markJobAsFailedIfAlreadyExceedsMaxAttempts($connectionName, $job, $maxTries)
492
    {
493
        $maxTries = ! is_null($job->maxTries()) ? $job->maxTries() : $maxTries;
494
 
495
        $retryUntil = $job->retryUntil();
496
 
497
        if ($retryUntil && Carbon::now()->getTimestamp() <= $retryUntil) {
498
            return;
499
        }
500
 
501
        if (! $retryUntil && ($maxTries === 0 || $job->attempts() <= $maxTries)) {
502
            return;
503
        }
504
 
505
        $this->failJob($job, $e = $this->maxAttemptsExceededException($job));
506
 
507
        throw $e;
508
    }
509
 
510
    /**
511
     * Mark the given job as failed if it has exceeded the maximum allowed attempts.
512
     *
513
     * @param  string  $connectionName
514
     * @param  \Illuminate\Contracts\Queue\Job  $job
515
     * @param  int  $maxTries
516
     * @param  \Throwable  $e
517
     * @return void
518
     */
519
    protected function markJobAsFailedIfWillExceedMaxAttempts($connectionName, $job, $maxTries, Throwable $e)
520
    {
521
        $maxTries = ! is_null($job->maxTries()) ? $job->maxTries() : $maxTries;
522
 
523
        if ($job->retryUntil() && $job->retryUntil() <= Carbon::now()->getTimestamp()) {
524
            $this->failJob($job, $e);
525
        }
526
 
527
        if (! $job->retryUntil() && $maxTries > 0 && $job->attempts() >= $maxTries) {
528
            $this->failJob($job, $e);
529
        }
530
    }
531
 
532
    /**
533
     * Mark the given job as failed if it has exceeded the maximum allowed attempts.
534
     *
535
     * @param  string  $connectionName
536
     * @param  \Illuminate\Contracts\Queue\Job  $job
537
     * @param  \Throwable  $e
538
     * @return void
539
     */
540
    protected function markJobAsFailedIfWillExceedMaxExceptions($connectionName, $job, Throwable $e)
541
    {
542
        if (! $this->cache || is_null($uuid = $job->uuid()) ||
543
            is_null($maxExceptions = $job->maxExceptions())) {
544
            return;
545
        }
546
 
547
        if (! $this->cache->get('job-exceptions:'.$uuid)) {
548
            $this->cache->put('job-exceptions:'.$uuid, 0, Carbon::now()->addDay());
549
        }
550
 
551
        if ($maxExceptions <= $this->cache->increment('job-exceptions:'.$uuid)) {
552
            $this->cache->forget('job-exceptions:'.$uuid);
553
 
554
            $this->failJob($job, $e);
555
        }
556
    }
557
 
558
    /**
559
     * Mark the given job as failed if it should fail on timeouts.
560
     *
561
     * @param  string  $connectionName
562
     * @param  \Illuminate\Contracts\Queue\Job  $job
563
     * @param  \Throwable  $e
564
     * @return void
565
     */
566
    protected function markJobAsFailedIfItShouldFailOnTimeout($connectionName, $job, Throwable $e)
567
    {
568
        if (method_exists($job, 'shouldFailOnTimeout') ? $job->shouldFailOnTimeout() : false) {
569
            $this->failJob($job, $e);
570
        }
571
    }
572
 
573
    /**
574
     * Mark the given job as failed and raise the relevant event.
575
     *
576
     * @param  \Illuminate\Contracts\Queue\Job  $job
577
     * @param  \Throwable  $e
578
     * @return void
579
     */
580
    protected function failJob($job, Throwable $e)
581
    {
582
        $job->fail($e);
583
    }
584
 
585
    /**
586
     * Calculate the backoff for the given job.
587
     *
588
     * @param  \Illuminate\Contracts\Queue\Job  $job
589
     * @param  \Illuminate\Queue\WorkerOptions  $options
590
     * @return int
591
     */
592
    protected function calculateBackoff($job, WorkerOptions $options)
593
    {
594
        $backoff = explode(
595
            ',',
596
            method_exists($job, 'backoff') && ! is_null($job->backoff())
597
                        ? $job->backoff()
598
                        : $options->backoff
599
        );
600
 
601
        return (int) ($backoff[$job->attempts() - 1] ?? last($backoff));
602
    }
603
 
604
    /**
605
     * Raise the before queue job event.
606
     *
607
     * @param  string  $connectionName
608
     * @param  \Illuminate\Contracts\Queue\Job  $job
609
     * @return void
610
     */
611
    protected function raiseBeforeJobEvent($connectionName, $job)
612
    {
613
        $this->events->dispatch(new JobProcessing(
614
            $connectionName, $job
615
        ));
616
    }
617
 
618
    /**
619
     * Raise the after queue job event.
620
     *
621
     * @param  string  $connectionName
622
     * @param  \Illuminate\Contracts\Queue\Job  $job
623
     * @return void
624
     */
625
    protected function raiseAfterJobEvent($connectionName, $job)
626
    {
627
        $this->events->dispatch(new JobProcessed(
628
            $connectionName, $job
629
        ));
630
    }
631
 
632
    /**
633
     * Raise the exception occurred queue job event.
634
     *
635
     * @param  string  $connectionName
636
     * @param  \Illuminate\Contracts\Queue\Job  $job
637
     * @param  \Throwable  $e
638
     * @return void
639
     */
640
    protected function raiseExceptionOccurredJobEvent($connectionName, $job, Throwable $e)
641
    {
642
        $this->events->dispatch(new JobExceptionOccurred(
643
            $connectionName, $job, $e
644
        ));
645
    }
646
 
647
    /**
648
     * Determine if the queue worker should restart.
649
     *
650
     * @param  int|null  $lastRestart
651
     * @return bool
652
     */
653
    protected function queueShouldRestart($lastRestart)
654
    {
655
        return $this->getTimestampOfLastQueueRestart() != $lastRestart;
656
    }
657
 
658
    /**
659
     * Get the last queue restart timestamp, or null.
660
     *
661
     * @return int|null
662
     */
663
    protected function getTimestampOfLastQueueRestart()
664
    {
665
        if ($this->cache) {
666
            return $this->cache->get('illuminate:queue:restart');
667
        }
668
    }
669
 
670
    /**
671
     * Enable async signals for the process.
672
     *
673
     * @return void
674
     */
675
    protected function listenForSignals()
676
    {
677
        pcntl_async_signals(true);
678
 
679
        pcntl_signal(SIGQUIT, fn () => $this->shouldQuit = true);
680
        pcntl_signal(SIGTERM, fn () => $this->shouldQuit = true);
681
        pcntl_signal(SIGUSR2, fn () => $this->paused = true);
682
        pcntl_signal(SIGCONT, fn () => $this->paused = false);
683
    }
684
 
685
    /**
686
     * Determine if "async" signals are supported.
687
     *
688
     * @return bool
689
     */
690
    protected function supportsAsyncSignals()
691
    {
692
        return extension_loaded('pcntl');
693
    }
694
 
695
    /**
696
     * Determine if the memory limit has been exceeded.
697
     *
698
     * @param  int  $memoryLimit
699
     * @return bool
700
     */
701
    public function memoryExceeded($memoryLimit)
702
    {
703
        return (memory_get_usage(true) / 1024 / 1024) >= $memoryLimit;
704
    }
705
 
706
    /**
707
     * Stop listening and bail out of the script.
708
     *
709
     * @param  int  $status
710
     * @param  WorkerOptions|null  $options
711
     * @return int
712
     */
713
    public function stop($status = 0, $options = null)
714
    {
715
        $this->events->dispatch(new WorkerStopping($status, $options));
716
 
717
        return $status;
718
    }
719
 
720
    /**
721
     * Kill the process.
722
     *
723
     * @param  int  $status
724
     * @param  \Illuminate\Queue\WorkerOptions|null  $options
725
     * @return never
726
     */
727
    public function kill($status = 0, $options = null)
728
    {
729
        $this->events->dispatch(new WorkerStopping($status, $options));
730
 
731
        if (extension_loaded('posix')) {
732
            posix_kill(getmypid(), SIGKILL);
733
        }
734
 
735
        exit($status);
736
    }
737
 
738
    /**
739
     * Create an instance of MaxAttemptsExceededException.
740
     *
741
     * @param  \Illuminate\Contracts\Queue\Job  $job
742
     * @return \Illuminate\Queue\MaxAttemptsExceededException
743
     */
744
    protected function maxAttemptsExceededException($job)
745
    {
746
        return new MaxAttemptsExceededException(
747
            $job->resolveName().' has been attempted too many times or run too long. The job may have previously timed out.'
748
        );
749
    }
750
 
751
    /**
752
     * Sleep the script for a given number of seconds.
753
     *
754
     * @param  int|float  $seconds
755
     * @return void
756
     */
757
    public function sleep($seconds)
758
    {
759
        if ($seconds < 1) {
760
            usleep($seconds * 1000000);
761
        } else {
762
            sleep($seconds);
763
        }
764
    }
765
 
766
    /**
767
     * Set the cache repository implementation.
768
     *
769
     * @param  \Illuminate\Contracts\Cache\Repository  $cache
770
     * @return $this
771
     */
772
    public function setCache(CacheContract $cache)
773
    {
774
        $this->cache = $cache;
775
 
776
        return $this;
777
    }
778
 
779
    /**
780
     * Set the name of the worker.
781
     *
782
     * @param  string  $name
783
     * @return $this
784
     */
785
    public function setName($name)
786
    {
787
        $this->name = $name;
788
 
789
        return $this;
790
    }
791
 
792
    /**
793
     * Register a callback to be executed to pick jobs.
794
     *
795
     * @param  string  $workerName
796
     * @param  callable  $callback
797
     * @return void
798
     */
799
    public static function popUsing($workerName, $callback)
800
    {
801
        if (is_null($callback)) {
802
            unset(static::$popCallbacks[$workerName]);
803
        } else {
804
            static::$popCallbacks[$workerName] = $callback;
805
        }
806
    }
807
 
808
    /**
809
     * Get the queue manager instance.
810
     *
811
     * @return \Illuminate\Contracts\Queue\Factory
812
     */
813
    public function getManager()
814
    {
815
        return $this->manager;
816
    }
817
 
818
    /**
819
     * Set the queue manager instance.
820
     *
821
     * @param  \Illuminate\Contracts\Queue\Factory  $manager
822
     * @return void
823
     */
824
    public function setManager(QueueManager $manager)
825
    {
826
        $this->manager = $manager;
827
    }
828
}