diff --git a/app/Console/Commands/Schedule/ProcessRunnableCommand.php b/app/Console/Commands/Schedule/ProcessRunnableCommand.php index fa335c2bd..b334fbb13 100644 --- a/app/Console/Commands/Schedule/ProcessRunnableCommand.php +++ b/app/Console/Commands/Schedule/ProcessRunnableCommand.php @@ -7,6 +7,7 @@ use Throwable; use Illuminate\Console\Command; use Pterodactyl\Models\Schedule; use Illuminate\Support\Facades\Log; +use Illuminate\Database\Eloquent\Builder; use Pterodactyl\Services\Schedules\ProcessScheduleService; class ProcessRunnableCommand extends Command @@ -26,7 +27,9 @@ class ProcessRunnableCommand extends Command */ public function handle() { - $schedules = Schedule::query()->with('tasks') + $schedules = Schedule::query() + ->with('tasks') + ->whereRelation('server', fn (Builder $builder) => $builder->whereNull('status')) ->where('is_active', true) ->where('is_processing', false) ->whereRaw('next_run_at <= NOW()') diff --git a/app/Jobs/Schedule/RunTaskJob.php b/app/Jobs/Schedule/RunTaskJob.php index fa62bc004..0b0f9e075 100644 --- a/app/Jobs/Schedule/RunTaskJob.php +++ b/app/Jobs/Schedule/RunTaskJob.php @@ -61,6 +61,16 @@ class RunTaskJob extends Job implements ShouldQueue } $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) { diff --git a/tests/Integration/Jobs/Schedule/RunTaskJobTest.php b/tests/Integration/Jobs/Schedule/RunTaskJobTest.php index 68249dc43..9a5dfcea9 100644 --- a/tests/Integration/Jobs/Schedule/RunTaskJobTest.php +++ b/tests/Integration/Jobs/Schedule/RunTaskJobTest.php @@ -3,6 +3,8 @@ namespace Pterodactyl\Tests\Integration\Jobs\Schedule; use Mockery; +use Carbon\Carbon; +use DateTimeInterface; use Carbon\CarbonImmutable; use GuzzleHttp\Psr7\Request; use Pterodactyl\Models\Task; @@ -146,6 +148,36 @@ class RunTaskJobTest extends IntegrationTestCase } } + /** + * Test that a schedule is not executed if the server is suspended. + * + * @see https://github.com/pterodactyl/panel/issues/4008 + */ + public function testTaskIsNotRunIfServerIsSuspended() + { + $server = $this->createServerModel([ + 'status' => Server::STATUS_SUSPENDED, + ]); + + $schedule = Schedule::factory()->for($server)->create([ + 'last_run_at' => Carbon::now()->subHour(), + ]); + + $task = Task::factory()->for($schedule)->create([ + 'action' => Task::ACTION_POWER, + 'payload' => 'start', + ]); + + Bus::dispatchNow(new RunTaskJob($task)); + + $task->refresh(); + $schedule->refresh(); + + $this->assertFalse($task->is_queued); + $this->assertFalse($schedule->is_processing); + $this->assertTrue(Carbon::now()->isSameAs(DateTimeInterface::ATOM, $schedule->last_run_at)); + } + /** * @return array */