Add support for executing a scheduled task right now
This commit is contained in:
parent
f33d0b1d72
commit
c1ee0ac4f8
13 changed files with 158 additions and 157 deletions
|
@ -15,16 +15,6 @@ interface ScheduleRepositoryInterface extends RepositoryInterface
|
|||
*/
|
||||
public function findServerSchedules(int $server): Collection;
|
||||
|
||||
/**
|
||||
* Load the tasks relationship onto the Schedule module if they are not
|
||||
* already present.
|
||||
*
|
||||
* @param \Pterodactyl\Models\Schedule $schedule
|
||||
* @param bool $refresh
|
||||
* @return \Pterodactyl\Models\Schedule
|
||||
*/
|
||||
public function loadTasks(Schedule $schedule, bool $refresh = false): Schedule;
|
||||
|
||||
/**
|
||||
* Return a schedule model with all of the associated tasks as a relationship.
|
||||
*
|
||||
|
|
|
@ -10,15 +10,19 @@ use Pterodactyl\Models\Server;
|
|||
use Pterodactyl\Models\Schedule;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Pterodactyl\Helpers\Utilities;
|
||||
use Pterodactyl\Jobs\Schedule\RunTaskJob;
|
||||
use Pterodactyl\Exceptions\DisplayException;
|
||||
use Pterodactyl\Repositories\Eloquent\ScheduleRepository;
|
||||
use Pterodactyl\Services\Schedules\ProcessScheduleService;
|
||||
use Pterodactyl\Transformers\Api\Client\ScheduleTransformer;
|
||||
use Pterodactyl\Http\Controllers\Api\Client\ClientApiController;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
use Pterodactyl\Http\Requests\Api\Client\Servers\Schedules\ViewScheduleRequest;
|
||||
use Pterodactyl\Http\Requests\Api\Client\Servers\Schedules\StoreScheduleRequest;
|
||||
use Pterodactyl\Http\Requests\Api\Client\Servers\Schedules\DeleteScheduleRequest;
|
||||
use Pterodactyl\Http\Requests\Api\Client\Servers\Schedules\UpdateScheduleRequest;
|
||||
use Pterodactyl\Http\Requests\Api\Client\Servers\Schedules\TriggerScheduleRequest;
|
||||
|
||||
class ScheduleController extends ClientApiController
|
||||
{
|
||||
|
@ -27,16 +31,23 @@ class ScheduleController extends ClientApiController
|
|||
*/
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Services\Schedules\ProcessScheduleService
|
||||
*/
|
||||
private $service;
|
||||
|
||||
/**
|
||||
* ScheduleController constructor.
|
||||
*
|
||||
* @param \Pterodactyl\Repositories\Eloquent\ScheduleRepository $repository
|
||||
* @param \Pterodactyl\Services\Schedules\ProcessScheduleService $service
|
||||
*/
|
||||
public function __construct(ScheduleRepository $repository)
|
||||
public function __construct(ScheduleRepository $repository, ProcessScheduleService $service)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->repository = $repository;
|
||||
$this->service = $service;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -147,6 +158,30 @@ class ScheduleController extends ClientApiController
|
|||
->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a given schedule immediately rather than waiting on it's normally scheduled time
|
||||
* to pass. This does not care about the schedule state.
|
||||
*
|
||||
* @param \Pterodactyl\Http\Requests\Api\Client\Servers\Schedules\TriggerScheduleRequest $request
|
||||
* @param \Pterodactyl\Models\Server $server
|
||||
* @param \Pterodactyl\Models\Schedule $schedule
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*
|
||||
* @throws \Throwable
|
||||
*/
|
||||
public function execute(TriggerScheduleRequest $request, Server $server, Schedule $schedule)
|
||||
{
|
||||
if (!$schedule->is_active) {
|
||||
throw new BadRequestHttpException(
|
||||
'Cannot trigger schedule exection for a schedule that is not currently active.'
|
||||
);
|
||||
}
|
||||
|
||||
$this->service->handle($schedule, true);
|
||||
|
||||
return new JsonResponse([], JsonResponse::HTTP_ACCEPTED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a schedule and it's associated tasks.
|
||||
*
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Requests\Api\Client\Servers\Schedules;
|
||||
|
||||
use Pterodactyl\Models\Permission;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class TriggerScheduleRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function permission(): string
|
||||
{
|
||||
return Permission::ACTION_SCHEDULE_UPDATE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
|
@ -42,15 +42,13 @@ class RunTaskJob extends Job implements ShouldQueue
|
|||
* @param \Pterodactyl\Repositories\Wings\DaemonCommandRepository $commandRepository
|
||||
* @param \Pterodactyl\Services\Backups\InitiateBackupService $backupService
|
||||
* @param \Pterodactyl\Repositories\Wings\DaemonPowerRepository $powerRepository
|
||||
* @param \Pterodactyl\Repositories\Eloquent\TaskRepository $taskRepository
|
||||
*
|
||||
* @throws \Throwable
|
||||
*/
|
||||
public function handle(
|
||||
DaemonCommandRepository $commandRepository,
|
||||
InitiateBackupService $backupService,
|
||||
DaemonPowerRepository $powerRepository,
|
||||
TaskRepository $taskRepository
|
||||
DaemonPowerRepository $powerRepository
|
||||
) {
|
||||
// Do not process a task that is not set to active.
|
||||
if (! $this->task->schedule->is_active) {
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
namespace Pterodactyl\Models;
|
||||
|
||||
use Cron\CronExpression;
|
||||
use Carbon\CarbonImmutable;
|
||||
use Illuminate\Container\Container;
|
||||
use Pterodactyl\Contracts\Extensions\HashidsInterface;
|
||||
|
||||
|
@ -114,6 +116,20 @@ class Schedule extends Model
|
|||
'next_run_at' => 'nullable|date',
|
||||
];
|
||||
|
||||
/**
|
||||
* Returns the schedule's execution crontab entry as a string.
|
||||
*
|
||||
* @return \Carbon\CarbonImmutable
|
||||
*/
|
||||
public function getNextRunDate()
|
||||
{
|
||||
$formatted = sprintf('%s %s %s * %s', $this->cron_minute, $this->cron_hour, $this->cron_day_of_month, $this->cron_day_of_week);
|
||||
|
||||
return CarbonImmutable::createFromTimestamp(
|
||||
CronExpression::factory($formatted)->getNextRunDate()->getTimestamp()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a hashid encoded string to represent the ID of the schedule.
|
||||
*
|
||||
|
|
|
@ -31,23 +31,6 @@ class ScheduleRepository extends EloquentRepository implements ScheduleRepositor
|
|||
return $this->getBuilder()->withCount('tasks')->where('server_id', '=', $server)->get($this->getColumns());
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the tasks relationship onto the Schedule module if they are not
|
||||
* already present.
|
||||
*
|
||||
* @param \Pterodactyl\Models\Schedule $schedule
|
||||
* @param bool $refresh
|
||||
* @return \Pterodactyl\Models\Schedule
|
||||
*/
|
||||
public function loadTasks(Schedule $schedule, bool $refresh = false): Schedule
|
||||
{
|
||||
if (! $schedule->relationLoaded('tasks') || $refresh) {
|
||||
$schedule->load('tasks');
|
||||
}
|
||||
|
||||
return $schedule;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a schedule model with all of the associated tasks as a relationship.
|
||||
*
|
||||
|
|
|
@ -2,12 +2,10 @@
|
|||
|
||||
namespace Pterodactyl\Services\Schedules;
|
||||
|
||||
use Cron\CronExpression;
|
||||
use Pterodactyl\Models\Schedule;
|
||||
use Illuminate\Contracts\Bus\Dispatcher;
|
||||
use Pterodactyl\Jobs\Schedule\RunTaskJob;
|
||||
use Pterodactyl\Contracts\Repository\TaskRepositoryInterface;
|
||||
use Pterodactyl\Contracts\Repository\ScheduleRepositoryInterface;
|
||||
use Illuminate\Database\ConnectionInterface;
|
||||
|
||||
class ProcessScheduleService
|
||||
{
|
||||
|
@ -17,62 +15,45 @@ class ProcessScheduleService
|
|||
private $dispatcher;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\ScheduleRepositoryInterface
|
||||
* @var \Illuminate\Database\ConnectionInterface
|
||||
*/
|
||||
private $scheduleRepository;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\TaskRepositoryInterface
|
||||
*/
|
||||
private $taskRepository;
|
||||
private $connection;
|
||||
|
||||
/**
|
||||
* ProcessScheduleService constructor.
|
||||
*
|
||||
* @param \Illuminate\Database\ConnectionInterface $connection
|
||||
* @param \Illuminate\Contracts\Bus\Dispatcher $dispatcher
|
||||
* @param \Pterodactyl\Contracts\Repository\ScheduleRepositoryInterface $scheduleRepository
|
||||
* @param \Pterodactyl\Contracts\Repository\TaskRepositoryInterface $taskRepository
|
||||
*/
|
||||
public function __construct(
|
||||
Dispatcher $dispatcher,
|
||||
ScheduleRepositoryInterface $scheduleRepository,
|
||||
TaskRepositoryInterface $taskRepository
|
||||
) {
|
||||
public function __construct(ConnectionInterface $connection, Dispatcher $dispatcher)
|
||||
{
|
||||
$this->dispatcher = $dispatcher;
|
||||
$this->scheduleRepository = $scheduleRepository;
|
||||
$this->taskRepository = $taskRepository;
|
||||
$this->connection = $connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a schedule and push the first task onto the queue worker.
|
||||
*
|
||||
* @param \Pterodactyl\Models\Schedule $schedule
|
||||
* @param bool $now
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
* @throws \Throwable
|
||||
*/
|
||||
public function handle(Schedule $schedule)
|
||||
public function handle(Schedule $schedule, bool $now = false)
|
||||
{
|
||||
$this->scheduleRepository->loadTasks($schedule);
|
||||
|
||||
/** @var \Pterodactyl\Models\Task $task */
|
||||
$task = $schedule->getRelation('tasks')->where('sequence_id', 1)->first();
|
||||
$task = $schedule->tasks()->where('sequence_id', 1)->firstOrFail();
|
||||
|
||||
$formattedCron = sprintf('%s %s %s * %s',
|
||||
$schedule->cron_minute,
|
||||
$schedule->cron_hour,
|
||||
$schedule->cron_day_of_month,
|
||||
$schedule->cron_day_of_week
|
||||
);
|
||||
$this->connection->transaction(function () use ($schedule, $task) {
|
||||
$schedule->forceFill([
|
||||
'is_processing' => true,
|
||||
'next_run_at' => $schedule->getNextRunDate(),
|
||||
])->saveOrFail();
|
||||
|
||||
$this->scheduleRepository->update($schedule->id, [
|
||||
'is_processing' => true,
|
||||
'next_run_at' => CronExpression::factory($formattedCron)->getNextRunDate(),
|
||||
]);
|
||||
$task->update(['is_queued' => true]);
|
||||
});
|
||||
|
||||
$this->taskRepository->update($task->id, ['is_queued' => true]);
|
||||
|
||||
$this->dispatcher->dispatch(
|
||||
$this->dispatcher->{$now ? 'dispatchNow' : 'dispatch'}(
|
||||
(new RunTaskJob($task))->delay($task->time_offset)
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue