jobData = $jobData; $this->userId = $userId; // Set the queue for this job $this->onQueue('register-creator'); } /** * Execute the job. */ public function handle(): void { $lineData = $this->jobData['line_data'] ?? []; $documents = $this->jobData['documents'] ?? []; $settings = $this->jobData['settings'] ?? []; $jobId = $this->jobData['job_id'] ?? uniqid('rc_', true); $registerColumnBased = $settings['register_column_based'] ?? 'line_number'; $lineIdentifier = $lineData[$registerColumnBased] ?? 'unknown'; Log::info("RegisterCreatorJob started", [ 'job_id' => $jobId, 'line' => $lineIdentifier, 'attempt' => $this->attempts(), 'user_id' => $this->userId ]); // Check if job is cancelled (deleted from queue cache) $queue = Cache::get('register-creator-queue-2', []); if (!isset($queue[$jobId])) { Log::info("RegisterCreatorJob cancelled by user (job ID not found in cache)", ['job_id' => $jobId]); return; } try { // Reset statistics before processing - FIX FOR WORKER STATE ISSUE \App\Services\RegisterCreator\ExcelRowHandler::resetStatistics(); Log::debug("ExcelRowHandler statistics reset for job", [ 'job_id' => $jobId, 'line' => $lineIdentifier ]); // Set locale setlocale(LC_ALL, 'ru_RU.utf8'); \App::setLocale("ru"); // Increase limits set_time_limit(-1); ini_set('max_execution_time', -1); ini_set('memory_limit', '2048M'); // Set user in settings for tracking if ($this->userId) { $settings['tracking_user_id'] = $this->userId; } // Create service instance $service = new RegisterCreatorService(); // Process the line $result = $service->processLine($lineData, $documents, array_merge($settings, [ 'job_id' => $jobId ])); Log::info("RegisterCreatorJob completed successfully", [ 'job_id' => $jobId, 'line' => $lineIdentifier, 'duration' => $result['duration'] ?? 0, 'statistics' => $result['statistics'] ?? [] ]); // Dispatch cache update for register creator view // Dispatch cache update for register creator view try { \App\Jobs\CacheBladeViewJob::dispatch('admin-ajax.register-no-cache', 'register-creator'); Log::info("RegisterCreatorJob: Cache update dispatched"); } catch (\Exception $e) { Log::warning('RegisterCreatorJob: Failed to dispatch cache update', ['error' => $e->getMessage()]); } // Send success notification email if configured $this->sendSuccessNotification($settings, $lineIdentifier, $result); } catch (\Throwable $th) { // Detailed error logging $errorDetails = [ 'job_id' => $jobId, 'line' => $lineIdentifier, 'error_message' => $th->getMessage(), 'error_type' => get_class($th), 'file' => $th->getFile(), 'line_number' => $th->getLine(), 'attempt' => $this->attempts(), 'max_tries' => $this->tries, 'trace' => $th->getTraceAsString(), 'input_data' => [ 'line_data_keys' => array_keys($lineData), 'documents_count' => count($documents), 'settings_keys' => array_keys($settings) ] ]; Log::error("RegisterCreatorJob failed", $errorDetails); // Write error to file for easier debugging try { $errorLogPath = "register_creator_errors/" . date('Y-m-d') . "/"; if (!Storage::exists($errorLogPath)) { Storage::makeDirectory($errorLogPath); } $errorFileName = $errorLogPath . "{$jobId}_error.json"; $errorContent = json_encode([ 'timestamp' => now()->toDateTimeString(), 'job_id' => $jobId, 'line_identifier' => $lineIdentifier, 'error' => [ 'type' => get_class($th), 'message' => $th->getMessage(), 'file' => $th->getFile(), 'line' => $th->getLine(), 'trace' => explode("\n", $th->getTraceAsString()) ], 'input_data' => [ 'line_data' => $lineData, 'documents' => $documents, 'settings' => $settings ], 'context' => [ 'attempt' => $this->attempts(), 'max_tries' => $this->tries, 'memory_usage' => round(memory_get_usage(true) / 1024 / 1024, 2) . ' MB', 'peak_memory' => round(memory_get_peak_usage(true) / 1024 / 1024, 2) . ' MB' ] ], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); Storage::put($errorFileName, $errorContent); Log::info("Error details saved to file: {$errorFileName}"); } catch (\Throwable $logError) { Log::warning("Could not write error to file", [ 'error' => $logError->getMessage() ]); } // Send failure notification $this->sendFailureNotification($settings, $lineIdentifier, $th); // Re-throw exception to mark job as failed throw $th; } finally { // Always reset statistics after job completion - CRITICAL FIX // This ensures that each job starts with a clean state even when worker reuses the same process \App\Services\RegisterCreator\ExcelRowHandler::resetStatistics(); Log::debug("ExcelRowHandler statistics reset after job completion", [ 'job_id' => $jobId ?? 'unknown', 'line' => $lineIdentifier ?? 'unknown' ]); } } /** * Handle a job failure. */ public function failed(\Throwable $exception): void { $lineData = $this->jobData['line_data'] ?? []; $settings = $this->jobData['settings'] ?? []; $jobId = $this->jobData['job_id'] ?? 'unknown'; $registerColumnBased = $settings['register_column_based'] ?? 'line_number'; $lineIdentifier = $lineData[$registerColumnBased] ?? 'unknown'; Log::critical("RegisterCreatorJob permanently failed", [ 'job_id' => $jobId, 'line' => $lineIdentifier, 'error' => $exception->getMessage(), 'attempts' => $this->attempts() ]); // Update progress to failed state \Cache::put("register-creator-progress-{$jobId}", [ 'status' => 'failed', 'progress' => 0, 'description' => "Failed: {$exception->getMessage()}", 'line_data' => $lineIdentifier, 'failed_at' => now()->toDateTimeString() ], now()->addDays(7)); } /** * Send success notification email */ private function sendSuccessNotification(array $settings, string $lineIdentifier, array $result): void { try { $userEmail = $settings['user_email'] ?? null; if (!$userEmail) { return; } // You can implement email notification here Log::debug("Success notification would be sent to {$userEmail} for line {$lineIdentifier}"); } catch (\Throwable $th) { Log::warning("Could not send success notification", [ 'error' => $th->getMessage() ]); } } /** * Send failure notification email */ private function sendFailureNotification(array $settings, string $lineIdentifier, \Throwable $exception): void { try { $userEmail = $settings['user_email'] ?? null; if (!$userEmail) { return; } // You can implement email notification here Log::debug("Failure notification would be sent to {$userEmail} for line {$lineIdentifier}"); } catch (\Throwable $th) { Log::warning("Could not send failure notification", [ 'error' => $th->getMessage() ]); } } }