fix(astrolabe): add pagination and psalm fixes for token refresh

- Add pagination to getAllUsersWithTokens() with limit/offset params
- Update RefreshUserTokens to process users in batches of 100
- Add lock TTL documentation to withTokenLock() docstring
- Fix psalm type errors in getAccessToken() method
- Add unit tests for pagination and batched processing

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Chris Coutinho
2026-01-28 08:13:22 +01:00
parent 5b71ac3251
commit 9491d698e8
4 changed files with 182 additions and 21 deletions
+23 -12
View File
@@ -38,6 +38,9 @@ class RefreshUserTokens extends TimedJob {
/** Default assumed token lifetime if we can't determine it (1 hour) */
private const DEFAULT_TOKEN_LIFETIME_SECONDS = 3600;
/** Batch size for processing users (prevents memory issues on large installations) */
private const BATCH_SIZE = 100;
public function __construct(
ITimeFactory $time,
private McpTokenStorage $tokenStorage,
@@ -52,23 +55,31 @@ class RefreshUserTokens extends TimedJob {
protected function run(mixed $argument): void {
$this->logger->info('RefreshUserTokens: Starting background token refresh');
$userIds = $this->tokenStorage->getAllUsersWithTokens();
$this->logger->debug('RefreshUserTokens: Found ' . count($userIds) . ' users with tokens');
$refreshed = 0;
$failed = 0;
$skipped = 0;
$offset = 0;
$totalUsers = 0;
foreach ($userIds as $userId) {
$result = $this->refreshUserTokenIfNeeded($userId);
match ($result) {
'refreshed' => $refreshed++,
'failed' => $failed++,
'skipped' => $skipped++,
};
}
// Process users in batches to prevent memory issues on large installations
do {
$userIds = $this->tokenStorage->getAllUsersWithTokens(self::BATCH_SIZE, $offset);
$batchCount = count($userIds);
$totalUsers += $batchCount;
$this->logger->info("RefreshUserTokens: Complete - refreshed=$refreshed, failed=$failed, skipped=$skipped");
foreach ($userIds as $userId) {
$result = $this->refreshUserTokenIfNeeded($userId);
match ($result) {
'refreshed' => $refreshed++,
'failed' => $failed++,
'skipped' => $skipped++,
};
}
$offset += self::BATCH_SIZE;
} while ($batchCount === self::BATCH_SIZE);
$this->logger->info("RefreshUserTokens: Complete - total=$totalUsers, refreshed=$refreshed, failed=$failed, skipped=$skipped");
}
/**