activityStub = Workflow::newActivityStub( ExternalApiSyncActivityInterface::class, ActivityOptions::new() ->withStartToCloseTimeout(CarbonInterval::minutes(5)) ->withHeartbeatTimeout(CarbonInterval::seconds(30)) ->withRetryOptions( RetryOptions::new() ->withMaximumAttempts(5) ->withInitialInterval(CarbonInterval::seconds(2)) ->withBackoffCoefficient(2.0) ->withMaximumInterval(CarbonInterval::seconds(30)) ) ); } public function sync(string $apiEndpoint, array $simulationConfig = []): \Generator { try { // Step 1: Refresh API token $this->status = 'authenticating'; $token = yield $this->activityStub->refreshToken($simulationConfig); // Step 2: Paginated fetch loop $this->status = 'syncing'; $hasMore = true; while ($hasMore) { // Check for pause if ($this->isPaused) { $this->status = 'paused'; yield Workflow::await(fn () => !$this->isPaused); $this->status = 'syncing'; } // Fetch one page $pageResult = yield $this->activityStub->fetchPage($this->currentCursor, $token, $simulationConfig); $pageResult = (array) $pageResult; $attempt = $pageResult['attempt'] ?? 1; if ($attempt > 1) { $this->retryCount += ($attempt - 1); } $this->pagesFetched++; $this->currentCursor = $pageResult['nextCursor']; $hasMore = $pageResult['hasMore']; // Transform and store records if (!empty($pageResult['records'])) { $storeResult = yield $this->activityStub->transformAndStore($pageResult['records'], $simulationConfig); $storeResult = (array) $storeResult; $this->recordsSynced += $storeResult['stored'] ?? 0; $storeAttempt = $storeResult['attempt'] ?? 1; if ($storeAttempt > 1) { $this->retryCount += ($storeAttempt - 1); } } } } catch (\Throwable $e) { $this->status = 'failed'; throw $e; } $this->status = 'completed'; return [ 'status' => 'completed', 'pagesFetched' => $this->pagesFetched, 'recordsSynced' => $this->recordsSynced, 'rateLimitHits' => $this->rateLimitHits, 'retryCount' => $this->retryCount, ]; } public function pause(): void { $this->isPaused = true; } public function resume(): void { $this->isPaused = false; } public function getProgress(): array { return [ 'status' => $this->status, 'pagesFetched' => $this->pagesFetched, 'recordsSynced' => $this->recordsSynced, 'rateLimitHits' => $this->rateLimitHits, 'retryCount' => $this->retryCount, 'currentCursor' => $this->currentCursor, 'isPaused' => $this->isPaused, ]; } }