find($this->bulkRunId); if (! $run || $run->status !== 'pending') { return; } $service->start($run); try { $itemCount = 0; $succeeded = 0; $failed = 0; $skipped = 0; $failures = []; $chunkSize = 10; $totalItems = $run->total_items ?: count($run->item_ids ?? []); $failureThreshold = (int) floor($totalItems / 2); foreach ($run->item_ids as $policyId) { $itemCount++; try { $policy = Policy::find($policyId); if (! $policy) { $service->recordFailure($run, (string) $policyId, 'Policy not found'); $failed++; $failures[] = [ 'item_id' => (string) $policyId, 'reason' => 'Policy not found', 'timestamp' => now()->toIso8601String(), ]; if ($failed > $failureThreshold) { $service->abort($run, 'Circuit breaker: more than 50% of items failed.'); if ($run->user) { Notification::make() ->title('Bulk Delete Aborted') ->body('Circuit breaker triggered: too many failures (>50%).') ->icon('heroicon-o-exclamation-triangle') ->danger() ->sendToDatabase($run->user) ->send(); } return; } continue; } if ($policy->ignored_at) { $service->recordSkipped($run); $skipped++; continue; } $policy->ignore(); $service->recordSuccess($run); $succeeded++; } catch (Throwable $e) { $service->recordFailure($run, (string) $policyId, $e->getMessage()); $failed++; $failures[] = [ 'item_id' => (string) $policyId, 'reason' => $e->getMessage(), 'timestamp' => now()->toIso8601String(), ]; if ($failed > $failureThreshold) { $service->abort($run, 'Circuit breaker: more than 50% of items failed.'); if ($run->user) { Notification::make() ->title('Bulk Delete Aborted') ->body('Circuit breaker triggered: too many failures (>50%).') ->icon('heroicon-o-exclamation-triangle') ->danger() ->sendToDatabase($run->user) ->send(); } return; } } // Refresh the run from database every 10 items to avoid stale data if ($itemCount % $chunkSize === 0) { $run->refresh(); } } $service->complete($run); if ($succeeded > 0 || $failed > 0 || $skipped > 0) { $message = "Successfully deleted {$succeeded} policies"; if ($skipped > 0) { $message .= " ({$skipped} skipped)"; } if ($failed > 0) { $message .= " ({$failed} failed)"; } $message .= '.'; Notification::make() ->title('Bulk Delete Completed') ->body($message) ->icon('heroicon-o-check-circle') ->success() ->sendToDatabase($run->user) ->send(); } } catch (Throwable $e) { $service->fail($run, $e->getMessage()); // Reload run with user relationship $run->refresh(); $run->load('user'); if ($run->user) { Notification::make() ->title('Bulk Delete Failed') ->body($e->getMessage()) ->icon('heroicon-o-x-circle') ->danger() ->sendToDatabase($run->user) ->send(); } throw $e; } } }