Auf der Produktionsmaschine traten vereinzelt Timeouts nach codeberg.org auf
("Operation timed out after 15003 milliseconds with 0 bytes received"), waehrend
die Verbindung sonst in ~0,1s antwortet.
Bisher fiel der Dauerlaeufer nach so einem Fehlschlag in den regulaeren Takt
zurueck. Weil SyncTrigger::consume() die Webhook-Anforderung schon vor dem Lauf
quittiert, war eine per Webhook angeforderte Aktualisierung damit verloren und
kam erst bis zu MONITOR_SYNC_INTERVAL Sekunden spaeter - genau die Verzoegerung,
die der Webhook abschaffen sollte.
Neu wird der naechste Versuch nach einem Fehlschlag vorgezogen: 5s, 10s, 20s, …
gedeckelt auf das regulaere Intervall (Sync\SyncSchedule). Ein kurzer Aussetzer
ist damit binnen Sekunden ueberstanden, eine laengere Codeberg-Stoerung laeuft
trotzdem nicht in einen Dauerbeschuss. Nach einem erfolgreichen Lauf gilt sofort
wieder das regulaere Intervall.
Die Wartezeit-Berechnung liegt in einer eigenen Klasse, weil die Schleife in
bin/sync-codeberg.php selbst nicht testbar ist.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
65 lines
2.2 KiB
PHP
65 lines
2.2 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Monitor\Api\Tests\Sync;
|
|
|
|
use Monitor\Api\Sync\SyncSchedule;
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
final class SyncScheduleTest extends TestCase
|
|
{
|
|
public function testUsesTheRegularIntervalWhileEverythingWorks(): void
|
|
{
|
|
$schedule = new SyncSchedule(600);
|
|
|
|
self::assertSame(600, $schedule->secondsUntilNextRun(0));
|
|
}
|
|
|
|
/**
|
|
* Der Kern des Fixes: Nach einem Fehlschlag darf nicht bis zum naechsten regulaeren
|
|
* Lauf gewartet werden - die per Webhook angeforderte Aktualisierung waere sonst bis
|
|
* zu MONITOR_SYNC_INTERVAL Sekunden verzoegert.
|
|
*/
|
|
public function testRetriesQuicklyAfterAFailure(): void
|
|
{
|
|
$schedule = new SyncSchedule(600, retryBaseSeconds: 5);
|
|
|
|
self::assertSame(5, $schedule->secondsUntilNextRun(1));
|
|
}
|
|
|
|
public function testBacksOffExponentiallyWhileFailuresContinue(): void
|
|
{
|
|
$schedule = new SyncSchedule(600, retryBaseSeconds: 5);
|
|
|
|
self::assertSame(10, $schedule->secondsUntilNextRun(2));
|
|
self::assertSame(20, $schedule->secondsUntilNextRun(3));
|
|
self::assertSame(40, $schedule->secondsUntilNextRun(4));
|
|
}
|
|
|
|
/** Eine laengere Codeberg-Stoerung darf nicht in einen Dauerbeschuss laufen. */
|
|
public function testNeverWaitsLongerThanTheRegularInterval(): void
|
|
{
|
|
$schedule = new SyncSchedule(600, retryBaseSeconds: 5);
|
|
|
|
self::assertSame(600, $schedule->secondsUntilNextRun(8));
|
|
self::assertSame(600, $schedule->secondsUntilNextRun(50));
|
|
}
|
|
|
|
/** Sehr viele Fehlschlaege duerfen 2^n nicht ueberlaufen lassen. */
|
|
public function testSurvivesAnAbsurdNumberOfFailures(): void
|
|
{
|
|
$schedule = new SyncSchedule(600, retryBaseSeconds: 5);
|
|
|
|
self::assertSame(600, $schedule->secondsUntilNextRun(PHP_INT_MAX));
|
|
}
|
|
|
|
/** Bei sehr kurzem Intervall bleibt dieses die Untergrenze, nicht die Retry-Basis. */
|
|
public function testShortIntervalIsNotStretchedByTheRetryBase(): void
|
|
{
|
|
$schedule = new SyncSchedule(3, retryBaseSeconds: 5);
|
|
|
|
self::assertSame(3, $schedule->secondsUntilNextRun(0));
|
|
self::assertSame(3, $schedule->secondsUntilNextRun(1));
|
|
}
|
|
}
|