monitor/api/tests/Unit/Sync/SyncScheduleTest.php
fds2610-bot ad14447092 Fehlgeschlagenen Codeberg-Sync zeitnah wiederholen statt bis zum naechsten Intervall zu warten
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>
2026-07-29 21:29:20 +02:00

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));
}
}