feat(scheduler): delete orphaned jobs and block editing of unregistered jobs

Adds deleteOrphanedJobs() to clean up stale job_keys during ensureSystemJobs, and prevents editing jobs that are no longer registered in the runtime registry.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-13 14:13:09 +02:00
parent 1c784efd5c
commit 312d43d9d9
7 changed files with 69 additions and 0 deletions

View File

@@ -102,6 +102,39 @@ class ScheduledJobServiceTest extends TestCase
$service->ensureSystemJobs();
}
public function testEnsureSystemJobsDisablesOrphanedJobs(): void
{
$jobRepository = $this->createMock(ScheduledJobRepository::class);
$runRepository = $this->createMock(ScheduledJobRunRepository::class);
$registry = $this->createMock(ScheduledJobRegistry::class);
$calculator = new ScheduleCalculator();
$registry->expects($this->once())->method('definitions')->willReturn([
'system_audit_purge' => [
'label' => 'System audit log cleanup',
'description' => 'Purges system audit log entries',
'default_enabled' => 1,
'default_timezone' => 'UTC',
'default_schedule_type' => 'daily',
'default_schedule_interval' => 1,
'default_schedule_time' => '03:00',
'default_schedule_weekdays_csv' => null,
'default_catchup_once' => 1,
'allowed_schedule_types' => ['daily', 'weekly'],
],
]);
$jobRepository->method('findByKey')->willReturn(null);
$jobRepository->method('create')->willReturn(1);
$jobRepository->expects($this->once())
->method('deleteOrphanedJobs')
->with(['system_audit_purge'])
->willReturn(1);
$service = new ScheduledJobService($jobRepository, $runRepository, $registry, $calculator);
$service->ensureSystemJobs();
}
public function testUpdateFromAdminReturnsValidationErrorForWeeklyWithoutWeekdays(): void
{
$jobRepository = $this->createMock(ScheduledJobRepository::class);