find($this->bulkRunId); if (! $run || $run->status !== 'pending') { return; } $service->start($run); try { $chunkSize = max(1, (int) config('tenantpilot.bulk_operations.chunk_size', 10)); $itemCount = 0; $supported = config('tenantpilot.supported_policy_types'); $totalItems = $run->total_items ?: count($run->item_ids ?? []); $failureThreshold = (int) floor($totalItems / 2); foreach (($run->item_ids ?? []) as $tenantId) { $itemCount++; try { $tenant = Tenant::query()->whereKey($tenantId)->first(); if (! $tenant) { $service->recordFailure($run, (string) $tenantId, 'Tenant not found'); if ($run->failed > $failureThreshold) { $service->abort($run, 'Circuit breaker: more than 50% of items failed.'); if ($run->user) { Notification::make() ->title('Bulk Sync Aborted') ->body('Circuit breaker triggered: too many failures (>50%).') ->icon('heroicon-o-exclamation-triangle') ->danger() ->sendToDatabase($run->user) ->send(); } return; } continue; } if (! $tenant->isActive()) { $service->recordSkippedWithReason($run, (string) $tenantId, 'Tenant is not active'); continue; } if (! $run->user || ! $run->user->canSyncTenant($tenant)) { $service->recordSkippedWithReason($run, (string) $tenantId, 'Not authorized to sync tenant'); continue; } $syncService->syncPolicies($tenant, $supported); $service->recordSuccess($run); } catch (Throwable $e) { $service->recordFailure($run, (string) $tenantId, $e->getMessage()); if ($run->failed > $failureThreshold) { $service->abort($run, 'Circuit breaker: more than 50% of items failed.'); if ($run->user) { Notification::make() ->title('Bulk Sync Aborted') ->body('Circuit breaker triggered: too many failures (>50%).') ->icon('heroicon-o-exclamation-triangle') ->danger() ->sendToDatabase($run->user) ->send(); } return; } } if ($itemCount % $chunkSize === 0) { $run->refresh(); } } $service->complete($run); if ($run->user) { $message = "Synced {$run->succeeded} tenant(s)"; if ($run->skipped > 0) { $message .= " ({$run->skipped} skipped)"; } if ($run->failed > 0) { $message .= " ({$run->failed} failed)"; } $message .= '.'; Notification::make() ->title('Bulk Sync Completed') ->body($message) ->icon('heroicon-o-check-circle') ->success() ->sendToDatabase($run->user) ->send(); } } catch (Throwable $e) { $service->fail($run, $e->getMessage()); $run->refresh(); $run->load('user'); if ($run->user) { Notification::make() ->title('Bulk Sync Failed') ->body($e->getMessage()) ->icon('heroicon-o-x-circle') ->danger() ->sendToDatabase($run->user) ->send(); } throw $e; } } }