get()) { Log::warning('[marketing-batch] skipped by lock', ['as_of_date' => $asOfDate]); return ['skipped' => true, 'as_of_date' => $asOfDate]; } try { $this->repo->upsertBatchRunStart($asOfDate); Log::info('[marketing-batch] step A upsertDaily start', ['as_of_date' => $asOfDate]); $dailyRows = $this->repo->upsertDaily($asOfDate); Log::info('[marketing-batch] step A upsertDaily done', ['daily_rows' => $dailyRows]); Log::info('[marketing-batch] step B rebuildPurchaseTotal start', ['as_of_date' => $asOfDate]); $totalRows = $this->repo->rebuildPurchaseTotal($asOfDate); Log::info('[marketing-batch] step B rebuildPurchaseTotal done', ['total_rows' => $totalRows]); Log::info('[marketing-batch] step C rebuildStats start', ['as_of_date' => $asOfDate]); $statsRows = $this->repo->rebuildStats($asOfDate); Log::info('[marketing-batch] step C rebuildStats done', ['stats_rows' => $statsRows]); $this->repo->markBatchRunSuccess($asOfDate, $dailyRows, $totalRows, $statsRows); return [ 'skipped' => false, 'as_of_date' => $asOfDate, 'daily_rows' => $dailyRows, 'total_rows' => $totalRows, 'stats_rows' => $statsRows, ]; } catch (\Throwable $e) { $this->repo->markBatchRunFailed($asOfDate, $e->getMessage()); Log::error('[marketing-batch] failed', ['as_of_date' => $asOfDate, 'err' => $e->getMessage()]); throw $e; } finally { optional($lock)->release(); } } }