feat: boka push ingest and stale monitoring (todo 04)
Add token- and IP-protected ingest.php, boka status checks in monitor.php, and document the two-repo push workflow. Todo 04 marked complete. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -282,6 +282,90 @@ function maybeSendReviewReminder(array $config, array $targets, string $currentH
|
||||
writeJsonFile($statePath, $newState);
|
||||
}
|
||||
|
||||
function bokaPushStaleMinutes(): int
|
||||
{
|
||||
return (int) (env('BOKA_PUSH_STALE_MINUTES') ?: 15);
|
||||
}
|
||||
|
||||
function bokaDiskWarnPercent(): int
|
||||
{
|
||||
return (int) (env('BOKA_DISK_WARN_PERCENT') ?: 85);
|
||||
}
|
||||
|
||||
function bokaBackupStaleHours(): int
|
||||
{
|
||||
return (int) (env('BOKA_BACKUP_STALE_HOURS') ?: 25);
|
||||
}
|
||||
|
||||
/** @return list<array<string, mixed>> */
|
||||
function checkBokaPushStatus(): array
|
||||
{
|
||||
$ingestToken = env('MONITOR_INGEST_TOKEN') ?? '';
|
||||
if ($ingestToken === '') {
|
||||
return [];
|
||||
}
|
||||
|
||||
$statusPath = privateDataDir() . '/boka-status.json';
|
||||
$status = readJsonFile($statusPath);
|
||||
if ($status === null) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$failures = [];
|
||||
$now = time();
|
||||
|
||||
$lastPush = $status['last_push'] ?? null;
|
||||
if (is_string($lastPush) && $lastPush !== '') {
|
||||
$lastPushAt = strtotime($lastPush) ?: 0;
|
||||
$staleMinutes = bokaPushStaleMinutes();
|
||||
$ageMinutes = (int) floor(($now - $lastPushAt) / 60);
|
||||
if ($ageMinutes > $staleMinutes) {
|
||||
$failures[] = [
|
||||
'name' => 'boka-push',
|
||||
'url' => 'ingest',
|
||||
'message' => "boka silent — no push in {$ageMinutes} min",
|
||||
'retried' => false,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$diskPercent = (int) ($status['disk_percent'] ?? 0);
|
||||
if ($diskPercent > bokaDiskWarnPercent()) {
|
||||
$failures[] = [
|
||||
'name' => 'boka-push',
|
||||
'url' => 'ingest',
|
||||
'message' => "disk at {$diskPercent}%",
|
||||
'retried' => false,
|
||||
];
|
||||
}
|
||||
|
||||
$unhealthy = (int) ($status['containers_unhealthy'] ?? 0);
|
||||
if ($unhealthy > 0) {
|
||||
$failures[] = [
|
||||
'name' => 'boka-push',
|
||||
'url' => 'ingest',
|
||||
'message' => "{$unhealthy} unhealthy container(s)",
|
||||
'retried' => false,
|
||||
];
|
||||
}
|
||||
|
||||
$backupLastSuccess = $status['backup_last_success'] ?? null;
|
||||
if (is_string($backupLastSuccess) && $backupLastSuccess !== '') {
|
||||
$backupAt = strtotime($backupLastSuccess) ?: 0;
|
||||
$ageHours = (int) floor(($now - $backupAt) / 3600);
|
||||
if ($ageHours > bokaBackupStaleHours()) {
|
||||
$failures[] = [
|
||||
'name' => 'boka-push',
|
||||
'url' => 'ingest',
|
||||
'message' => "backup stale — last success {$ageHours}h ago",
|
||||
'retried' => false,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $failures;
|
||||
}
|
||||
|
||||
/** @param list<array<string, mixed>> $failures */
|
||||
function sendDownAlert(array $failures): void
|
||||
{
|
||||
@@ -360,6 +444,16 @@ function runMonitor(bool $verbose = false): int
|
||||
maybeSendReviewReminder($config, $targets, $currentHash, $verbose);
|
||||
|
||||
$failures = array_values(array_filter($checks, static fn (array $check): bool => $check['status'] === 'down'));
|
||||
$bokaFailures = checkBokaPushStatus();
|
||||
if ($bokaFailures !== []) {
|
||||
if ($verbose) {
|
||||
foreach ($bokaFailures as $failure) {
|
||||
fwrite(STDERR, sprintf("boka-push: %s\n", $failure['message']));
|
||||
}
|
||||
}
|
||||
$failures = array_merge($failures, $bokaFailures);
|
||||
}
|
||||
|
||||
if ($failures === []) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user