monitor/api/bin/sync-codeberg.php
fds2610-bot ec8c74c0f8 Neue KPI: offene PRs ueber alle Projekte (Issue #59)
CodebergSyncService berechnet am Ende jedes Sync-Laufs (periodisch und
webhook-getriggert, auch bei PR-Aenderungen) die Summe der offenen Pull
Requests aller konfigurierten Projekte und speichert sie als KPI
"open_prs" im bestehenden generischen KPI-Repository - sie erscheint
damit automatisch im KPI-Monitor der Wand und im KPI-Modal.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-21 11:57:08 +02:00

74 lines
2.6 KiB
PHP
Executable file

#!/usr/bin/env php
<?php
declare(strict_types=1);
use Monitor\Api\Config;
use Monitor\Api\Db\Database;
use Monitor\Api\Repository\KpiRepository;
use Monitor\Api\Repository\RepoConfigRepository;
use Monitor\Api\Repository\TicketRepository;
use Monitor\Api\Sync\CodebergSyncService;
use Monitor\Api\Sync\CurlCodebergClient;
use Monitor\Api\Sync\SyncSchedule;
use Monitor\Api\Sync\SyncTrigger;
require dirname(__DIR__) . '/vendor/autoload.php';
$config = Config::fromEnvironment();
$db = Database::forFile($config->dbPath());
$service = new CodebergSyncService(
new CurlCodebergClient($config->codebergApiBase(), $config->codebergToken()),
new TicketRepository($db),
new RepoConfigRepository($db),
new KpiRepository($db),
);
// Ohne --watch bleibt das Skript ein einmaliger Lauf (manueller Aufruf, siehe README).
if (!in_array('--watch', $argv, true)) {
$service->sync();
fwrite(STDOUT, "Codeberg-Sync abgeschlossen.\n");
return;
}
$trigger = new SyncTrigger($config->syncTriggerPath());
$interval = $config->syncIntervalSeconds();
$schedule = new SyncSchedule($interval);
fwrite(STDOUT, sprintf("[sync] Watch-Modus, periodischer Lauf alle %ds, Webhook-Trigger sofort.\n", $interval));
$lastRun = 0;
$failures = 0;
while (true) {
$triggered = $trigger->consume();
$due = (time() - $lastRun) >= $schedule->secondsUntilNextRun($failures);
if ($triggered || $due) {
$lastRun = time();
try {
$service->sync();
$failures = 0;
fwrite(STDOUT, sprintf("[sync] Lauf beendet (%s).\n", $triggered ? 'Webhook' : 'periodisch'));
} catch (Throwable $e) {
// Ein fehlgeschlagener Lauf (Codeberg nicht erreichbar, Rate-Limit) darf die
// Schleife nicht beenden, sonst landet der Container in einer Restart-Schleife.
// Stattdessen wird der naechste Versuch vorgezogen (siehe SyncSchedule) - eine
// per Webhook angeforderte Aktualisierung ist sonst verloren, weil die
// Anforderung vor dem Lauf quittiert wurde.
$failures++;
fwrite(STDERR, sprintf(
"[sync] Lauf fehlgeschlagen (%dx in Folge, naechster Versuch in %ds): %s\n",
$failures,
$schedule->secondsUntilNextRun($failures),
$e->getMessage()
));
}
}
// Sekundentakt: bestimmt, wie schnell ein Webhook-Trigger bemerkt wird. Der Check ist
// ein file_exists() auf einem lokalen Volume, kostet also praktisch nichts - im
// Gegensatz zum Codeberg-Request, der weiterhin nur bei Bedarf laeuft.
sleep(1);
}