refactor(gitlab): make GitLabProvider fetch non-blocking

startFetch() resolves the user id and fires the first events page,
returning a handle without reading it; resolveFetch() continues the
existing do/while pagination starting from that first response.

Pagination itself stays sequential within this provider since each
page depends on the previous one - parallelism here only spans across
providers, not within GitLab's own pages.
This commit is contained in:
2026-07-07 13:31:30 +02:00
parent 596260bb85
commit 9b631f4777
+39 -13
View File
@@ -7,6 +7,7 @@ namespace App\Service\Provider;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Contracts\HttpClient\HttpClientInterface;
use Symfony\Contracts\HttpClient\ResponseInterface;
/**
* Fetches the last 365 days of push/merge events from the GitLab REST API.
@@ -46,9 +47,14 @@ final class GitLabProvider implements ProviderInterface
}
/**
* @return array<string, int> date (Y-m-d) => event count
* @return array{baseUrl: string, userId: int, after: string, page: int, response: ResponseInterface}
*
* ponytail: the user-id lookup and event pagination stay sequential within
* this one provider (each page depends on the previous). Parallelism here
* only spans across providers; revisit only if GitLab pagination itself
* becomes the bottleneck.
*/
public function fetch(): array
public function startFetch(): array
{
$baseUrl = rtrim($this->baseUrl !== '' ? $this->baseUrl : 'https://gitlab.com', '/');
@@ -64,21 +70,30 @@ final class GitLabProvider implements ProviderInterface
throw new NotFoundHttpException("GitLab: user '{$this->username}' not found on $baseUrl");
}
$userId = $users[0]['id'];
$after = (new \DateTimeImmutable('-365 days'))->format('Y-m-d');
$response = $this->client->request('GET', "$baseUrl/api/v4/users/$userId/events", [
'headers' => ['PRIVATE-TOKEN' => $this->token],
'query' => [
'after' => $after,
'per_page' => 100,
'page' => 1,
],
]);
return ['baseUrl' => $baseUrl, 'userId' => $userId, 'after' => $after, 'page' => 1, 'response' => $response];
}
/**
* @return array<string, int> date (Y-m-d) => event count
*/
public function resolveFetch(mixed $handle): array
{
['baseUrl' => $baseUrl, 'userId' => $userId, 'after' => $after, 'page' => $page, 'response' => $response] = $handle;
$result = [];
$after = (new \DateTimeImmutable('-365 days'))->format('Y-m-d');
$page = 1;
do {
$response = $this->client->request('GET', "$baseUrl/api/v4/users/$userId/events", [
'headers' => ['PRIVATE-TOKEN' => $this->token],
'query' => [
'after' => $after,
'per_page' => 100,
'page' => $page,
],
]);
$events = $response->toArray();
foreach ($events as $event) {
@@ -87,6 +102,17 @@ final class GitLabProvider implements ProviderInterface
}
$page++;
if (count($events) === 100) {
$response = $this->client->request('GET', "$baseUrl/api/v4/users/$userId/events", [
'headers' => ['PRIVATE-TOKEN' => $this->token],
'query' => [
'after' => $after,
'per_page' => 100,
'page' => $page,
],
]);
}
} while (count($events) === 100);
$this->logger->info('GitLabProvider: fetched contributions', [