Lance Pioch 82409f2fba
Laravel 12.x Shift (#1045)
* Convert route options to fluent methods

Laravel 8 adopts the tuple syntax for controller actions. Since the old options array is incompatible with this syntax, Shift converted them to use modern, fluent methods.

* Slim `lang` files

* Shift core files

* Validate via object directly within Controllers

* Use `Gate` facade for controller authorization

* Dispatch jobs directly

* Remove base controller inheritance

* Default config files

In an effort to make upgrading the constantly changing config files easier, Shift defaulted them and merged your true customizations - where ENV variables may not be used.

* Set new `ENV` variables

* Add new Laravel `composer run dev` script

* Add `storage/app/private` folder

* Bump Composer dependencies

* Convert `$casts` property to method

* Adopt Laravel type hints

* Shift cleanup

* Apply suggestions from code review

Co-authored-by: MartinOscar <40749467+rmartinoscar@users.noreply.github.com>

* Add old key as backup

* Update composer

* Remove extra line

* Update this

---------

Co-authored-by: Shift <shift@laravelshift.com>
Co-authored-by: MartinOscar <40749467+rmartinoscar@users.noreply.github.com>
2025-03-03 14:41:00 -05:00

136 lines
4.3 KiB
PHP

<?php
namespace App\Jobs\Schedule;
use App\Jobs\Job;
use Carbon\CarbonImmutable;
use App\Models\Task;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use App\Services\Backups\InitiateBackupService;
use App\Repositories\Daemon\DaemonPowerRepository;
use App\Services\Files\DeleteFilesService;
use Exception;
use Illuminate\Http\Client\ConnectionException;
class RunTaskJob extends Job implements ShouldQueue
{
use InteractsWithQueue;
use SerializesModels;
/**
* RunTaskJob constructor.
*/
public function __construct(public Task $task, public bool $manualRun = false) {}
/**
* Run the job and send actions to the daemon running the server.
*
* @throws \Throwable
*/
public function handle(
InitiateBackupService $backupService,
DaemonPowerRepository $powerRepository,
DeleteFilesService $deleteFilesService
): void {
// Do not process a task that is not set to active, unless it's been manually triggered.
if (!$this->task->schedule->is_active && !$this->manualRun) {
$this->markTaskNotQueued();
$this->markScheduleComplete();
return;
}
$server = $this->task->server;
// If we made it to this point and the server status is not null it means the
// server was likely suspended or marked as reinstalling after the schedule
// was queued up. Just end the task right now — this should be a very rare
// condition.
if (!is_null($server->status)) {
$this->failed();
return;
}
// Perform the provided task against the daemon.
try {
switch ($this->task->action) {
case Task::ACTION_POWER:
$powerRepository->setServer($server)->send($this->task->payload);
break;
case Task::ACTION_COMMAND:
$server->send($this->task->payload);
break;
case Task::ACTION_BACKUP:
$backupService->setIgnoredFiles(explode(PHP_EOL, $this->task->payload))->handle($server, null, true);
break;
case Task::ACTION_DELETE_FILES:
$deleteFilesService->handle($server, explode(PHP_EOL, $this->task->payload));
break;
default:
throw new \InvalidArgumentException('Invalid task action provided: ' . $this->task->action);
}
} catch (Exception $exception) {
// If this isn't a ConnectionException on a task that allows for failures
// throw the exception back up the chain so that the task is stopped.
if (!($this->task->continue_on_failure && $exception instanceof ConnectionException)) {
throw $exception;
}
}
$this->markTaskNotQueued();
$this->queueNextTask();
}
/**
* Handle a failure while sending the action to the daemon or otherwise processing the job.
*/
public function failed(): void
{
$this->markTaskNotQueued();
$this->markScheduleComplete();
}
/**
* Get the next task in the schedule and queue it for running after the defined period of wait time.
*/
private function queueNextTask(): void
{
/** @var \App\Models\Task|null $nextTask */
$nextTask = Task::query()->where('schedule_id', $this->task->schedule_id)
->orderBy('sequence_id', 'asc')
->where('sequence_id', '>', $this->task->sequence_id)
->first();
if (is_null($nextTask)) {
$this->markScheduleComplete();
return;
}
$nextTask->update(['is_queued' => true]);
dispatch((new self($nextTask, $this->manualRun))->delay($nextTask->time_offset));
}
/**
* Marks the parent schedule as being complete.
*/
private function markScheduleComplete(): void
{
$this->task->schedule()->update([
'is_processing' => false,
'last_run_at' => CarbonImmutable::now()->toDateTimeString(),
]);
}
/**
* Mark a specific task as no longer being queued.
*/
private function markTaskNotQueued(): void
{
$this->task->update(['is_queued' => false]);
}
}