options->get(self::VERSION_OPTION, 0) >= Schema::VERSION) { return self::CURRENT; } $failure = $this->failure(); if (!$force && $failure !== null && $this->clock->now() < $failure['at'] + self::RETRY_SECONDS) { return self::WAITING; } try { $version = (new Schema($this->db, $this->lockTimeout))->migrate(); } catch (\Throwable $e) { $this->options->set(self::FAILURE_OPTION, ['at' => $this->clock->now(), 'error' => get_class($e)]); return self::FAILED; } $this->options->set(self::VERSION_OPTION, $version); if ($failure !== null) { $this->options->set(self::FAILURE_OPTION, []); } return self::DONE; } /** @return array{at:int, error:string}|null the last failed attempt, until an attempt succeeds */ public function failure(): ?array { $f = $this->options->get(self::FAILURE_OPTION, []); return is_array($f) && isset($f['at'], $f['error']) ? ['at' => (int) $f['at'], 'error' => (string) $f['error']] : null; } }