activityStub = Workflow::newActivityStub( UserMigrationActivityInterface::class, ActivityOptions::new() ->withStartToCloseTimeout(CarbonInterval::minutes(10)) ->withHeartbeatTimeout(CarbonInterval::seconds(60)) ->withRetryOptions( RetryOptions::new() ->withMaximumAttempts(3) ) ); } public function migrate(int $totalUsers, int $batchSize, array $simulationConfig = []): \Generator { $this->totalUsers = $totalUsers; $this->batchSize = $batchSize; $this->totalBatches = (int) ceil($totalUsers / $batchSize); try { $this->status = 'fetching_users'; $users = yield $this->activityStub->fetchExternalUsers($totalUsers, $simulationConfig); $this->status = 'processing'; for ($i = 0; $i < $this->totalBatches; $i++) { if ($this->isPaused) { $this->status = 'paused'; yield Workflow::await(fn () => !$this->isPaused); $this->status = 'processing'; } $this->currentBatch = $i + 1; $batchUsers = array_slice($users, $i * $this->batchSize, $this->batchSize); $validUsers = yield $this->activityStub->validateUsers($batchUsers, $simulationConfig); $result = yield $this->activityStub->createAccounts($validUsers, $simulationConfig); $this->processedUsers += $result['created']; $this->failedUsers += $result['failed']; $attempt = $result['attempt'] ?? 1; if ($attempt > 1) { $this->retryCount += ($attempt - 1); } yield $this->activityStub->sendWelcomeEmails($result['created_ids'], $simulationConfig); } $this->status = 'generating_report'; $report = yield $this->activityStub->generateMigrationReport( $this->totalUsers, $this->processedUsers, $this->failedUsers, $simulationConfig ); } catch (\Throwable $e) { $this->status = 'failed'; throw $e; } $this->status = 'completed'; return $report; } public function pause(): void { $this->isPaused = true; } public function resume(): void { $this->isPaused = false; } public function getProgress(): array { return [ 'status' => $this->status, 'totalUsers' => $this->totalUsers, 'processedUsers' => $this->processedUsers, 'failedUsers' => $this->failedUsers, 'isPaused' => $this->isPaused, 'currentBatch' => $this->currentBatch, 'totalBatches' => $this->totalBatches, 'percentComplete' => $this->totalUsers > 0 ? round(($this->processedUsers / $this->totalUsers) * 100, 2) : 0.0, 'retryCount' => $this->retryCount, 'rateLimitHits' => $this->rateLimitHits, ]; } }