get(); foreach ($tenants as $tenant) { app()->instance('tenant', $tenant); $this->runTenantTasks($tenant, $now); } return response()->json([ 'status' => 'ok', 'time' => $now->toDateTimeString(), ]); } private function runTenantTasks(Tenant $tenant, Carbon $now) { $tasks = CronTask::all(); foreach ($tasks as $task) { // --- Every-Time Tasks --- if ($task->execution_type === CronTaskType::CRON_TASK_TYPE_REALTIME) { $this->runTask($task); } // --- Daily Tasks --- if ($task->execution_type === CronTaskType::CRON_TASK_TYPE_DAILY) { $scheduledTime = $task->schedule_time; $alreadyRunToday = $task->last_run?->isToday() ?? false; if (!$alreadyRunToday && $now->format('H:i') === $scheduledTime) { $this->runTask($task); } } } } private function runTask(CronTask $task) { $logger = $this->taskLogger($task->name, app('tenant')); app()->instance('taskLogger', $logger); $taskClass = "\\App\\Tasks\\" . $task->name; if (class_exists($taskClass)) { $instance = new $taskClass(); $instance->handle(); // Update last_run $task->last_run = now(); $task->save(); } } private function taskLogger(string $taskName, $tenant = null) : LoggerInterface { $tenantSlug = $tenant->slug; $logDir = storage_path("logs/{$tenantSlug}"); if (!file_exists($logDir)) { mkdir($logDir, 0755, true); } $logPath = "{$logDir}/{$taskName}.log"; return \Illuminate\Support\Facades\Log::build([ 'driver' => 'single', 'path' => $logPath, 'level' => 'debug', ]); } }