Cron systém
Cron joby jsou v app/cron/jobs/. Jediný soubor spouštěný z crontabu je run.php, který každou minutu prochází složky a podle názvu souborů rozhodne, co spustit.
Struktura
app/cron/
├── CronVariable.php // Persistentní proměnné mezi běhy
├── PreventParallelJobRun.php // Zamezení paralelnímu běhu
└── jobs/
├── run.php // Hlavní dispatcher (spouští se každou minutu)
├── admin/
│ ├── every_1min.php
│ └── daily_at_08_30.php
└── reports/
├── every_1h.php
└── weekly_at_1.php
Crontab
# Jediný záznam v crontabu — spouští run.php každou minutu
* * * * * /usr/bin/php /var/www/app/cron/jobs/run.php
Vzory souborů
Název souboru určuje frekvenci spouštění. Soubory se umísťují do podsložek (admin/, reports/, ...).
Minutové intervaly
| every_1min.php | Každou minutu |
| every_5min.php | Každých 5 minut (0, 5, 10, 15, ...) |
| every_10min.php | Každých 10 minut (0, 10, 20, 30, ...) |
| every_15min.php | Každých 15 minut (0, 15, 30, 45) |
| every_20min.php | Každých 20 minut (0, 20, 40) |
| every_30min.php | Každých 30 minut (0, 30) |
Hodinové intervaly
| every_1h.php | Každou hodinu v 0. minutě |
| every_3h.php | Každé 3 hodiny (0:00, 3:00, 6:00, ...) |
| every_6h.php | Každých 6 hodin (0:00, 6:00, 12:00, 18:00) |
| every_12h.php | Každých 12 hodin (0:00, 12:00) |
Denní a týdenní
| daily.php | Každý den o půlnoci (0:00) |
| daily_at_XX_XX.php | Každý den v konkrétní čas. Např. daily_at_08_30.php = 8:30. |
| weekly.php | Každé pondělí o půlnoci |
| weekly_at_X.php | Každý týden v konkrétní den o půlnoci. 1=Po, 7=Ne. Např. weekly_at_5.php = pátek. |
Všechny časy jsou v timezone serveru, ne v UTC.
Vytvoření cron jobu
Příkaz php moony make cron-job vytvoří nový cron job. Formát: "složka/pattern" — složka je povinná.
php moony make cron-job "admin/every_1min"
php moony make cron-job "reports/daily_at_08_30"
php moony make cron-job "cleanup/weekly_at_5"
Příkaz automaticky:
- Zvaliduje pattern (musí být jeden z platných vzorů)
- Vytvoří složku pokud neexistuje
- Vygeneruje soubor s namespace podle cesty
- Nastaví správnou relativní cestu k bootstrap.php
Vygenerovaná šablona
Příklad pro php moony make cron-job "admin/every_1min":
<?php
namespace Moony\app\cron\jobs\admin;
use Moony\app\cron\PreventParallelJobRun;
use Moony\app\repositories\system\CronHistoryRepository;
use Moony\bootstrap\core\facades\DB;
require __DIR__ . '/../../../../bootstrap.php';
class every_1min extends PreventParallelJobRun
{
private array $data = [];
public function __construct()
{
parent::__construct();
$this->run();
$this->finish();
}
private function run(): void
{
// Cron job work
// Volitelně — uložit data do historie
$this->data['processed'] = 42;
$this->data['errors'] = 0;
}
private function finish(): void
{
if(DB::isConnected()) {
CronHistoryRepository::updateBy([
'folder' => 'admin',
'class' => 'every_1min',
'finished_at' => null,
], [
'finished_at' => (new \DateTime())->format('Y-m-d H:i:s.u'),
'data' => !empty($this->data) ? json_encode($this->data, JSON_UNESCAPED_UNICODE) : null,
]);
}
}
}
if(isset($argv[0]) && basename(__FILE__) === basename($argv[0])) {
(new every_1min());
}
Jak to funguje
| PreventParallelJobRun | Zabraňuje spuštění jobu, pokud předchozí běh ještě neskončil (file lock) |
| $data | Privátní pole — v run() do něj zapsat výsledky/statistiky, po skončení se uloží jako JSON do DB |
| run() | Hlavní logika cron jobu |
| finish() | Po dokončení run() zapíše finished_at a $data (jako JSON) do cron_history |
| if(isset($argv[0])...) | Spouštěcí guard — job se spustí jen z CLI, ne při require/include |
run.php spouští joby přes exec/pclose a okamžitě se odpojí (fire & forget). Nesleduje výsledek — každý job běží nezávisle.
CronVariable
Pro persistenci dat mezi běhy cron jobů (např. poslední zpracované ID, checkpoint) slouží CronVariable. Data se ukládají serializovaná do DB.
| CronVariable::get(string $key) | Přečte uloženou hodnotu (libovolný typ). Vrátí null pokud neexistuje. |
| CronVariable::set(string $key, mixed $value) | Uloží hodnotu (UPSERT — vytvoří nebo přepíše) |
// Uložení checkpointu
CronVariable::set('last_processed_id', $lastId);
// Čtení při dalším běhu
$lastId = CronVariable::get('last_processed_id') ?? 0;
Historie (cron_history)
Každé spuštění se zaloguje do tabulky cron_history se začátkem a koncem. Datetime má přesnost na 1 desetinné místo.
| id | INT UNSIGNED AUTO_INCREMENT |
| folder | VARCHAR(255) — název složky (admin, reports, ...) |
| class | VARCHAR(255) — název třídy/souboru (every_1min, daily, ...) |
| started_at | DATETIME(1) NOT NULL — čas spuštění s desetinami sekundy |
| finished_at | DATETIME(1) NULL — čas dokončení (null = stále běží nebo spadl) |
| data | MEDIUMTEXT NULL — volitelná JSON data z cron jobu (statistiky, výsledky) |
DDL
CREATE TABLE IF NOT EXISTS `cron_history` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`folder` VARCHAR(255) NOT NULL COLLATE 'utf8mb4_general_ci',
`class` VARCHAR(255) NOT NULL COLLATE 'utf8mb4_general_ci',
`started_at` DATETIME(1) NOT NULL,
`finished_at` DATETIME(1) NULL DEFAULT NULL,
`data` MEDIUMTEXT NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_folder_class` (`folder`, `class`) USING BTREE,
INDEX `idx_started_at` (`started_at`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
Záznam s finished_at = NULL znamená, že job stále běží nebo havaroval. Lze použít pro monitoring a alerting.
