with(['tenant', 'user'])->find($this->bulkOperationRunId); if (! $run) { return; } $policy = Policy::query()->with('tenant')->find($this->policyId); if (! $policy || ! $policy->tenant) { $bulkOperationService->abort($run, 'policy_not_found'); $this->notifyStatus($run, 'failed'); return; } $this->notifyStatus($run, 'queued'); $bulkOperationService->start($run); $this->notifyStatus($run, 'running'); try { $versionService->captureFromGraph( tenant: $policy->tenant, policy: $policy, createdBy: $this->createdBy, includeAssignments: $this->includeAssignments, includeScopeTags: $this->includeScopeTags, ); $bulkOperationService->recordSuccess($run); $bulkOperationService->complete($run); $this->notifyStatus($run, $run->refresh()->status); } catch (Throwable $e) { $bulkOperationService->recordFailure( run: $run, itemId: (string) $policy->getKey(), reason: $bulkOperationService->sanitizeFailureReason($e->getMessage()) ); $bulkOperationService->complete($run); $this->notifyStatus($run->refresh(), $run->status); throw $e; } } private function notifyStatus(BulkOperationRun $run, string $status): void { if (! $run->relationLoaded('user')) { $run->loadMissing('user'); } if (! $run->user) { return; } $normalizedStatus = $status === 'pending' ? 'queued' : $status; $run->user->notify(new RunStatusChangedNotification([ 'tenant_id' => (int) $run->tenant_id, 'run_type' => 'bulk_operation', 'run_id' => (int) $run->getKey(), 'status' => (string) $normalizedStatus, 'counts' => [ 'total' => (int) $run->total_items, 'processed' => (int) $run->processed_items, 'succeeded' => (int) $run->succeeded, 'failed' => (int) $run->failed, 'skipped' => (int) $run->skipped, ], ])); } }