activityStub = Workflow::newActivityStub( SystemMonitorActivityInterface::class, ActivityOptions::new() ->withStartToCloseTimeout(CarbonInterval::seconds(60)) ->withHeartbeatTimeout(CarbonInterval::seconds(15)) ->withRetryOptions( RetryOptions::new()->withMaximumAttempts(3) ) ); } public function monitor(int $intervalSeconds = 60, int $maxIterations = 30, array $state = [], array $simulationConfig = []): \Generator { // Restore state from previous Continue-As-New run, or initialize if (!empty($state)) { $this->iteration = $state['iteration'] ?? 0; $this->totalIterations = $state['totalIterations'] ?? $maxIterations; $this->checkHistory = $state['checkHistory'] ?? []; $this->startedAt = $state['startedAt'] ?? Workflow::now()->format('c'); $this->healthScore = $state['healthScore'] ?? 100; } else { $this->totalIterations = $maxIterations; $this->startedAt = Workflow::now()->format('c'); } $this->status = 'monitoring'; try { while ($this->iteration < $this->totalIterations && !$this->stopped) { // Run health check activity $result = yield $this->activityStub->runHealthCheck($simulationConfig); // Store in check history (keep last 10) $this->lastCheckAt = $result['timestamp'] ?? Workflow::now()->format('c'); $this->checkHistory[] = $result; if (count($this->checkHistory) > 10) { $this->checkHistory = array_slice($this->checkHistory, -10); } // Update health score (rolling average of last checks) $scores = array_column($this->checkHistory, 'healthScore'); $this->healthScore = count($scores) > 0 ? round(array_sum($scores) / count($scores), 1) : 100; $this->iteration++; // Check if we should Continue-As-New if (Workflow::getInfo()->shouldContinueAsNew || ($this->iteration % 15 === 0 && $this->iteration < $this->totalIterations)) { $continueStub = Workflow::newContinueAsNewStub(SystemMonitorWorkflowInterface::class); return yield $continueStub->monitor( $intervalSeconds, $this->totalIterations, [ 'iteration' => $this->iteration, 'totalIterations' => $this->totalIterations, 'checkHistory' => $this->checkHistory, 'startedAt' => $this->startedAt, 'healthScore' => $this->healthScore, ], $simulationConfig ); } // Don't sleep after the last iteration or if stopped if ($this->iteration < $this->totalIterations && !$this->stopped) { yield Workflow::timer($intervalSeconds); } } } catch (\Throwable $e) { $this->status = 'failed'; throw $e; } $this->status = $this->stopped ? 'stopped' : 'completed'; return [ 'status' => $this->status, 'totalChecks' => $this->iteration, 'avgHealthScore' => $this->healthScore, 'lastCheckAt' => $this->lastCheckAt, 'startedAt' => $this->startedAt, 'checkHistory' => $this->checkHistory, ]; } public function stop(): void { $this->stopped = true; } public function getStatus(): array { return [ 'status' => $this->status, 'stopped' => $this->stopped, 'iteration' => $this->iteration, 'totalIterations' => $this->totalIterations, 'healthScore' => $this->healthScore, 'startedAt' => $this->startedAt, 'lastCheckAt' => $this->lastCheckAt, 'checkHistory' => $this->checkHistory, ]; } }