Name = 'Scheduler'; $this->Version = '1.0'; $this->Creator = 'Chronos'; $this->License = 'GNU/GPLv3'; $this->Description = 'Allow to setup and execute planned and recurring tasks'; $this->Models = array(SchedulerAction::GetClassName(), Scheduler::GetClassName()); } function DoStart(): void { $this->System->FormManager->RegisterClass('Scheduler', array( 'Title' => 'Plánovač', 'Table' => 'Scheduler', 'DefaultSortColumn' => 'ScheduledTime', 'Items' => array( 'Name' => array('Type' => 'String', 'Caption' => 'Jméno', 'Default' => ''), 'Enabled' => array('Type' => 'Boolean', 'Caption' => 'Povoleno', 'Default' => '0'), 'ScheduledTime' => array('Type' => 'DateTime', 'Caption' => 'Plánovaný čas', 'Default' => ''), 'Action' => array('Type' => 'TSchedulerAction', 'Caption' => 'Akce', 'Default' => ''), 'Period' => array('Type' => 'Integer', 'Caption' => 'Opakovat po', 'Default' => '', 'Null' => true, 'Suffix' => 'sekund'), 'LastExecutedTime' => array('Type' => 'DateTime', 'Caption' => 'Čas posledního spuštění', 'Default' => '', 'ReadOnly' => true), 'Duration' => array('Type' => 'TimeDiff', 'Caption' => 'Trvání', 'Default' => '', 'ReadOnly' => true), 'Log' => array('Type' => 'Text', 'Caption' => 'Poslední záznam', 'Default' => '', 'ReadOnly' => true, 'NotInList' => true), ), )); $this->System->FormManager->RegisterClass('SchedulerAction', array( 'Title' => 'Akce plánovače', 'Table' => 'SchedulerAction', 'DefaultSortColumn' => 'Name', 'ReadOnly' => true, 'Items' => array( 'Name' => array('Type' => 'String', 'Caption' => 'Jméno', 'Default' => '', 'ReadOnly' => true), 'Class' => array('Type' => 'String', 'Caption' => 'Vykonat třídu', 'Default' => '', 'ReadOnly' => true), ), )); $this->System->FormManager->RegisterFormType('TSchedulerAction', array( 'Type' => 'Reference', 'Table' => 'SchedulerAction', 'Id' => 'Id', 'Name' => 'Name', 'Filter' => '1', )); $this->System->RegisterCommandLine('run-scheduler', 'Runs scheduled tasks', array(ModuleScheduler::Cast($this->System->GetModule('Scheduler')), 'Run')); } function Run(array $Parameters): void { while (true) { $DbResult = $this->Database->query('SELECT `Scheduler`.*, `SchedulerAction`.`Class` AS `Class` FROM `Scheduler` '. 'LEFT JOIN `SchedulerAction` ON `SchedulerAction`.`Id` = `Scheduler`.`Action` '. 'WHERE (`Scheduler`.`Enabled`=1) AND ( '. '(`Scheduler`.`ScheduledTime` < "'.TimeToMysqlDateTime(time()).'") OR '. '(`Scheduler`.`ScheduledTime` IS NULL))'); while ($DbRow = $DbResult->fetch_assoc()) { echo('Executing '.$DbRow['Name']."\n"); $Output = ''; $StartTime = time(); if (class_exists($DbRow['Class'])) { $Class = new $DbRow['Class']($this->System); try { $Output = $Class->Execute(); } catch (Exception $E) { echo($E->getMessage()."\n"); } echo($Output); } else echo('Class '.$DbRow['Class'].' not found'."\n"); $StopTime = time(); $Duration = $StopTime - $StartTime; $this->Database->update('Scheduler', 'Id='.$DbRow['Id'], array('Log' => $Output, 'LastExecutedTime' => TimeToMysqlDateTime($StartTime), 'Duration' => $Duration)); if ($DbRow['Period'] != '') { if ($DbRow['ScheduledTime'] == '') $NewScheduledTime = $StartTime + $DbRow['Period']; else $NewScheduledTime = MysqlDateTimeToTime($DbRow['ScheduledTime']) + $DbRow['Period']; if ($NewScheduledTime < $StopTime) $NewScheduledTime = $StopTime + $DbRow['Period']; $this->Database->update('Scheduler', 'Id='.$DbRow['Id'], array('ScheduledTime' => TimeToMysqlDateTime($NewScheduledTime))); } } echo('.'); sleep(1); } } static function Cast(Module $Module): ModuleScheduler { if ($Module instanceof ModuleScheduler) { return $Module; } throw new Exception('Expected ModuleScheduler type but got '.gettype($Module)); } } class SchedulerTask extends Model { function Execute(): string { return ''; } } class ScheduleTaskTest extends SchedulerTask { function Execute(): string { $Output = '#'; return $Output; } } class Scheduler extends Model { static function GetModelDesc(): ModelDesc { $Desc = new ModelDesc(self::GetClassName()); $Desc->AddString('Name'); $Desc->AddBoolean('Enabled'); $Desc->AddDateTime('ScheduledTime'); $Desc->AddReference('Action', SchedulerAction::GetClassName()); $Desc->AddInteger('Period'); $Desc->AddDateTime('LastExecutedTime'); $Desc->AddInteger('Duration'); $Desc->AddText('Log'); return $Desc; } } class SchedulerAction extends Model { static function GetModelDesc(): ModelDesc { $Desc = new ModelDesc(self::GetClassName()); $Desc->AddString('Name'); $Desc->AddString('Class'); return $Desc; } }