PABLO.ENGINEERING
// WRÓĆ DO WSZYSTKICH WPISÓW
// 4 min

Nocny potok wpisów: watchdog kolejki i twarde limity

Nocny potok wpisów kończył się bez publikacji, mimo że sam proces nie wisiał. Dziś znalazłem przyczynę, scaliłem zaległości i zabezpieczyłem potok tak, żeby brak publikacji był widoczny, a nie ukryty za zielonym statusem.

Problem: cron meldował sukces, a wpisy leżały w PR-ach

Wyobraź sobie nocnego sortownika poczty, który co rano melduje "gotowe", ale koperty zostały w skrzynce, bo nikt nie zawiózł ich na pocztę. Dokładnie to działo się u mnie: cron nie wisiał, kończył się poprawnie i nic nie publikował.

  • 38 wpisów czekało w dwóch niezamkniętych PR-ach: 12 w agents-diary, 26 w daily digest.
  • Ostatni wpis na main pochodził z 2026-09-23.
  • Workflow kończył się bezwarunkowo exit 0, więc błąd gita, gh albo LLM nie dawał czerwonego statusu.
  • Bramka sekretów traktowała [ścieżka na serwerze] i ~/.hermes/ jako sekrety, więc fałszywe alarmy przerywały nocny przebieg.
  • repairFrontmatter wstawiał em-dash w tytuł i tym samym potrafił odrzucić własny wynik.

Do tego lokalne Playwright e2e reconnectowało się do zastarzałego serwera Next.js z poprzedniego przebiegu (reuseExistingServer), więc testy mierzyły stary build. A targetPathFor ucinał slug do 60 znaków i zostawiał myślnik na końcu: takie wpisy trafiały do feedu i sitemapy, ale ich strona zwracała 404.

Co zrobiłem:

  • Dodałem devlog_queue_watchdog.py (cron co 30 minut), który porównuje branche PR-ów z mainem i alertuje na Telegram, gdy wpisy czekają na merge albo gdy przez 2 doby nic nie trafiło na main.
  • Wprowadziłem twarde limity potoku: budżet czasu LLM 10 minut, limit 10 requestów na przebieg, timeout 120 s dla każdego procesu git i gh, przywracanie brancha w finally.
  • Zapisy wpisów są atomowe (tmp + fsync + rename). Kolizja nazwy pliku z innym tytułem kończy się błędem, a nie nadpisaniem cudzego wpisu.
  • Workflow przestał kończyć się bezwarunkowo exit 0: błąd gita, gh lub LLM daje teraz czerwony status.
  • Poprawiłem bramkę sekretów: koniec fałszywych alarmów na [ścieżka na serwerze] i ~/.hermes/, doszło wykrywanie Authorization: Bearer, tokenów botów telegramowych i zmiennych API_KEY.
  • Naprawiłem repairFrontmatter, który wstawiał em-dash w tytuł.
  • Ustawiłem reuseExistingServer: false, żeby e2e nie mierzyło starego builda.
  • Naprawiłem generator slugów i przemianowałem dwa istniejące pliki, które prowadziły do 404. Doszedł test pilnujący slugów.
  • Scaliłem 38 zaległych wpisów (PR #1 i #2) do main. GitHub oznaczył oba PR-y jako scalone.
  • Przywróciłem hotfix bezpieczeństwa robots.txt (disallow /app/) wykonany wczoraj bezpośrednio w [ścieżka na serwerze]. Teraz jest w repozytorium.
  • Dodałem 27 testów jednostkowych (npm test) wpiętych w CI: bramki, sanityzacja, budżet LLM, zapisy atomowe, wykrywanie kolejki i slugów.
  • Uprościłem teksty na /fleet: zamiast "routing", "failover" i "zero-drop" jest po polsku opisane, jaki model obsługuje którego agenta i co się dzieje przy awarii modelu głównego.

Osobno trafił się incydent operacyjny: przy wdrożeniu na [ścieżka na serwerze] użyłem git reset --hard, co skasowało nieśledzony hotfix robots.ts. Odtworzyłem go z kopii [ścieżka na serwerze] i przeniosłem do repo.

Dlaczego to ważne (Use Case):

  • Zniknął cichy tryb awarii. Jeśli wpisy znowu zaczną czekać na merge albo main stanie na 2 doby, dostaję alert, a nie pusty wpis w devlogu.
  • Wiem, ile potok może kosztować: budżet LLM i limit requestów są twarde, nie uznaniowe.
  • Atomowe zapisy i wykrywanie kolizji nazw chronią cudzą pracę przed nadpisaniem.
  • 27 testów w CI pilnuje tych zachowań, więc regresja nie przejdzie niezauważona.

Czego się nauczyłem:

  • exit 0 na końcu workflow to najprostszy sposób na ukrycie awarii. Zielony status musi być czymś zasłużonym.
  • Reużycie serwera w testach e2e potrafi po cichu mierzyć stary build. Test, który patrzy w złe miejsce, jest gorszy niż brak testu.
  • Przed git reset --hard w katalogu produkcyjnym sprawdzam git status. Nieśledzony plik nie wraca sam.

Nie twierdzę, że problem zniknął na zawsze. Twierdzę, że następnym razem zobaczę go w alercie, a nie po dwóch dniach ciszy.

#daily#ai-agents#testing