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\Console\Scheduling;
4
 
5
use Closure;
6
use Cron\CronExpression;
7
use GuzzleHttp\Client as HttpClient;
8
use GuzzleHttp\Exception\TransferException;
9
use Illuminate\Contracts\Container\Container;
10
use Illuminate\Contracts\Debug\ExceptionHandler;
11
use Illuminate\Contracts\Mail\Mailer;
12
use Illuminate\Support\Arr;
13
use Illuminate\Support\Facades\Date;
14
use Illuminate\Support\Reflector;
15
use Illuminate\Support\Stringable;
16
use Illuminate\Support\Traits\Macroable;
17
use Illuminate\Support\Traits\ReflectsClosures;
18
use Psr\Http\Client\ClientExceptionInterface;
19
use Symfony\Component\Process\Process;
20
use Throwable;
21
 
22
class Event
23
{
24
    use Macroable, ManagesFrequencies, ReflectsClosures;
25
 
26
    /**
27
     * The command string.
28
     *
29
     * @var string|null
30
     */
31
    public $command;
32
 
33
    /**
34
     * The cron expression representing the event's frequency.
35
     *
36
     * @var string
37
     */
38
    public $expression = '* * * * *';
39
 
40
    /**
41
     * The timezone the date should be evaluated on.
42
     *
43
     * @var \DateTimeZone|string
44
     */
45
    public $timezone;
46
 
47
    /**
48
     * The user the command should run as.
49
     *
50
     * @var string|null
51
     */
52
    public $user;
53
 
54
    /**
55
     * The list of environments the command should run under.
56
     *
57
     * @var array
58
     */
59
    public $environments = [];
60
 
61
    /**
62
     * Indicates if the command should run in maintenance mode.
63
     *
64
     * @var bool
65
     */
66
    public $evenInMaintenanceMode = false;
67
 
68
    /**
69
     * Indicates if the command should not overlap itself.
70
     *
71
     * @var bool
72
     */
73
    public $withoutOverlapping = false;
74
 
75
    /**
76
     * Indicates if the command should only be allowed to run on one server for each cron expression.
77
     *
78
     * @var bool
79
     */
80
    public $onOneServer = false;
81
 
82
    /**
83
     * The amount of time the mutex should be valid.
84
     *
85
     * @var int
86
     */
87
    public $expiresAt = 1440;
88
 
89
    /**
90
     * Indicates if the command should run in the background.
91
     *
92
     * @var bool
93
     */
94
    public $runInBackground = false;
95
 
96
    /**
97
     * The array of filter callbacks.
98
     *
99
     * @var array
100
     */
101
    protected $filters = [];
102
 
103
    /**
104
     * The array of reject callbacks.
105
     *
106
     * @var array
107
     */
108
    protected $rejects = [];
109
 
110
    /**
111
     * The location that output should be sent to.
112
     *
113
     * @var string
114
     */
115
    public $output = '/dev/null';
116
 
117
    /**
118
     * Indicates whether output should be appended.
119
     *
120
     * @var bool
121
     */
122
    public $shouldAppendOutput = false;
123
 
124
    /**
125
     * The array of callbacks to be run before the event is started.
126
     *
127
     * @var array
128
     */
129
    protected $beforeCallbacks = [];
130
 
131
    /**
132
     * The array of callbacks to be run after the event is finished.
133
     *
134
     * @var array
135
     */
136
    protected $afterCallbacks = [];
137
 
138
    /**
139
     * The human readable description of the event.
140
     *
141
     * @var string|null
142
     */
143
    public $description;
144
 
145
    /**
146
     * The event mutex implementation.
147
     *
148
     * @var \Illuminate\Console\Scheduling\EventMutex
149
     */
150
    public $mutex;
151
 
152
    /**
153
     * The mutex name resolver callback.
154
     *
155
     * @var \Closure|null
156
     */
157
    public $mutexNameResolver;
158
 
159
    /**
160
     * The exit status code of the command.
161
     *
162
     * @var int|null
163
     */
164
    public $exitCode;
165
 
166
    /**
167
     * Create a new event instance.
168
     *
169
     * @param  \Illuminate\Console\Scheduling\EventMutex  $mutex
170
     * @param  string  $command
171
     * @param  \DateTimeZone|string|null  $timezone
172
     * @return void
173
     */
174
    public function __construct(EventMutex $mutex, $command, $timezone = null)
175
    {
176
        $this->mutex = $mutex;
177
        $this->command = $command;
178
        $this->timezone = $timezone;
179
 
180
        $this->output = $this->getDefaultOutput();
181
    }
182
 
183
    /**
184
     * Get the default output depending on the OS.
185
     *
186
     * @return string
187
     */
188
    public function getDefaultOutput()
189
    {
190
        return (DIRECTORY_SEPARATOR === '\\') ? 'NUL' : '/dev/null';
191
    }
192
 
193
    /**
194
     * Run the given event.
195
     *
196
     * @param  \Illuminate\Contracts\Container\Container  $container
197
     * @return void
198
     *
199
     * @throws \Throwable
200
     */
201
    public function run(Container $container)
202
    {
203
        if ($this->shouldSkipDueToOverlapping()) {
204
            return;
205
        }
206
 
207
        $exitCode = $this->start($container);
208
 
209
        if (! $this->runInBackground) {
210
            $this->finish($container, $exitCode);
211
        }
212
    }
213
 
214
    /**
215
     * Determine if the event should skip because another process is overlapping.
216
     *
217
     * @return bool
218
     */
219
    public function shouldSkipDueToOverlapping()
220
    {
221
        return $this->withoutOverlapping && ! $this->mutex->create($this);
222
    }
223
 
224
    /**
225
     * Run the command process.
226
     *
227
     * @param  \Illuminate\Contracts\Container\Container  $container
228
     * @return int
229
     *
230
     * @throws \Throwable
231
     */
232
    protected function start($container)
233
    {
234
        try {
235
            $this->callBeforeCallbacks($container);
236
 
237
            return $this->execute($container);
238
        } catch (Throwable $exception) {
239
            $this->removeMutex();
240
 
241
            throw $exception;
242
        }
243
    }
244
 
245
    /**
246
     * Run the command process.
247
     *
248
     * @param  \Illuminate\Contracts\Container\Container  $container
249
     * @return int
250
     */
251
    protected function execute($container)
252
    {
253
        return Process::fromShellCommandline(
254
            $this->buildCommand(), base_path(), null, null, null
255
        )->run();
256
    }
257
 
258
    /**
259
     * Mark the command process as finished and run callbacks/cleanup.
260
     *
261
     * @param  \Illuminate\Contracts\Container\Container  $container
262
     * @param  int  $exitCode
263
     * @return void
264
     */
265
    public function finish(Container $container, $exitCode)
266
    {
267
        $this->exitCode = (int) $exitCode;
268
 
269
        try {
270
            $this->callAfterCallbacks($container);
271
        } finally {
272
            $this->removeMutex();
273
        }
274
    }
275
 
276
    /**
277
     * Call all of the "before" callbacks for the event.
278
     *
279
     * @param  \Illuminate\Contracts\Container\Container  $container
280
     * @return void
281
     */
282
    public function callBeforeCallbacks(Container $container)
283
    {
284
        foreach ($this->beforeCallbacks as $callback) {
285
            $container->call($callback);
286
        }
287
    }
288
 
289
    /**
290
     * Call all of the "after" callbacks for the event.
291
     *
292
     * @param  \Illuminate\Contracts\Container\Container  $container
293
     * @return void
294
     */
295
    public function callAfterCallbacks(Container $container)
296
    {
297
        foreach ($this->afterCallbacks as $callback) {
298
            $container->call($callback);
299
        }
300
    }
301
 
302
    /**
303
     * Build the command string.
304
     *
305
     * @return string
306
     */
307
    public function buildCommand()
308
    {
309
        return (new CommandBuilder)->buildCommand($this);
310
    }
311
 
312
    /**
313
     * Determine if the given event should run based on the Cron expression.
314
     *
315
     * @param  \Illuminate\Contracts\Foundation\Application  $app
316
     * @return bool
317
     */
318
    public function isDue($app)
319
    {
320
        if (! $this->runsInMaintenanceMode() && $app->isDownForMaintenance()) {
321
            return false;
322
        }
323
 
324
        return $this->expressionPasses() &&
325
               $this->runsInEnvironment($app->environment());
326
    }
327
 
328
    /**
329
     * Determine if the event runs in maintenance mode.
330
     *
331
     * @return bool
332
     */
333
    public function runsInMaintenanceMode()
334
    {
335
        return $this->evenInMaintenanceMode;
336
    }
337
 
338
    /**
339
     * Determine if the Cron expression passes.
340
     *
341
     * @return bool
342
     */
343
    protected function expressionPasses()
344
    {
345
        $date = Date::now();
346
 
347
        if ($this->timezone) {
348
            $date = $date->setTimezone($this->timezone);
349
        }
350
 
351
        return (new CronExpression($this->expression))->isDue($date->toDateTimeString());
352
    }
353
 
354
    /**
355
     * Determine if the event runs in the given environment.
356
     *
357
     * @param  string  $environment
358
     * @return bool
359
     */
360
    public function runsInEnvironment($environment)
361
    {
362
        return empty($this->environments) || in_array($environment, $this->environments);
363
    }
364
 
365
    /**
366
     * Determine if the filters pass for the event.
367
     *
368
     * @param  \Illuminate\Contracts\Foundation\Application  $app
369
     * @return bool
370
     */
371
    public function filtersPass($app)
372
    {
373
        foreach ($this->filters as $callback) {
374
            if (! $app->call($callback)) {
375
                return false;
376
            }
377
        }
378
 
379
        foreach ($this->rejects as $callback) {
380
            if ($app->call($callback)) {
381
                return false;
382
            }
383
        }
384
 
385
        return true;
386
    }
387
 
388
    /**
389
     * Ensure that the output is stored on disk in a log file.
390
     *
391
     * @return $this
392
     */
393
    public function storeOutput()
394
    {
395
        $this->ensureOutputIsBeingCaptured();
396
 
397
        return $this;
398
    }
399
 
400
    /**
401
     * Send the output of the command to a given location.
402
     *
403
     * @param  string  $location
404
     * @param  bool  $append
405
     * @return $this
406
     */
407
    public function sendOutputTo($location, $append = false)
408
    {
409
        $this->output = $location;
410
 
411
        $this->shouldAppendOutput = $append;
412
 
413
        return $this;
414
    }
415
 
416
    /**
417
     * Append the output of the command to a given location.
418
     *
419
     * @param  string  $location
420
     * @return $this
421
     */
422
    public function appendOutputTo($location)
423
    {
424
        return $this->sendOutputTo($location, true);
425
    }
426
 
427
    /**
428
     * E-mail the results of the scheduled operation.
429
     *
430
     * @param  array|mixed  $addresses
431
     * @param  bool  $onlyIfOutputExists
432
     * @return $this
433
     *
434
     * @throws \LogicException
435
     */
436
    public function emailOutputTo($addresses, $onlyIfOutputExists = false)
437
    {
438
        $this->ensureOutputIsBeingCaptured();
439
 
440
        $addresses = Arr::wrap($addresses);
441
 
442
        return $this->then(function (Mailer $mailer) use ($addresses, $onlyIfOutputExists) {
443
            $this->emailOutput($mailer, $addresses, $onlyIfOutputExists);
444
        });
445
    }
446
 
447
    /**
448
     * E-mail the results of the scheduled operation if it produces output.
449
     *
450
     * @param  array|mixed  $addresses
451
     * @return $this
452
     *
453
     * @throws \LogicException
454
     */
455
    public function emailWrittenOutputTo($addresses)
456
    {
457
        return $this->emailOutputTo($addresses, true);
458
    }
459
 
460
    /**
461
     * E-mail the results of the scheduled operation if it fails.
462
     *
463
     * @param  array|mixed  $addresses
464
     * @return $this
465
     */
466
    public function emailOutputOnFailure($addresses)
467
    {
468
        $this->ensureOutputIsBeingCaptured();
469
 
470
        $addresses = Arr::wrap($addresses);
471
 
472
        return $this->onFailure(function (Mailer $mailer) use ($addresses) {
473
            $this->emailOutput($mailer, $addresses, false);
474
        });
475
    }
476
 
477
    /**
478
     * Ensure that the command output is being captured.
479
     *
480
     * @return void
481
     */
482
    protected function ensureOutputIsBeingCaptured()
483
    {
484
        if (is_null($this->output) || $this->output == $this->getDefaultOutput()) {
485
            $this->sendOutputTo(storage_path('logs/schedule-'.sha1($this->mutexName()).'.log'));
486
        }
487
    }
488
 
489
    /**
490
     * E-mail the output of the event to the recipients.
491
     *
492
     * @param  \Illuminate\Contracts\Mail\Mailer  $mailer
493
     * @param  array  $addresses
494
     * @param  bool  $onlyIfOutputExists
495
     * @return void
496
     */
497
    protected function emailOutput(Mailer $mailer, $addresses, $onlyIfOutputExists = false)
498
    {
499
        $text = is_file($this->output) ? file_get_contents($this->output) : '';
500
 
501
        if ($onlyIfOutputExists && empty($text)) {
502
            return;
503
        }
504
 
505
        $mailer->raw($text, function ($m) use ($addresses) {
506
            $m->to($addresses)->subject($this->getEmailSubject());
507
        });
508
    }
509
 
510
    /**
511
     * Get the e-mail subject line for output results.
512
     *
513
     * @return string
514
     */
515
    protected function getEmailSubject()
516
    {
517
        if ($this->description) {
518
            return $this->description;
519
        }
520
 
521
        return "Scheduled Job Output For [{$this->command}]";
522
    }
523
 
524
    /**
525
     * Register a callback to ping a given URL before the job runs.
526
     *
527
     * @param  string  $url
528
     * @return $this
529
     */
530
    public function pingBefore($url)
531
    {
532
        return $this->before($this->pingCallback($url));
533
    }
534
 
535
    /**
536
     * Register a callback to ping a given URL before the job runs if the given condition is true.
537
     *
538
     * @param  bool  $value
539
     * @param  string  $url
540
     * @return $this
541
     */
542
    public function pingBeforeIf($value, $url)
543
    {
544
        return $value ? $this->pingBefore($url) : $this;
545
    }
546
 
547
    /**
548
     * Register a callback to ping a given URL after the job runs.
549
     *
550
     * @param  string  $url
551
     * @return $this
552
     */
553
    public function thenPing($url)
554
    {
555
        return $this->then($this->pingCallback($url));
556
    }
557
 
558
    /**
559
     * Register a callback to ping a given URL after the job runs if the given condition is true.
560
     *
561
     * @param  bool  $value
562
     * @param  string  $url
563
     * @return $this
564
     */
565
    public function thenPingIf($value, $url)
566
    {
567
        return $value ? $this->thenPing($url) : $this;
568
    }
569
 
570
    /**
571
     * Register a callback to ping a given URL if the operation succeeds.
572
     *
573
     * @param  string  $url
574
     * @return $this
575
     */
576
    public function pingOnSuccess($url)
577
    {
578
        return $this->onSuccess($this->pingCallback($url));
579
    }
580
 
581
    /**
582
     * Register a callback to ping a given URL if the operation fails.
583
     *
584
     * @param  string  $url
585
     * @return $this
586
     */
587
    public function pingOnFailure($url)
588
    {
589
        return $this->onFailure($this->pingCallback($url));
590
    }
591
 
592
    /**
593
     * Get the callback that pings the given URL.
594
     *
595
     * @param  string  $url
596
     * @return \Closure
597
     */
598
    protected function pingCallback($url)
599
    {
600
        return function (Container $container, HttpClient $http) use ($url) {
601
            try {
602
                $http->request('GET', $url);
603
            } catch (ClientExceptionInterface|TransferException $e) {
604
                $container->make(ExceptionHandler::class)->report($e);
605
            }
606
        };
607
    }
608
 
609
    /**
610
     * State that the command should run in the background.
611
     *
612
     * @return $this
613
     */
614
    public function runInBackground()
615
    {
616
        $this->runInBackground = true;
617
 
618
        return $this;
619
    }
620
 
621
    /**
622
     * Set which user the command should run as.
623
     *
624
     * @param  string  $user
625
     * @return $this
626
     */
627
    public function user($user)
628
    {
629
        $this->user = $user;
630
 
631
        return $this;
632
    }
633
 
634
    /**
635
     * Limit the environments the command should run in.
636
     *
637
     * @param  array|mixed  $environments
638
     * @return $this
639
     */
640
    public function environments($environments)
641
    {
642
        $this->environments = is_array($environments) ? $environments : func_get_args();
643
 
644
        return $this;
645
    }
646
 
647
    /**
648
     * State that the command should run even in maintenance mode.
649
     *
650
     * @return $this
651
     */
652
    public function evenInMaintenanceMode()
653
    {
654
        $this->evenInMaintenanceMode = true;
655
 
656
        return $this;
657
    }
658
 
659
    /**
660
     * Do not allow the event to overlap each other.
661
     *
662
     * @param  int  $expiresAt
663
     * @return $this
664
     */
665
    public function withoutOverlapping($expiresAt = 1440)
666
    {
667
        $this->withoutOverlapping = true;
668
 
669
        $this->expiresAt = $expiresAt;
670
 
671
        return $this->skip(function () {
672
            return $this->mutex->exists($this);
673
        });
674
    }
675
 
676
    /**
677
     * Allow the event to only run on one server for each cron expression.
678
     *
679
     * @return $this
680
     */
681
    public function onOneServer()
682
    {
683
        $this->onOneServer = true;
684
 
685
        return $this;
686
    }
687
 
688
    /**
689
     * Register a callback to further filter the schedule.
690
     *
691
     * @param  \Closure|bool  $callback
692
     * @return $this
693
     */
694
    public function when($callback)
695
    {
696
        $this->filters[] = Reflector::isCallable($callback) ? $callback : function () use ($callback) {
697
            return $callback;
698
        };
699
 
700
        return $this;
701
    }
702
 
703
    /**
704
     * Register a callback to further filter the schedule.
705
     *
706
     * @param  \Closure|bool  $callback
707
     * @return $this
708
     */
709
    public function skip($callback)
710
    {
711
        $this->rejects[] = Reflector::isCallable($callback) ? $callback : function () use ($callback) {
712
            return $callback;
713
        };
714
 
715
        return $this;
716
    }
717
 
718
    /**
719
     * Register a callback to be called before the operation.
720
     *
721
     * @param  \Closure  $callback
722
     * @return $this
723
     */
724
    public function before(Closure $callback)
725
    {
726
        $this->beforeCallbacks[] = $callback;
727
 
728
        return $this;
729
    }
730
 
731
    /**
732
     * Register a callback to be called after the operation.
733
     *
734
     * @param  \Closure  $callback
735
     * @return $this
736
     */
737
    public function after(Closure $callback)
738
    {
739
        return $this->then($callback);
740
    }
741
 
742
    /**
743
     * Register a callback to be called after the operation.
744
     *
745
     * @param  \Closure  $callback
746
     * @return $this
747
     */
748
    public function then(Closure $callback)
749
    {
750
        $parameters = $this->closureParameterTypes($callback);
751
 
752
        if (Arr::get($parameters, 'output') === Stringable::class) {
753
            return $this->thenWithOutput($callback);
754
        }
755
 
756
        $this->afterCallbacks[] = $callback;
757
 
758
        return $this;
759
    }
760
 
761
    /**
762
     * Register a callback that uses the output after the job runs.
763
     *
764
     * @param  \Closure  $callback
765
     * @param  bool  $onlyIfOutputExists
766
     * @return $this
767
     */
768
    public function thenWithOutput(Closure $callback, $onlyIfOutputExists = false)
769
    {
770
        $this->ensureOutputIsBeingCaptured();
771
 
772
        return $this->then($this->withOutputCallback($callback, $onlyIfOutputExists));
773
    }
774
 
775
    /**
776
     * Register a callback to be called if the operation succeeds.
777
     *
778
     * @param  \Closure  $callback
779
     * @return $this
780
     */
781
    public function onSuccess(Closure $callback)
782
    {
783
        $parameters = $this->closureParameterTypes($callback);
784
 
785
        if (Arr::get($parameters, 'output') === Stringable::class) {
786
            return $this->onSuccessWithOutput($callback);
787
        }
788
 
789
        return $this->then(function (Container $container) use ($callback) {
790
            if ($this->exitCode === 0) {
791
                $container->call($callback);
792
            }
793
        });
794
    }
795
 
796
    /**
797
     * Register a callback that uses the output if the operation succeeds.
798
     *
799
     * @param  \Closure  $callback
800
     * @param  bool  $onlyIfOutputExists
801
     * @return $this
802
     */
803
    public function onSuccessWithOutput(Closure $callback, $onlyIfOutputExists = false)
804
    {
805
        $this->ensureOutputIsBeingCaptured();
806
 
807
        return $this->onSuccess($this->withOutputCallback($callback, $onlyIfOutputExists));
808
    }
809
 
810
    /**
811
     * Register a callback to be called if the operation fails.
812
     *
813
     * @param  \Closure  $callback
814
     * @return $this
815
     */
816
    public function onFailure(Closure $callback)
817
    {
818
        $parameters = $this->closureParameterTypes($callback);
819
 
820
        if (Arr::get($parameters, 'output') === Stringable::class) {
821
            return $this->onFailureWithOutput($callback);
822
        }
823
 
824
        return $this->then(function (Container $container) use ($callback) {
825
            if ($this->exitCode !== 0) {
826
                $container->call($callback);
827
            }
828
        });
829
    }
830
 
831
    /**
832
     * Register a callback that uses the output if the operation fails.
833
     *
834
     * @param  \Closure  $callback
835
     * @param  bool  $onlyIfOutputExists
836
     * @return $this
837
     */
838
    public function onFailureWithOutput(Closure $callback, $onlyIfOutputExists = false)
839
    {
840
        $this->ensureOutputIsBeingCaptured();
841
 
842
        return $this->onFailure($this->withOutputCallback($callback, $onlyIfOutputExists));
843
    }
844
 
845
    /**
846
     * Get a callback that provides output.
847
     *
848
     * @param  \Closure  $callback
849
     * @param  bool  $onlyIfOutputExists
850
     * @return \Closure
851
     */
852
    protected function withOutputCallback(Closure $callback, $onlyIfOutputExists = false)
853
    {
854
        return function (Container $container) use ($callback, $onlyIfOutputExists) {
855
            $output = $this->output && is_file($this->output) ? file_get_contents($this->output) : '';
856
 
857
            return $onlyIfOutputExists && empty($output)
858
                            ? null
859
                            : $container->call($callback, ['output' => new Stringable($output)]);
860
        };
861
    }
862
 
863
    /**
864
     * Set the human-friendly description of the event.
865
     *
866
     * @param  string  $description
867
     * @return $this
868
     */
869
    public function name($description)
870
    {
871
        return $this->description($description);
872
    }
873
 
874
    /**
875
     * Set the human-friendly description of the event.
876
     *
877
     * @param  string  $description
878
     * @return $this
879
     */
880
    public function description($description)
881
    {
882
        $this->description = $description;
883
 
884
        return $this;
885
    }
886
 
887
    /**
888
     * Get the summary of the event for display.
889
     *
890
     * @return string
891
     */
892
    public function getSummaryForDisplay()
893
    {
894
        if (is_string($this->description)) {
895
            return $this->description;
896
        }
897
 
898
        return $this->buildCommand();
899
    }
900
 
901
    /**
902
     * Determine the next due date for an event.
903
     *
904
     * @param  \DateTimeInterface|string  $currentTime
905
     * @param  int  $nth
906
     * @param  bool  $allowCurrentDate
907
     * @return \Illuminate\Support\Carbon
908
     */
909
    public function nextRunDate($currentTime = 'now', $nth = 0, $allowCurrentDate = false)
910
    {
911
        return Date::instance((new CronExpression($this->getExpression()))
912
            ->getNextRunDate($currentTime, $nth, $allowCurrentDate, $this->timezone));
913
    }
914
 
915
    /**
916
     * Get the Cron expression for the event.
917
     *
918
     * @return string
919
     */
920
    public function getExpression()
921
    {
922
        return $this->expression;
923
    }
924
 
925
    /**
926
     * Set the event mutex implementation to be used.
927
     *
928
     * @param  \Illuminate\Console\Scheduling\EventMutex  $mutex
929
     * @return $this
930
     */
931
    public function preventOverlapsUsing(EventMutex $mutex)
932
    {
933
        $this->mutex = $mutex;
934
 
935
        return $this;
936
    }
937
 
938
    /**
939
     * Get the mutex name for the scheduled command.
940
     *
941
     * @return string
942
     */
943
    public function mutexName()
944
    {
945
        $mutexNameResolver = $this->mutexNameResolver;
946
 
947
        if (! is_null($mutexNameResolver) && is_callable($mutexNameResolver)) {
948
            return $mutexNameResolver($this);
949
        }
950
 
951
        return 'framework'.DIRECTORY_SEPARATOR.'schedule-'.sha1($this->expression.$this->command);
952
    }
953
 
954
    /**
955
     * Set the mutex name or name resolver callback.
956
     *
957
     * @param  \Closure|string  $mutexName
958
     * @return $this
959
     */
960
    public function createMutexNameUsing(Closure|string $mutexName)
961
    {
962
        $this->mutexNameResolver = is_string($mutexName) ? fn () => $mutexName : $mutexName;
963
 
964
        return $this;
965
    }
966
 
967
    /**
968
     * Delete the mutex for the event.
969
     *
970
     * @return void
971
     */
972
    protected function removeMutex()
973
    {
974
        if ($this->withoutOverlapping) {
975
            $this->mutex->forget($this);
976
        }
977
    }
978
}