Correzioni sulle tasks

This commit is contained in:
Dasc3er 2020-08-27 17:28:53 +02:00
parent 577bf0d555
commit d541d7a93c
5 changed files with 120 additions and 21 deletions

View File

@ -9,7 +9,6 @@
// Schema crontab: "*/5 * * * * php <percorso_root>/cron.php"
use Carbon\Carbon;
use Cron\CronExpression;
use Models\Cache;
use Monolog\Handler\RotatingFileHandler;
use Monolog\Logger;
@ -47,6 +46,8 @@ $logger->pushHandler($handler);
$ultima_esecuzione = Cache::get('Ultima esecuzione del cron');
$data = $ultima_esecuzione->content;
$cron_id = Cache::get('ID del cron');
$riavvia = Cache::get('Riavvia cron');
$disattiva = Cache::get('Disabilita cron');
if (!empty($disattiva->content)) {
@ -58,11 +59,15 @@ $slot_duration = 5;
// Controllo sull'ultima esecuzione
$data = $data ? new Carbon($data) : null;
$minimo_esecuzione = (new Carbon())->addMinutes($slot_duration * 5);
$minimo_esecuzione = (new Carbon())->subMinutes($slot_duration * 5);
if (!empty($data) && $minimo_esecuzione->lessThan($data)) {
return;
}
// Generazione e registrazione del cron
$current_id = random_string();
$cron_id->set($current_id);
// Registrazione dell'esecuzione
$adesso = new Carbon();
$ultima_esecuzione->set($adesso->__toString());
@ -75,10 +80,11 @@ $number = 1;
while (true) {
$riavvia->refresh();
$disattiva->refresh();
$cron_id->refresh();
// Controllo su possibili aggiornamenti per bloccare il sistema
$database_online = $database->isInstalled() && !Update::isUpdateAvailable();
if (!$database_online || !empty($disattiva->content) || !empty($riavvia->content)) {
if (!$database_online || !empty($disattiva->content) || !empty($riavvia->content) || $cron_id->content != $current_id) {
return;
}
@ -93,8 +99,7 @@ while (true) {
]);
// Calcolo del primo slot disponibile per l'esecuzione successiva
$inizio_iterazione = new Carbon();
$inizio_programmato_iterazione = $slot_minimo->copy();
$inizio_iterazione = $slot_minimo->copy();
$slot_minimo = $inizio_iterazione->copy()->startOfHour();
while ($inizio_iterazione->greaterThanOrEqualTo($slot_minimo)) {
$slot_minimo->addMinutes($slot_duration);
@ -105,25 +110,40 @@ while (true) {
foreach ($tasks as $task) {
$adesso = new Carbon();
// Individuazione delle informazioni previste dalla relativa espressione
$cron = CronExpression::factory($task->expression);
$data_successiva = Carbon::instance($cron->getNextRunDate($adesso));
// Esecuzione diretta solo nel caso in cui sia prevista
if (!empty($task->next_execution_at) && $task->next_execution_at->greaterThanOrEqualTo($inizio_iterazione) && $task->next_execution_at->lessThanOrEqualTo($adesso)) {
// Registrazione dell'esecuzione nei log
$logger->info($task->name.': '.$task->expression);
$task->execute();
// Registrazione della data per l'esecuzione se non indicata
if (empty($task->next_execution_at)) {
dd($task->next_execution_at);
$task->registerNextExecution($inizio_iterazione);
$task->save();
}
// Salvataggio della data per l'esecuzione susccessiva
$task->next_execution_at = $data_successiva;
$task->save();
// Esecuzione diretta solo nel caso in cui sia prevista
if ($task->next_execution_at->greaterThanOrEqualTo($inizio_iterazione) && $task->next_execution_at->lessThanOrEqualTo($adesso)) {
// Registrazione dell'esecuzione nei log
$logger->info($task->name.': '.$task->expression);
try {
$task->execute();
} catch (Exception $e) {
// Registrazione del completamento nei log
$this->log('error', 'Errore di esecuzione', [
'code' => $e->getCode(),
'message' => $e->getMessage(),
'trace' => $e->getTraceAsString(),
]);
}
}
// Esecuzione mancata
elseif ($task->next_execution_at->lessThan($inizio_iterazione)) {
$logger->info($task->name.': mancata', [
'timestamp' => $task->next_execution_at->toDateTimeString(),
]);
$task->registerMissedExecution($inizio_iterazione);
}
// Calcolo dello successivo slot
if ($data_successiva->lessThan($slot_minimo)) {
$slot_minimo = $data_successiva;
if ($task->next_execution_at->lessThan($slot_minimo)) {
$slot_minimo = $task->next_execution_at;
}
}

22
src/Tasks/Log.php Normal file
View File

@ -0,0 +1,22 @@
<?php
namespace Tasks;
use Common\Model;
/**
* Risorsa per la gestione dei log per le task ricorrenti del gestionale.
*/
class Log extends Model
{
protected $table = 'zz_tasks_logs';
protected $casts = [
'context' => 'array',
];
public function task()
{
return $this->belongsTo(Task::class, 'id_task');
}
}

View File

@ -4,6 +4,7 @@ namespace Tasks;
use Carbon\Carbon;
use Common\Model;
use Cron\CronExpression;
/**
* Risorsa per la gestione delle task ricorrenti del gestionale.
@ -17,8 +18,24 @@ class Task extends Model
'last_executed_at',
];
public function log($level, $message, $context = [])
{
$log = Log::build();
$log->level = $level;
$log->message = $message;
$log->context = $context;
$log->task()->associate($this);
$log->save();
}
public function execute()
{
// Registrazione dell'inizio nei log
$this->log('info', 'Inizio esecuzione');
// Individuazione del gestore
$class = $this->attributes['class'];
$manager = new $class($this);
@ -28,13 +45,41 @@ class Task extends Model
// Salvtagggio dell'esecuzione
$this->last_executed_at = new Carbon();
// Individuazione della data per la prossima esecuzione dalla relativa espressione
$this->registerNextExecution($this->last_executed_at);
$this->save();
// Registrazione del completamento nei log
$this->log('info', 'Fine esecuzione');
return $result;
}
public function registerMissedExecution(Carbon $now)
{
// Registrazione del completamento nei log
$this->log('warning', 'Esecuzione mancata', [
'timestamp' => $this->next_execution_at->toDateTimeString(),
]);
$this->registerNextExecution($now);
$this->save();
}
public function registerNextExecution(Carbon $now)
{
$cron = CronExpression::factory($this->expression);
$this->next_execution_at = Carbon::instance($cron->getNextRunDate($now));
}
public function delete()
{
return false;
}
public function logs()
{
return $this->hasMany(Log::class, 'id_task');
}
}

View File

@ -9,13 +9,24 @@ CREATE TABLE IF NOT EXISTS `zz_tasks` (
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS `zz_tasks_logs` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`id_task` int(11),
`level` VARCHAR(255) NOT NULL,
`message` TEXT NOT NULL,
`context` TEXT NOT NULL,
PRIMARY KEY (`id`),
FOREIGN KEY (`id_task`) REFERENCES `zz_tasks`(`id`)
) ENGINE=InnoDB;
INSERT INTO `zz_cache` (`id`, `name`, `content`, `valid_time`, `expire_at`) VALUES
(NULL, 'Ultima esecuzione del cron', '', '1 month', NULL),
(NULL, 'ID del cron', '', '1 month', NULL),
(NULL, 'Riavvia cron', '', '1 month', NULL),
(NULL, 'Disabilita cron', '', '1 month', NULL);
INSERT INTO `zz_tasks` (`id`, `name`, `class`, `expression`, `last_executed_at`) VALUES
(NULL, 'Backup automatico', 'Modules\\Backups\\BackupTask', '0 0 * * *', NULL);
(NULL, 'Backup automatico', 'Modules\\Backups\\BackupTask', '0 1 * * *', NULL);
DELETE FROM `zz_hooks` WHERE `class` = 'Modules\\Backups\\BackupHook';

View File

@ -122,6 +122,7 @@ return [
'zz_semaphores',
'zz_settings',
'zz_tasks',
'zz_tasks_logs',
'zz_tokens',
'zz_users',
'zz_user_sedi',