Begin adding schedule processing jobs.
This commit is contained in:
parent
c0d7e02481
commit
c5f2dfd6f6
16 changed files with 626 additions and 49 deletions
110
app/Console/Commands/Schedule/ProcessRunnableCommand.php
Normal file
110
app/Console/Commands/Schedule/ProcessRunnableCommand.php
Normal file
|
@ -0,0 +1,110 @@
|
|||
<?php
|
||||
/*
|
||||
* Pterodactyl - Panel
|
||||
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
namespace Pterodactyl\Console\Commands\Schedule;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Collection;
|
||||
use Pterodactyl\Services\Schedules\ProcessScheduleService;
|
||||
use Pterodactyl\Contracts\Repository\ScheduleRepositoryInterface;
|
||||
|
||||
class ProcessRunnableCommand extends Command
|
||||
{
|
||||
/**
|
||||
* @var \Carbon\Carbon
|
||||
*/
|
||||
protected $carbon;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Process schedules in the database and determine which are ready to run.';
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Services\Schedules\ProcessScheduleService
|
||||
*/
|
||||
protected $processScheduleService;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\ScheduleRepositoryInterface
|
||||
*/
|
||||
protected $repository;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'p:schedule:process';
|
||||
|
||||
/**
|
||||
* ProcessRunnableCommand constructor.
|
||||
*
|
||||
* @param \Carbon\Carbon $carbon
|
||||
* @param \Pterodactyl\Services\Schedules\ProcessScheduleService $processScheduleService
|
||||
* @param \Pterodactyl\Contracts\Repository\ScheduleRepositoryInterface $repository
|
||||
*/
|
||||
public function __construct(
|
||||
Carbon $carbon,
|
||||
ProcessScheduleService $processScheduleService,
|
||||
ScheduleRepositoryInterface $repository
|
||||
) {
|
||||
parent::__construct();
|
||||
|
||||
$this->carbon = $carbon;
|
||||
$this->processScheduleService = $processScheduleService;
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle command execution.
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$schedules = $this->repository->getSchedulesToProcess($this->carbon->now()->toAtomString());
|
||||
|
||||
$bar = $this->output->createProgressBar(count($schedules));
|
||||
foreach ($schedules as $schedule) {
|
||||
if (! $schedule->tasks instanceof Collection || count($schedule->tasks) < 1) {
|
||||
$bar->advance();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->processScheduleService->handle($schedule);
|
||||
if ($this->input->isInteractive()) {
|
||||
$this->line(trans('command/messages.schedule.output_line', [
|
||||
'schedule' => $schedule->name,
|
||||
'hash' => $schedule->hashid,
|
||||
]));
|
||||
}
|
||||
|
||||
$bar->advance();
|
||||
}
|
||||
|
||||
$this->line('');
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@ use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
|
|||
use Pterodactyl\Console\Commands\Location\MakeLocationCommand;
|
||||
use Pterodactyl\Console\Commands\User\DisableTwoFactorCommand;
|
||||
use Pterodactyl\Console\Commands\Location\DeleteLocationCommand;
|
||||
use Pterodactyl\Console\Commands\Schedule\ProcessRunnableCommand;
|
||||
|
||||
class Kernel extends ConsoleKernel
|
||||
{
|
||||
|
@ -25,17 +26,7 @@ class Kernel extends ConsoleKernel
|
|||
InfoCommand::class,
|
||||
MakeLocationCommand::class,
|
||||
MakeUserCommand::class,
|
||||
// \Pterodactyl\Console\Commands\MakeUser::class,
|
||||
// \Pterodactyl\Console\Commands\ShowVersion::class,
|
||||
// \Pterodactyl\Console\Commands\UpdateEnvironment::class,
|
||||
// \Pterodactyl\Console\Commands\RunTasks::class,
|
||||
// \Pterodactyl\Console\Commands\ClearTasks::class,
|
||||
// \Pterodactyl\Console\Commands\ClearServices::class,
|
||||
// \Pterodactyl\Console\Commands\UpdateEmailSettings::class,
|
||||
// \Pterodactyl\Console\Commands\CleanServiceBackup::class,
|
||||
// \Pterodactyl\Console\Commands\AddNode::class,
|
||||
// \Pterodactyl\Console\Commands\MakeLocationCommand::class,
|
||||
// \Pterodactyl\Console\Commands\RebuildServer::class,
|
||||
ProcessRunnableCommand::class,
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -45,8 +36,8 @@ class Kernel extends ConsoleKernel
|
|||
*/
|
||||
protected function schedule(Schedule $schedule)
|
||||
{
|
||||
$schedule->command('pterodactyl:tasks')->everyMinute()->withoutOverlapping();
|
||||
$schedule->command('pterodactyl:tasks:clearlog')->twiceDaily(3, 15);
|
||||
$schedule->command('pterodactyl:cleanservices')->twiceDaily(1, 13);
|
||||
// $schedule->command('pterodactyl:tasks')->everyMinute()->withoutOverlapping();
|
||||
// $schedule->command('pterodactyl:tasks:clearlog')->twiceDaily(3, 15);
|
||||
// $schedule->command('pterodactyl:cleanservices')->twiceDaily(1, 13);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,4 +41,12 @@ interface ScheduleRepositoryInterface extends RepositoryInterface
|
|||
* @return \Illuminate\Support\Collection
|
||||
*/
|
||||
public function getScheduleWithTasks($schedule);
|
||||
|
||||
/**
|
||||
* Return all of the schedules that should be processed.
|
||||
*
|
||||
* @param string $timestamp
|
||||
* @return \Illuminate\Support\Collection
|
||||
*/
|
||||
public function getSchedulesToProcess($timestamp);
|
||||
}
|
||||
|
|
|
@ -26,4 +26,22 @@ namespace Pterodactyl\Contracts\Repository;
|
|||
|
||||
interface TaskRepositoryInterface extends RepositoryInterface
|
||||
{
|
||||
/**
|
||||
* Get a task and the server relationship for that task.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Pterodactyl\Models\Task
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
public function getTaskWithServer($id);
|
||||
|
||||
/**
|
||||
* Returns the next task in a schedule.
|
||||
*
|
||||
* @param int $schedule the ID of the schedule to select the next task from
|
||||
* @param int $index the index of the current task
|
||||
* @return null|\Pterodactyl\Models\Task
|
||||
*/
|
||||
public function getNextTask($schedule, $index);
|
||||
}
|
||||
|
|
191
app/Jobs/Schedule/RunTaskJob.php
Normal file
191
app/Jobs/Schedule/RunTaskJob.php
Normal file
|
@ -0,0 +1,191 @@
|
|||
<?php
|
||||
/*
|
||||
* Pterodactyl - Panel
|
||||
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
namespace Pterodactyl\Jobs\Schedule;
|
||||
|
||||
use Exception;
|
||||
use Carbon\Carbon;
|
||||
use Pterodactyl\Jobs\Job;
|
||||
use Webmozart\Assert\Assert;
|
||||
use InvalidArgumentException;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||
use Pterodactyl\Contracts\Repository\TaskRepositoryInterface;
|
||||
use Pterodactyl\Contracts\Repository\ScheduleRepositoryInterface;
|
||||
use Pterodactyl\Contracts\Repository\Daemon\PowerRepositoryInterface;
|
||||
use Pterodactyl\Contracts\Repository\Daemon\CommandRepositoryInterface;
|
||||
|
||||
class RunTaskJob extends Job implements ShouldQueue
|
||||
{
|
||||
use DispatchesJobs, InteractsWithQueue, SerializesModels;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\Daemon\CommandRepositoryInterface
|
||||
*/
|
||||
protected $commandRepository;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\Daemon\PowerRepositoryInterface
|
||||
*/
|
||||
protected $powerRepository;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $schedule;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $task;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\TaskRepositoryInterface
|
||||
*/
|
||||
protected $taskRepository;
|
||||
|
||||
/**
|
||||
* RunTaskJob constructor.
|
||||
*
|
||||
* @param int $task
|
||||
* @param int $schedule
|
||||
*/
|
||||
public function __construct($task, $schedule)
|
||||
{
|
||||
Assert::integerish($task, 'First argument passed to constructor must be numeric, received %s.');
|
||||
|
||||
$this->queue = app()->make('config')->get('pterodactyl.queues.standard');
|
||||
$this->task = $task;
|
||||
$this->schedule = $schedule;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the job and send actions to the daemon running the server.
|
||||
*
|
||||
* @param \Pterodactyl\Contracts\Repository\Daemon\CommandRepositoryInterface $commandRepository
|
||||
* @param \Pterodactyl\Contracts\Repository\Daemon\PowerRepositoryInterface $powerRepository
|
||||
* @param \Pterodactyl\Contracts\Repository\TaskRepositoryInterface $taskRepository
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\Daemon\InvalidPowerSignalException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
public function handle(
|
||||
CommandRepositoryInterface $commandRepository,
|
||||
PowerRepositoryInterface $powerRepository,
|
||||
TaskRepositoryInterface $taskRepository
|
||||
) {
|
||||
$this->commandRepository = $commandRepository;
|
||||
$this->powerRepository = $powerRepository;
|
||||
$this->taskRepository = $taskRepository;
|
||||
|
||||
$task = $this->taskRepository->getTaskWithServer($this->task);
|
||||
$server = $task->server;
|
||||
|
||||
// Perform the provided task aganist the daemon.
|
||||
switch ($task->action) {
|
||||
case 'power':
|
||||
$this->powerRepository->setNode($server->node_id)
|
||||
->setAccessServer($server->uuid)
|
||||
->setAccessToken($server->daemonSecret)
|
||||
->sendSignal($task->payload);
|
||||
break;
|
||||
case 'command':
|
||||
$this->commandRepository->setNode($server->node_id)
|
||||
->setAccessServer($server->uuid)
|
||||
->setAccessToken($server->daemonSecret)
|
||||
->send($task->payload);
|
||||
break;
|
||||
default:
|
||||
throw new InvalidArgumentException('Cannot run a task that points to a non-existant action.');
|
||||
}
|
||||
|
||||
$this->markTaskNotQueued();
|
||||
$this->queueNextTask($task->sequence_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a failure while sending the action to the daemon or otherwise processing the job.
|
||||
*
|
||||
* @param null|\Exception $exception
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
public function failed(Exception $exception = null)
|
||||
{
|
||||
$this->markTaskNotQueued();
|
||||
$this->markScheduleComplete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next task in the schedule and queue it for running after the defined period of wait time.
|
||||
*
|
||||
* @param int $sequence
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
private function queueNextTask($sequence)
|
||||
{
|
||||
$nextTask = $this->taskRepository->getNextTask($this->schedule, $sequence);
|
||||
if (is_null($nextTask)) {
|
||||
$this->markScheduleComplete();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->taskRepository->update($nextTask->id, ['is_queued' => true]);
|
||||
$this->dispatch((new self($nextTask->id, $this->schedule))->delay($nextTask->time_offset));
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the parent schedule as being complete.
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
private function markScheduleComplete()
|
||||
{
|
||||
$repository = app()->make(ScheduleRepositoryInterface::class);
|
||||
$repository->withoutFresh()->update($this->schedule, [
|
||||
'is_processing' => false,
|
||||
'last_run_at' => app()->make(Carbon::class)->now()->toDateTimeString(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark a specific task as no longer being queued.
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
private function markTaskNotQueued()
|
||||
{
|
||||
$repository = app()->make(TaskRepositoryInterface::class);
|
||||
$repository->update($this->task, ['is_queued' => false]);
|
||||
}
|
||||
}
|
|
@ -117,8 +117,8 @@ class Schedule extends Model implements CleansAttributes, ValidableContract
|
|||
'cron_minute' => 'string',
|
||||
'is_active' => 'boolean',
|
||||
'is_processing' => 'boolean',
|
||||
'last_run_at' => 'nullable|timestamp',
|
||||
'next_run_at' => 'nullable|timestamp',
|
||||
'last_run_at' => 'nullable|date',
|
||||
'next_run_at' => 'nullable|date',
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
|
@ -27,12 +27,13 @@ namespace Pterodactyl\Models;
|
|||
use Sofa\Eloquence\Eloquence;
|
||||
use Sofa\Eloquence\Validable;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Znck\Eloquent\Traits\BelongsToThrough;
|
||||
use Sofa\Eloquence\Contracts\CleansAttributes;
|
||||
use Sofa\Eloquence\Contracts\Validable as ValidableContract;
|
||||
|
||||
class Task extends Model implements CleansAttributes, ValidableContract
|
||||
{
|
||||
use Eloquence, Validable;
|
||||
use BelongsToThrough, Eloquence, Validable;
|
||||
|
||||
/**
|
||||
* The table associated with the model.
|
||||
|
@ -130,14 +131,11 @@ class Task extends Model implements CleansAttributes, ValidableContract
|
|||
/**
|
||||
* Return the server a task is assigned to, acts as a belongsToThrough.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
* @return \Znck\Eloquent\Relations\BelongsToThrough
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function server()
|
||||
{
|
||||
if ($schedule = $this->schedule) {
|
||||
return $schedule->server();
|
||||
} else {
|
||||
throw new \InvalidArgumentException('Instance of Task must have an associated Schedule in the database.');
|
||||
}
|
||||
return $this->belongsToThrough(Server::class, Schedule::class);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,4 +52,15 @@ class ScheduleRepository extends EloquentRepository implements ScheduleRepositor
|
|||
{
|
||||
return $this->getBuilder()->with('tasks')->find($schedule, $this->getColumns());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSchedulesToProcess($timestamp)
|
||||
{
|
||||
return $this->getBuilder()->with('tasks')
|
||||
->where('is_active', true)
|
||||
->where('next_run_at', '<=', $timestamp)
|
||||
->get($this->getColumns());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,33 +42,28 @@ class TaskRepository extends EloquentRepository implements TaskRepositoryInterfa
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getParentTasksWithChainCount($server)
|
||||
public function getTaskWithServer($id)
|
||||
{
|
||||
Assert::numeric($server, 'First argument passed to GetParentTasksWithChainCount must be numeric, received %s.');
|
||||
|
||||
return $this->getBuilder()->withCount('chained')->where([
|
||||
['server_id', '=', $server],
|
||||
['parent_task_id', '=', null],
|
||||
])->get($this->getColumns());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getTaskForServer($task, $server)
|
||||
{
|
||||
Assert::numeric($task, 'First argument passed to getTaskForServer must be numeric, received %s.');
|
||||
Assert::numeric($server, 'Second argument passed to getTaskForServer must be numeric, received %s.');
|
||||
|
||||
$instance = $this->getBuilder()->with('chained')->where([
|
||||
['server_id', '=', $server],
|
||||
['parent_task_id', '=', null],
|
||||
])->find($task, $this->getColumns());
|
||||
Assert::integerish($id, 'First argument passed to getTaskWithServer must be numeric, received %s.');
|
||||
|
||||
$instance = $this->getBuilder()->with('server')->find($id, $this->getColumns());
|
||||
if (! $instance) {
|
||||
throw new RecordNotFoundException;
|
||||
}
|
||||
|
||||
return $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getNextTask($schedule, $index)
|
||||
{
|
||||
Assert::integerish($schedule, 'First argument passed to getNextTask must be integer, received %s.');
|
||||
Assert::integerish($index, 'Second argument passed to getNextTask must be integer, received %s.');
|
||||
|
||||
return $this->getBuilder()->where('schedule_id', '=', $schedule)
|
||||
->where('sequence_id', '=', $index + 1)
|
||||
->first($this->getColumns());
|
||||
}
|
||||
}
|
||||
|
|
80
app/Services/Schedules/ProcessScheduleService.php
Normal file
80
app/Services/Schedules/ProcessScheduleService.php
Normal file
|
@ -0,0 +1,80 @@
|
|||
<?php
|
||||
/*
|
||||
* Pterodactyl - Panel
|
||||
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
namespace Pterodactyl\Services\Schedules;
|
||||
|
||||
use Cron\CronExpression;
|
||||
use Webmozart\Assert\Assert;
|
||||
use Pterodactyl\Models\Schedule;
|
||||
use Pterodactyl\Services\Schedules\Tasks\RunTaskService;
|
||||
use Pterodactyl\Contracts\Repository\ScheduleRepositoryInterface;
|
||||
|
||||
class ProcessScheduleService
|
||||
{
|
||||
protected $repository;
|
||||
|
||||
protected $runnerService;
|
||||
|
||||
public function __construct(
|
||||
RunTaskService $runnerService,
|
||||
ScheduleRepositoryInterface $repository
|
||||
) {
|
||||
$this->repository = $repository;
|
||||
$this->runnerService = $runnerService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a schedule and push the first task onto the queue worker.
|
||||
*
|
||||
* @param int|\Pterodactyl\Models\Schedule $schedule
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
public function handle($schedule)
|
||||
{
|
||||
Assert::true(($schedule instanceof Schedule || is_digit($schedule)),
|
||||
'First argument passed to handle must be instance of \Pterodactyl\Models\Schedule or an integer, received %s.'
|
||||
);
|
||||
|
||||
if (($schedule instanceof Schedule && ! $schedule->relationLoaded('tasks')) || ! $schedule instanceof Schedule) {
|
||||
$schedule = $this->repository->getScheduleWithTasks(is_digit($schedule) ? $schedule : $schedule->id);
|
||||
}
|
||||
|
||||
$formattedCron = sprintf('%s %s %s * %s *',
|
||||
$schedule->cron_minute,
|
||||
$schedule->cron_hour,
|
||||
$schedule->cron_day_of_month,
|
||||
$schedule->cron_day_of_week
|
||||
);
|
||||
|
||||
$this->repository->update($schedule->id, [
|
||||
'is_processing' => true,
|
||||
'next_run_at' => CronExpression::factory($formattedCron)->getNextRunDate(),
|
||||
]);
|
||||
|
||||
$task = $schedule->tasks->where('sequence_id', 1)->first();
|
||||
$this->runnerService->handle($task);
|
||||
}
|
||||
}
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
namespace Pterodactyl\Services\Schedules;
|
||||
|
||||
use Cron\CronExpression;
|
||||
use Webmozart\Assert\Assert;
|
||||
use Pterodactyl\Models\Server;
|
||||
use Illuminate\Database\ConnectionInterface;
|
||||
|
@ -83,6 +84,7 @@ class ScheduleCreationService
|
|||
|
||||
$server = ($server instanceof Server) ? $server->id : $server;
|
||||
$data['server_id'] = $server;
|
||||
$data['next_run_at'] = $this->getCronTimestamp($data);
|
||||
|
||||
$this->connection->beginTransaction();
|
||||
$schedule = $this->repository->create($data);
|
||||
|
@ -103,4 +105,22 @@ class ScheduleCreationService
|
|||
|
||||
return $schedule;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a DateTime object after parsing the cron data provided.
|
||||
*
|
||||
* @param array $data
|
||||
* @return \DateTime
|
||||
*/
|
||||
private function getCronTimestamp(array $data)
|
||||
{
|
||||
$formattedCron = sprintf('%s %s %s * %s *',
|
||||
array_get($data, 'cron_minute', '*'),
|
||||
array_get($data, 'cron_hour', '*'),
|
||||
array_get($data, 'cron_day_of_month', '*'),
|
||||
array_get($data, 'cron_day_of_week', '*')
|
||||
);
|
||||
|
||||
return CronExpression::factory($formattedCron)->getNextRunDate();
|
||||
}
|
||||
}
|
||||
|
|
75
app/Services/Schedules/Tasks/RunTaskService.php
Normal file
75
app/Services/Schedules/Tasks/RunTaskService.php
Normal file
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
/*
|
||||
* Pterodactyl - Panel
|
||||
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
namespace Pterodactyl\Services\Schedules\Tasks;
|
||||
|
||||
use Pterodactyl\Models\Task;
|
||||
use Illuminate\Contracts\Bus\Dispatcher;
|
||||
use Pterodactyl\Jobs\Schedule\RunTaskJob;
|
||||
use Pterodactyl\Contracts\Repository\TaskRepositoryInterface;
|
||||
|
||||
class RunTaskService
|
||||
{
|
||||
/**
|
||||
* @var \Illuminate\Contracts\Bus\Dispatcher
|
||||
*/
|
||||
protected $dispatcher;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\TaskRepositoryInterface
|
||||
*/
|
||||
protected $repository;
|
||||
|
||||
/**
|
||||
* RunTaskService constructor.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Bus\Dispatcher $dispatcher
|
||||
* @param \Pterodactyl\Contracts\Repository\TaskRepositoryInterface $repository
|
||||
*/
|
||||
public function __construct(
|
||||
Dispatcher $dispatcher,
|
||||
TaskRepositoryInterface $repository
|
||||
) {
|
||||
$this->dispatcher = $dispatcher;
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Push a single task onto the queue.
|
||||
*
|
||||
* @param int|\Pterodactyl\Models\Task $task
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
public function handle($task)
|
||||
{
|
||||
if (! $task instanceof Task) {
|
||||
$task = $this->repository->find($task);
|
||||
}
|
||||
|
||||
$this->repository->update($task->id, ['is_queued' => true]);
|
||||
$this->dispatcher->dispatch((new RunTaskJob($task->id, $task->schedule_id))->delay($task->time_offset));
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue