Quelltext des aktuellen Standes
<?php
/**
* Unified cron scheduler entry point.
*
* Replaces the per-job crontab entries with a single line:
*
* * * * * * /usr/bin/php /pfad/zu/bin/scheduler.php >> /pfad/zu/storage/logs/scheduler.log 2>&1
*
* On every minute-tick it picks all tasks from `cron_tasks` whose
* `next_run_at` is due and either runs them inline or detaches a background
* worker (bin/run-task.php). Per-task admin-tunable schedule lives in the
* cron_tasks table; the corresponding admin UI is at /admin/cronjobs.
*/
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
require_once __DIR__ . '/../bootstrap.php';
use OpenNIT\Cron\BackgroundDispatcher;
use OpenNIT\Cron\Bootstrap;
use OpenNIT\Cron\Scheduler;
use OpenNIT\Cron\TaskRegistry;
$rootDir = dirname(__DIR__);
try {
$context = Bootstrap::init($rootDir);
} catch (\Throwable $e) {
fwrite(STDERR, '[scheduler] Bootstrap failed: ' . $e->getMessage() . PHP_EOL);
exit(1);
}
$lockDir = $rootDir . '/storage/locks';
$logDir = $rootDir . '/storage/logs';
if (!is_dir($logDir)) {
@mkdir($logDir, 0775, true);
}
$registry = new TaskRegistry();
$dispatcher = new BackgroundDispatcher(
phpBinary: PHP_BINARY,
workerScript: __DIR__ . '/run-task.php',
logFile: $logDir . '/scheduler.log',
);
$scheduler = new Scheduler($context->db, $context, $registry, $dispatcher, $lockDir);
$stats = $scheduler->tick();
// Single-line summary so cron mails / log tails stay readable.
$ts = date('Y-m-d H:i:s');
printf(
"[%s] tick: dispatched=%d inline=%d background=%d skipped=%d errors=%d%s",
$ts,
$stats['dispatched'],
$stats['inline'],
$stats['background'],
$stats['skipped'],
$stats['errors'],
PHP_EOL
);
exit($stats['errors'] > 0 ? 1 : 0);