create(); $log->cron_type = $cronType; $log->started_at = date('Y-m-d H:i:s'); $log->status = 'running'; $log->save(); self::$logId = $log->id(); return self::$logId; } /** * Update log with current statistics * @param array $stats Statistics array */ public static function updateStats($stats = []) { if (!self::$logId) return; $log = ORM::for_table('tbl_cron_logs')->find_one(self::$logId); if (!$log) return; foreach ($stats as $key => $value) { if (property_exists($log, $key)) { $log->$key = $value; } } $log->save(); } /** * Increment a counter * @param string $field Field to increment * @param int $amount Amount to increment by */ public static function increment($field, $amount = 1) { if (!self::$logId) return; $log = ORM::for_table('tbl_cron_logs')->find_one(self::$logId); if (!$log) return; if (property_exists($log, $field)) { $log->$field = $log->$field + $amount; $log->save(); } } /** * Complete the cron job successfully * @param array $finalStats Final statistics */ public static function complete($finalStats = []) { if (!self::$logId) return; $log = ORM::for_table('tbl_cron_logs')->find_one(self::$logId); if (!$log) return; $log->finished_at = date('Y-m-d H:i:s'); $log->status = 'completed'; // Calculate execution time if (self::$startTime) { $log->execution_time = round(microtime(true) - self::$startTime, 3); } // Calculate memory usage if (self::$startMemory) { $currentMemory = memory_get_usage(); $peakMemory = memory_get_peak_usage(); $log->memory_usage = self::formatBytes($peakMemory - self::$startMemory); } // Update final stats foreach ($finalStats as $key => $value) { if (property_exists($log, $key)) { $log->$key = $value; } } $log->save(); // Clean up old logs (keep last 1000 records) self::cleanup(); } /** * Mark cron job as failed * @param string $errorMessage Error message * @param array $finalStats Final statistics */ public static function fail($errorMessage, $finalStats = []) { if (!self::$logId) return; $log = ORM::for_table('tbl_cron_logs')->find_one(self::$logId); if (!$log) return; $log->finished_at = date('Y-m-d H:i:s'); $log->status = 'failed'; $log->error_message = $errorMessage; // Calculate execution time if (self::$startTime) { $log->execution_time = round(microtime(true) - self::$startTime, 3); } // Update final stats foreach ($finalStats as $key => $value) { if (property_exists($log, $key)) { $log->$key = $value; } } $log->save(); } /** * Get recent cron logs * @param int $limit Number of records to return * @param string $cronType Filter by cron type * @return array */ public static function getRecent($limit = 50, $cronType = null) { $query = ORM::for_table('tbl_cron_logs'); if ($cronType) { $query->where('cron_type', $cronType); } return $query->order_by_desc('started_at') ->limit($limit) ->find_many(); } /** * Get cron job statistics * @param int $days Number of days to look back * @return array */ public static function getStats($days = 7) { $since = date('Y-m-d H:i:s', strtotime("-$days days")); $stats = ORM::for_table('tbl_cron_logs') ->where_gte('started_at', $since) ->find_many(); $result = [ 'total_runs' => count($stats), 'successful_runs' => 0, 'failed_runs' => 0, 'total_expired_users' => 0, 'total_notifications_sent' => 0, 'total_auto_renewals' => 0, 'avg_execution_time' => 0, 'last_run' => null, 'last_success' => null, 'last_failure' => null ]; $totalExecutionTime = 0; $executionCount = 0; foreach ($stats as $log) { if ($log->status == 'completed') { $result['successful_runs']++; $result['last_success'] = $log->finished_at; } elseif ($log->status == 'failed') { $result['failed_runs']++; $result['last_failure'] = $log->finished_at; } $result['total_expired_users'] += $log->expired_users_processed; $result['total_notifications_sent'] += $log->notifications_sent; $result['total_auto_renewals'] += $log->auto_renewals_successful; if ($log->execution_time) { $totalExecutionTime += $log->execution_time; $executionCount++; } if (!$result['last_run'] || $log->started_at > $result['last_run']) { $result['last_run'] = $log->started_at; } } if ($executionCount > 0) { $result['avg_execution_time'] = round($totalExecutionTime / $executionCount, 3); } return $result; } /** * Clean up old logs (keep last 1000 records) */ private static function cleanup() { $count = ORM::for_table('tbl_cron_logs')->count(); if ($count > 1000) { $logsToDelete = ORM::for_table('tbl_cron_logs') ->order_by_asc('started_at') ->limit($count - 1000) ->find_many(); foreach ($logsToDelete as $log) { $log->delete(); } } } /** * Format bytes to human readable format * @param int $bytes * @return string */ private static function formatBytes($bytes) { $units = ['B', 'KB', 'MB', 'GB']; $bytes = max($bytes, 0); $pow = floor(($bytes ? log($bytes) : 0) / log(1024)); $pow = min($pow, count($units) - 1); $bytes /= pow(1024, $pow); return round($bytes, 2) . ' ' . $units[$pow]; } /** * Check if cron is running (has a running log in last 5 minutes) * @return bool */ public static function isRunning() { $fiveMinutesAgo = date('Y-m-d H:i:s', strtotime('-5 minutes')); $runningLog = ORM::for_table('tbl_cron_logs') ->where('status', 'running') ->where_gte('started_at', $fiveMinutesAgo) ->find_one(); return $runningLog ? true : false; } /** * Get the last successful cron run * @return object|null */ public static function getLastSuccess() { return ORM::for_table('tbl_cron_logs') ->where('status', 'completed') ->order_by_desc('finished_at') ->find_one(); } }