📋 Commit iniziale con: - ✅ Documentazione unificata in docs/ - ✅ Codice Laravel in netgescon-laravel/ - ✅ Script automazione in scripts/ - ✅ Configurazione sync rsync - ✅ Struttura organizzata e pulita 🔄 Versione: 2025.07.19-1644 🎯 Sistema pronto per Git distribuito
860 lines
21 KiB
PHP
860 lines
21 KiB
PHP
<?php
|
|
|
|
namespace Illuminate\Console\Scheduling;
|
|
|
|
use Closure;
|
|
use Cron\CronExpression;
|
|
use GuzzleHttp\Client as HttpClient;
|
|
use GuzzleHttp\ClientInterface as HttpClientInterface;
|
|
use GuzzleHttp\Exception\TransferException;
|
|
use Illuminate\Console\Application;
|
|
use Illuminate\Contracts\Container\Container;
|
|
use Illuminate\Contracts\Debug\ExceptionHandler;
|
|
use Illuminate\Contracts\Mail\Mailer;
|
|
use Illuminate\Support\Arr;
|
|
use Illuminate\Support\Facades\Date;
|
|
use Illuminate\Support\Stringable;
|
|
use Illuminate\Support\Traits\Macroable;
|
|
use Illuminate\Support\Traits\ReflectsClosures;
|
|
use Illuminate\Support\Traits\Tappable;
|
|
use Psr\Http\Client\ClientExceptionInterface;
|
|
use Symfony\Component\Process\Process;
|
|
use Throwable;
|
|
|
|
class Event
|
|
{
|
|
use Macroable, ManagesAttributes, ManagesFrequencies, ReflectsClosures, Tappable;
|
|
|
|
/**
|
|
* The command string.
|
|
*
|
|
* @var string|null
|
|
*/
|
|
public $command;
|
|
|
|
/**
|
|
* The location that output should be sent to.
|
|
*
|
|
* @var string
|
|
*/
|
|
public $output = '/dev/null';
|
|
|
|
/**
|
|
* Indicates whether output should be appended.
|
|
*
|
|
* @var bool
|
|
*/
|
|
public $shouldAppendOutput = false;
|
|
|
|
/**
|
|
* The array of callbacks to be run before the event is started.
|
|
*
|
|
* @var array
|
|
*/
|
|
protected $beforeCallbacks = [];
|
|
|
|
/**
|
|
* The array of callbacks to be run after the event is finished.
|
|
*
|
|
* @var array
|
|
*/
|
|
protected $afterCallbacks = [];
|
|
|
|
/**
|
|
* The event mutex implementation.
|
|
*
|
|
* @var \Illuminate\Console\Scheduling\EventMutex
|
|
*/
|
|
public $mutex;
|
|
|
|
/**
|
|
* The mutex name resolver callback.
|
|
*
|
|
* @var \Closure|null
|
|
*/
|
|
public $mutexNameResolver;
|
|
|
|
/**
|
|
* The last time the event was checked for eligibility to run.
|
|
*
|
|
* Utilized by sub-minute repeated events.
|
|
*
|
|
* @var \Illuminate\Support\Carbon|null
|
|
*/
|
|
protected $lastChecked;
|
|
|
|
/**
|
|
* The exit status code of the command.
|
|
*
|
|
* @var int|null
|
|
*/
|
|
public $exitCode;
|
|
|
|
/**
|
|
* Create a new event instance.
|
|
*
|
|
* @param \Illuminate\Console\Scheduling\EventMutex $mutex
|
|
* @param string $command
|
|
* @param \DateTimeZone|string|null $timezone
|
|
*/
|
|
public function __construct(EventMutex $mutex, $command, $timezone = null)
|
|
{
|
|
$this->mutex = $mutex;
|
|
$this->command = $command;
|
|
$this->timezone = $timezone;
|
|
|
|
$this->output = $this->getDefaultOutput();
|
|
}
|
|
|
|
/**
|
|
* Get the default output depending on the OS.
|
|
*
|
|
* @return string
|
|
*/
|
|
public function getDefaultOutput()
|
|
{
|
|
return (DIRECTORY_SEPARATOR === '\\') ? 'NUL' : '/dev/null';
|
|
}
|
|
|
|
/**
|
|
* Run the given event.
|
|
*
|
|
* @param \Illuminate\Contracts\Container\Container $container
|
|
* @return void
|
|
*
|
|
* @throws \Throwable
|
|
*/
|
|
public function run(Container $container)
|
|
{
|
|
if ($this->shouldSkipDueToOverlapping()) {
|
|
return;
|
|
}
|
|
|
|
$exitCode = $this->start($container);
|
|
|
|
if (! $this->runInBackground) {
|
|
$this->finish($container, $exitCode);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Determine if the event should skip because another process is overlapping.
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function shouldSkipDueToOverlapping()
|
|
{
|
|
return $this->withoutOverlapping && ! $this->mutex->create($this);
|
|
}
|
|
|
|
/**
|
|
* Determine if the event has been configured to repeat multiple times per minute.
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function isRepeatable()
|
|
{
|
|
return ! is_null($this->repeatSeconds);
|
|
}
|
|
|
|
/**
|
|
* Determine if the event is ready to repeat.
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function shouldRepeatNow()
|
|
{
|
|
return $this->isRepeatable()
|
|
&& $this->lastChecked?->diffInSeconds() >= $this->repeatSeconds;
|
|
}
|
|
|
|
/**
|
|
* Run the command process.
|
|
*
|
|
* @param \Illuminate\Contracts\Container\Container $container
|
|
* @return int
|
|
*
|
|
* @throws \Throwable
|
|
*/
|
|
protected function start($container)
|
|
{
|
|
try {
|
|
$this->callBeforeCallbacks($container);
|
|
|
|
return $this->execute($container);
|
|
} catch (Throwable $exception) {
|
|
$this->removeMutex();
|
|
|
|
throw $exception;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Run the command process.
|
|
*
|
|
* @param \Illuminate\Contracts\Container\Container $container
|
|
* @return int
|
|
*/
|
|
protected function execute($container)
|
|
{
|
|
return Process::fromShellCommandline(
|
|
$this->buildCommand(), base_path(), null, null, null
|
|
)->run(
|
|
laravel_cloud()
|
|
? fn ($type, $line) => fwrite($type === 'out' ? STDOUT : STDERR, $line)
|
|
: fn () => true
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Mark the command process as finished and run callbacks/cleanup.
|
|
*
|
|
* @param \Illuminate\Contracts\Container\Container $container
|
|
* @param int $exitCode
|
|
* @return void
|
|
*/
|
|
public function finish(Container $container, $exitCode)
|
|
{
|
|
$this->exitCode = (int) $exitCode;
|
|
|
|
try {
|
|
$this->callAfterCallbacks($container);
|
|
} finally {
|
|
$this->removeMutex();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Call all of the "before" callbacks for the event.
|
|
*
|
|
* @param \Illuminate\Contracts\Container\Container $container
|
|
* @return void
|
|
*/
|
|
public function callBeforeCallbacks(Container $container)
|
|
{
|
|
foreach ($this->beforeCallbacks as $callback) {
|
|
$container->call($callback);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Call all of the "after" callbacks for the event.
|
|
*
|
|
* @param \Illuminate\Contracts\Container\Container $container
|
|
* @return void
|
|
*/
|
|
public function callAfterCallbacks(Container $container)
|
|
{
|
|
foreach ($this->afterCallbacks as $callback) {
|
|
$container->call($callback);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Build the command string.
|
|
*
|
|
* @return string
|
|
*/
|
|
public function buildCommand()
|
|
{
|
|
return (new CommandBuilder)->buildCommand($this);
|
|
}
|
|
|
|
/**
|
|
* Determine if the given event should run based on the Cron expression.
|
|
*
|
|
* @param \Illuminate\Contracts\Foundation\Application $app
|
|
* @return bool
|
|
*/
|
|
public function isDue($app)
|
|
{
|
|
if (! $this->runsInMaintenanceMode() && $app->isDownForMaintenance()) {
|
|
return false;
|
|
}
|
|
|
|
return $this->expressionPasses() &&
|
|
$this->runsInEnvironment($app->environment());
|
|
}
|
|
|
|
/**
|
|
* Determine if the event runs in maintenance mode.
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function runsInMaintenanceMode()
|
|
{
|
|
return $this->evenInMaintenanceMode;
|
|
}
|
|
|
|
/**
|
|
* Determine if the Cron expression passes.
|
|
*
|
|
* @return bool
|
|
*/
|
|
protected function expressionPasses()
|
|
{
|
|
$date = Date::now();
|
|
|
|
if ($this->timezone) {
|
|
$date = $date->setTimezone($this->timezone);
|
|
}
|
|
|
|
return (new CronExpression($this->expression))->isDue($date->toDateTimeString());
|
|
}
|
|
|
|
/**
|
|
* Determine if the event runs in the given environment.
|
|
*
|
|
* @param string $environment
|
|
* @return bool
|
|
*/
|
|
public function runsInEnvironment($environment)
|
|
{
|
|
return empty($this->environments) || in_array($environment, $this->environments);
|
|
}
|
|
|
|
/**
|
|
* Determine if the filters pass for the event.
|
|
*
|
|
* @param \Illuminate\Contracts\Foundation\Application $app
|
|
* @return bool
|
|
*/
|
|
public function filtersPass($app)
|
|
{
|
|
$this->lastChecked = Date::now();
|
|
|
|
foreach ($this->filters as $callback) {
|
|
if (! $app->call($callback)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
foreach ($this->rejects as $callback) {
|
|
if ($app->call($callback)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Ensure that the output is stored on disk in a log file.
|
|
*
|
|
* @return $this
|
|
*/
|
|
public function storeOutput()
|
|
{
|
|
$this->ensureOutputIsBeingCaptured();
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Send the output of the command to a given location.
|
|
*
|
|
* @param string $location
|
|
* @param bool $append
|
|
* @return $this
|
|
*/
|
|
public function sendOutputTo($location, $append = false)
|
|
{
|
|
$this->output = $location;
|
|
|
|
$this->shouldAppendOutput = $append;
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Append the output of the command to a given location.
|
|
*
|
|
* @param string $location
|
|
* @return $this
|
|
*/
|
|
public function appendOutputTo($location)
|
|
{
|
|
return $this->sendOutputTo($location, true);
|
|
}
|
|
|
|
/**
|
|
* E-mail the results of the scheduled operation.
|
|
*
|
|
* @param array|mixed $addresses
|
|
* @param bool $onlyIfOutputExists
|
|
* @return $this
|
|
*
|
|
* @throws \LogicException
|
|
*/
|
|
public function emailOutputTo($addresses, $onlyIfOutputExists = true)
|
|
{
|
|
$this->ensureOutputIsBeingCaptured();
|
|
|
|
$addresses = Arr::wrap($addresses);
|
|
|
|
return $this->then(function (Mailer $mailer) use ($addresses, $onlyIfOutputExists) {
|
|
$this->emailOutput($mailer, $addresses, $onlyIfOutputExists);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* E-mail the results of the scheduled operation if it produces output.
|
|
*
|
|
* @param array|mixed $addresses
|
|
* @return $this
|
|
*
|
|
* @throws \LogicException
|
|
*/
|
|
public function emailWrittenOutputTo($addresses)
|
|
{
|
|
return $this->emailOutputTo($addresses, true);
|
|
}
|
|
|
|
/**
|
|
* E-mail the results of the scheduled operation if it fails.
|
|
*
|
|
* @param array|mixed $addresses
|
|
* @return $this
|
|
*/
|
|
public function emailOutputOnFailure($addresses)
|
|
{
|
|
$this->ensureOutputIsBeingCaptured();
|
|
|
|
$addresses = Arr::wrap($addresses);
|
|
|
|
return $this->onFailure(function (Mailer $mailer) use ($addresses) {
|
|
$this->emailOutput($mailer, $addresses, false);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Ensure that the command output is being captured.
|
|
*
|
|
* @return void
|
|
*/
|
|
protected function ensureOutputIsBeingCaptured()
|
|
{
|
|
if (is_null($this->output) || $this->output == $this->getDefaultOutput()) {
|
|
$this->sendOutputTo(storage_path('logs/schedule-'.sha1($this->mutexName()).'.log'));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* E-mail the output of the event to the recipients.
|
|
*
|
|
* @param \Illuminate\Contracts\Mail\Mailer $mailer
|
|
* @param array $addresses
|
|
* @param bool $onlyIfOutputExists
|
|
* @return void
|
|
*/
|
|
protected function emailOutput(Mailer $mailer, $addresses, $onlyIfOutputExists = true)
|
|
{
|
|
$text = is_file($this->output) ? file_get_contents($this->output) : '';
|
|
|
|
if ($onlyIfOutputExists && empty($text)) {
|
|
return;
|
|
}
|
|
|
|
$mailer->raw($text, function ($m) use ($addresses) {
|
|
$m->to($addresses)->subject($this->getEmailSubject());
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Get the e-mail subject line for output results.
|
|
*
|
|
* @return string
|
|
*/
|
|
protected function getEmailSubject()
|
|
{
|
|
if ($this->description) {
|
|
return $this->description;
|
|
}
|
|
|
|
return "Scheduled Job Output For [{$this->command}]";
|
|
}
|
|
|
|
/**
|
|
* Register a callback to ping a given URL before the job runs.
|
|
*
|
|
* @param string $url
|
|
* @return $this
|
|
*/
|
|
public function pingBefore($url)
|
|
{
|
|
return $this->before($this->pingCallback($url));
|
|
}
|
|
|
|
/**
|
|
* Register a callback to ping a given URL before the job runs if the given condition is true.
|
|
*
|
|
* @param bool $value
|
|
* @param string $url
|
|
* @return $this
|
|
*/
|
|
public function pingBeforeIf($value, $url)
|
|
{
|
|
return $value ? $this->pingBefore($url) : $this;
|
|
}
|
|
|
|
/**
|
|
* Register a callback to ping a given URL after the job runs.
|
|
*
|
|
* @param string $url
|
|
* @return $this
|
|
*/
|
|
public function thenPing($url)
|
|
{
|
|
return $this->then($this->pingCallback($url));
|
|
}
|
|
|
|
/**
|
|
* Register a callback to ping a given URL after the job runs if the given condition is true.
|
|
*
|
|
* @param bool $value
|
|
* @param string $url
|
|
* @return $this
|
|
*/
|
|
public function thenPingIf($value, $url)
|
|
{
|
|
return $value ? $this->thenPing($url) : $this;
|
|
}
|
|
|
|
/**
|
|
* Register a callback to ping a given URL if the operation succeeds.
|
|
*
|
|
* @param string $url
|
|
* @return $this
|
|
*/
|
|
public function pingOnSuccess($url)
|
|
{
|
|
return $this->onSuccess($this->pingCallback($url));
|
|
}
|
|
|
|
/**
|
|
* Register a callback to ping a given URL if the operation succeeds and if the given condition is true.
|
|
*
|
|
* @param bool $value
|
|
* @param string $url
|
|
* @return $this
|
|
*/
|
|
public function pingOnSuccessIf($value, $url)
|
|
{
|
|
return $value ? $this->onSuccess($this->pingCallback($url)) : $this;
|
|
}
|
|
|
|
/**
|
|
* Register a callback to ping a given URL if the operation fails.
|
|
*
|
|
* @param string $url
|
|
* @return $this
|
|
*/
|
|
public function pingOnFailure($url)
|
|
{
|
|
return $this->onFailure($this->pingCallback($url));
|
|
}
|
|
|
|
/**
|
|
* Register a callback to ping a given URL if the operation fails and if the given condition is true.
|
|
*
|
|
* @param bool $value
|
|
* @param string $url
|
|
* @return $this
|
|
*/
|
|
public function pingOnFailureIf($value, $url)
|
|
{
|
|
return $value ? $this->onFailure($this->pingCallback($url)) : $this;
|
|
}
|
|
|
|
/**
|
|
* Get the callback that pings the given URL.
|
|
*
|
|
* @param string $url
|
|
* @return \Closure
|
|
*/
|
|
protected function pingCallback($url)
|
|
{
|
|
return function (Container $container) use ($url) {
|
|
try {
|
|
$this->getHttpClient($container)->request('GET', $url);
|
|
} catch (ClientExceptionInterface|TransferException $e) {
|
|
$container->make(ExceptionHandler::class)->report($e);
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Get the Guzzle HTTP client to use to send pings.
|
|
*
|
|
* @param \Illuminate\Contracts\Container\Container $container
|
|
* @return \GuzzleHttp\ClientInterface
|
|
*/
|
|
protected function getHttpClient(Container $container)
|
|
{
|
|
return match (true) {
|
|
$container->bound(HttpClientInterface::class) => $container->make(HttpClientInterface::class),
|
|
$container->bound(HttpClient::class) => $container->make(HttpClient::class),
|
|
default => new HttpClient([
|
|
'connect_timeout' => 10,
|
|
'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT,
|
|
'timeout' => 30,
|
|
]),
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Register a callback to be called before the operation.
|
|
*
|
|
* @param \Closure $callback
|
|
* @return $this
|
|
*/
|
|
public function before(Closure $callback)
|
|
{
|
|
$this->beforeCallbacks[] = $callback;
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Register a callback to be called after the operation.
|
|
*
|
|
* @param \Closure $callback
|
|
* @return $this
|
|
*/
|
|
public function after(Closure $callback)
|
|
{
|
|
return $this->then($callback);
|
|
}
|
|
|
|
/**
|
|
* Register a callback to be called after the operation.
|
|
*
|
|
* @param \Closure $callback
|
|
* @return $this
|
|
*/
|
|
public function then(Closure $callback)
|
|
{
|
|
$parameters = $this->closureParameterTypes($callback);
|
|
|
|
if (Arr::get($parameters, 'output') === Stringable::class) {
|
|
return $this->thenWithOutput($callback);
|
|
}
|
|
|
|
$this->afterCallbacks[] = $callback;
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Register a callback that uses the output after the job runs.
|
|
*
|
|
* @param \Closure $callback
|
|
* @param bool $onlyIfOutputExists
|
|
* @return $this
|
|
*/
|
|
public function thenWithOutput(Closure $callback, $onlyIfOutputExists = false)
|
|
{
|
|
$this->ensureOutputIsBeingCaptured();
|
|
|
|
return $this->then($this->withOutputCallback($callback, $onlyIfOutputExists));
|
|
}
|
|
|
|
/**
|
|
* Register a callback to be called if the operation succeeds.
|
|
*
|
|
* @param \Closure $callback
|
|
* @return $this
|
|
*/
|
|
public function onSuccess(Closure $callback)
|
|
{
|
|
$parameters = $this->closureParameterTypes($callback);
|
|
|
|
if (Arr::get($parameters, 'output') === Stringable::class) {
|
|
return $this->onSuccessWithOutput($callback);
|
|
}
|
|
|
|
return $this->then(function (Container $container) use ($callback) {
|
|
if ($this->exitCode === 0) {
|
|
$container->call($callback);
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Register a callback that uses the output if the operation succeeds.
|
|
*
|
|
* @param \Closure $callback
|
|
* @param bool $onlyIfOutputExists
|
|
* @return $this
|
|
*/
|
|
public function onSuccessWithOutput(Closure $callback, $onlyIfOutputExists = false)
|
|
{
|
|
$this->ensureOutputIsBeingCaptured();
|
|
|
|
return $this->onSuccess($this->withOutputCallback($callback, $onlyIfOutputExists));
|
|
}
|
|
|
|
/**
|
|
* Register a callback to be called if the operation fails.
|
|
*
|
|
* @param \Closure $callback
|
|
* @return $this
|
|
*/
|
|
public function onFailure(Closure $callback)
|
|
{
|
|
$parameters = $this->closureParameterTypes($callback);
|
|
|
|
if (Arr::get($parameters, 'output') === Stringable::class) {
|
|
return $this->onFailureWithOutput($callback);
|
|
}
|
|
|
|
return $this->then(function (Container $container) use ($callback) {
|
|
if ($this->exitCode !== 0) {
|
|
$container->call($callback);
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Register a callback that uses the output if the operation fails.
|
|
*
|
|
* @param \Closure $callback
|
|
* @param bool $onlyIfOutputExists
|
|
* @return $this
|
|
*/
|
|
public function onFailureWithOutput(Closure $callback, $onlyIfOutputExists = false)
|
|
{
|
|
$this->ensureOutputIsBeingCaptured();
|
|
|
|
return $this->onFailure($this->withOutputCallback($callback, $onlyIfOutputExists));
|
|
}
|
|
|
|
/**
|
|
* Get a callback that provides output.
|
|
*
|
|
* @param \Closure $callback
|
|
* @param bool $onlyIfOutputExists
|
|
* @return \Closure
|
|
*/
|
|
protected function withOutputCallback(Closure $callback, $onlyIfOutputExists = false)
|
|
{
|
|
return function (Container $container) use ($callback, $onlyIfOutputExists) {
|
|
$output = $this->output && is_file($this->output) ? file_get_contents($this->output) : '';
|
|
|
|
return $onlyIfOutputExists && empty($output)
|
|
? null
|
|
: $container->call($callback, ['output' => new Stringable($output)]);
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Get the summary of the event for display.
|
|
*
|
|
* @return string
|
|
*/
|
|
public function getSummaryForDisplay()
|
|
{
|
|
if (is_string($this->description)) {
|
|
return $this->description;
|
|
}
|
|
|
|
return $this->buildCommand();
|
|
}
|
|
|
|
/**
|
|
* Determine the next due date for an event.
|
|
*
|
|
* @param \DateTimeInterface|string $currentTime
|
|
* @param int $nth
|
|
* @param bool $allowCurrentDate
|
|
* @return \Illuminate\Support\Carbon
|
|
*/
|
|
public function nextRunDate($currentTime = 'now', $nth = 0, $allowCurrentDate = false)
|
|
{
|
|
return Date::instance((new CronExpression($this->getExpression()))
|
|
->getNextRunDate($currentTime, $nth, $allowCurrentDate, $this->timezone));
|
|
}
|
|
|
|
/**
|
|
* Get the Cron expression for the event.
|
|
*
|
|
* @return string
|
|
*/
|
|
public function getExpression()
|
|
{
|
|
return $this->expression;
|
|
}
|
|
|
|
/**
|
|
* Set the event mutex implementation to be used.
|
|
*
|
|
* @param \Illuminate\Console\Scheduling\EventMutex $mutex
|
|
* @return $this
|
|
*/
|
|
public function preventOverlapsUsing(EventMutex $mutex)
|
|
{
|
|
$this->mutex = $mutex;
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Get the mutex name for the scheduled command.
|
|
*
|
|
* @return string
|
|
*/
|
|
public function mutexName()
|
|
{
|
|
$mutexNameResolver = $this->mutexNameResolver;
|
|
|
|
if (! is_null($mutexNameResolver) && is_callable($mutexNameResolver)) {
|
|
return $mutexNameResolver($this);
|
|
}
|
|
|
|
return 'framework'.DIRECTORY_SEPARATOR.'schedule-'.
|
|
sha1($this->expression.$this->normalizeCommand($this->command ?? ''));
|
|
}
|
|
|
|
/**
|
|
* Set the mutex name or name resolver callback.
|
|
*
|
|
* @param \Closure|string $mutexName
|
|
* @return $this
|
|
*/
|
|
public function createMutexNameUsing(Closure|string $mutexName)
|
|
{
|
|
$this->mutexNameResolver = is_string($mutexName) ? fn () => $mutexName : $mutexName;
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Delete the mutex for the event.
|
|
*
|
|
* @return void
|
|
*/
|
|
protected function removeMutex()
|
|
{
|
|
if ($this->withoutOverlapping) {
|
|
$this->mutex->forget($this);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Format the given command string with a normalized PHP binary path.
|
|
*
|
|
* @param string $command
|
|
* @return string
|
|
*/
|
|
public static function normalizeCommand($command)
|
|
{
|
|
return str_replace([
|
|
Application::phpBinary(),
|
|
Application::artisanBinary(),
|
|
], [
|
|
'php',
|
|
preg_replace("#['\"]#", '', Application::artisanBinary()),
|
|
], $command);
|
|
}
|
|
}
|