Skip to content

Commit 472ee62

Browse files
committed
Update root repo file in the CDN, fix cache busting issues on the main domain
1 parent 5130def commit 472ee62

File tree

2 files changed

+63
-24
lines changed

2 files changed

+63
-24
lines changed

src/Package/V2Dumper.php

Lines changed: 45 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ public function dumpRoot(bool $verbose = false): void
8181
];
8282
$rootFileContents['providers-api'] = str_replace('VND/PKG', '%package%', $this->router->generate('view_providers', ['name' => 'VND/PKG', '_format' => 'json'], UrlGeneratorInterface::ABSOLUTE_URL));
8383
$rootFileContents['warning'] = 'Support for Composer 1 will be shutdown on August 1st 2025. You should upgrade to Composer 2. See https://blog.packagist.com/shutting-down-packagist-org-support-for-composer-1-x/';
84-
$rootFileContents['warning-versions'] = '<1.99';
84+
$rootFileContents['warning-versions'] = '<1.999';
8585

8686
// hardcoded v1 data for BC
8787
$rootFileContents['provider-includes'] = [
@@ -268,13 +268,15 @@ private function dumpRootFile(string $file, string $json): void
268268
if (file_exists($file) && file_get_contents($file) === $json) {
269269
return;
270270
}
271-
// TODO change this to upload the file to the CDN eventually
272-
$time = time();
273271

274-
$this->writeFileAtomic($file, $json, $time);
272+
$filemtime = $this->writeCdn('packages.json', $json);
273+
274+
$this->writeFileAtomic($file, $json, $filemtime);
275275
$encoded = gzencode($json, 8);
276276
assert(is_string($encoded));
277-
$this->writeFileAtomic($file . '.gz', $encoded, $time);
277+
$this->writeFileAtomic($file . '.gz', $encoded, $filemtime);
278+
279+
$this->purgeCdn('packages.json');
278280
}
279281

280282
private function writeFileAtomic(string $path, string $contents, ?int $mtime = null): void
@@ -369,21 +371,7 @@ private function writeV2File(Package $package, string $name, string $path, strin
369371
$relativePath = 'p2/'.$pkgWithDevFlag.'.json';
370372
$this->filesystem->mkdir(dirname($path));
371373

372-
$retries = 3;
373-
do {
374-
try {
375-
$filemtime = $this->cdnClient->uploadMetadata($relativePath, $contents);
376-
break;
377-
} catch (TransportExceptionInterface $e) {
378-
if ($retries === 0) {
379-
throw $e;
380-
}
381-
$this->logger->debug('Retrying due to failure', ['exception' => $e]);
382-
sleep(1);
383-
}
384-
} while ($retries-- > 0);
385-
386-
assert(isset($filemtime));
374+
$filemtime = $this->writeCdn($relativePath, $contents);
387375

388376
// we need to make sure dumps happen always with incrementing times to avoid race conditions when
389377
// fetching metadata changes in the currently elapsing second (new items dumped after the fetch can then
@@ -406,6 +394,40 @@ private function writeV2File(Package $package, string $name, string $path, strin
406394
$timeUnix = intval(ceil($filemtime / 10000));
407395
$this->writeFileAtomic($path, $contents, $timeUnix);
408396

397+
$this->writeToReplica($path, $contents, $timeUnix);
398+
399+
$this->purgeCdn($relativePath);
400+
401+
$this->redis->zadd('metadata-dumps', [$pkgWithDevFlag => $filemtime]);
402+
$this->statsd->increment('packagist.metadata_dump_v2');
403+
}
404+
405+
/**
406+
* @param non-empty-string $relativePath
407+
* @throws TransportExceptionInterface
408+
*/
409+
private function writeCdn(string $relativePath, string $contents): int
410+
{
411+
$retries = 3;
412+
do {
413+
try {
414+
$filemtime = $this->cdnClient->uploadMetadata($relativePath, $contents);
415+
416+
return $filemtime;
417+
} catch (TransportExceptionInterface $e) {
418+
if ($retries === 0) {
419+
throw $e;
420+
}
421+
$this->logger->debug('Retrying due to failure', ['exception' => $e]);
422+
sleep(1);
423+
}
424+
} while ($retries-- > 0);
425+
426+
throw $e;
427+
}
428+
429+
private function writeToReplica(string $relativePath, string $contents, int $timeUnix): void
430+
{
409431
$retries = 3;
410432
do {
411433
try {
@@ -419,7 +441,10 @@ private function writeV2File(Package $package, string $name, string $path, strin
419441
sleep(1);
420442
}
421443
} while ($retries-- > 0);
444+
}
422445

446+
private function purgeCdn(string $relativePath): void
447+
{
423448
$retries = 3;
424449
do {
425450
if ($this->cdnClient->purgeMetadataCache($relativePath)) {
@@ -430,8 +455,5 @@ private function writeV2File(Package $package, string $name, string $path, strin
430455
}
431456
sleep(1);
432457
} while ($retries-- > 0);
433-
434-
$this->redis->zadd('metadata-dumps', [$pkgWithDevFlag => $filemtime]);
435-
$this->statsd->increment('packagist.metadata_dump_v2');
436458
}
437459
}

src/Service/CdnClient.php

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ public function __construct(
2525
private ?string $metadataPublicEndpoint,
2626
private ?string $metadataApiKey,
2727
private ?string $cdnApiKey,
28+
private string $packagistHost,
2829
private readonly LoggerInterface $logger,
2930
) {
3031
}
@@ -58,14 +59,30 @@ public function uploadMetadata(string $path, string $contents): int
5859

5960
public function purgeMetadataCache(string $path): bool
6061
{
62+
if ($this->metadataApiKey === null || $this->metadataEndpoint === null || $this->metadataPublicEndpoint === null || $this->cdnApiKey === null) {
63+
return true;
64+
}
65+
6166
$resp = $this->httpClient->request('POST', 'https://api.bunny.net/purge?'.http_build_query(['url' => $this->metadataPublicEndpoint.$path, 'async' => 'true']), [
6267
'headers' => [
6368
'AccessKey' => $this->cdnApiKey,
6469
],
6570
]);
6671
// wait for status code at least
6772
if ($resp->getStatusCode() !== 200) {
68-
$this->logger->error('Failed purging '.$path.' from CDN', ['response' => $resp->getContent(false), 'status' => $resp->getStatusCode()]);
73+
$this->logger->error('Failed purging '.$path.' from metadata CDN', ['response' => $resp->getContent(false), 'status' => $resp->getStatusCode()]);
74+
75+
return false;
76+
}
77+
78+
$resp = $this->httpClient->request('POST', 'https://api.bunny.net/purge?'.http_build_query(['url' => $this->packagistHost.$path, 'async' => 'true']), [
79+
'headers' => [
80+
'AccessKey' => $this->cdnApiKey,
81+
],
82+
]);
83+
// wait for status code at least
84+
if ($resp->getStatusCode() !== 200) {
85+
$this->logger->error('Failed purging '.$path.' from main host CDN', ['response' => $resp->getContent(false), 'status' => $resp->getStatusCode()]);
6986

7087
return false;
7188
}

0 commit comments

Comments
 (0)