Trwała dostawa wyników: OUTBOX + idempotentny INBOX (wynik nie ginie) #12
Reference in New Issue
Block a user
Delete Branch "librarian-durable-delivery"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Po co
8-godzinne wyszukanie to realne pieniądze — wynik nie może zginąć przez chwilową niedostępność bota, zły adres/API, ani restart którejkolwiek strony. Robię ścieżkę librarian→bot trwałą, at-least-once, z idempotentnym renderem.
Wspólny rdzeń
durable_queue.DiskQueue— bezzależnościowa, atomowo zapisywana (temp+os.replace) kolejka na dysku, jeden plik JSON na klucz, korumpowane pliki pomijane. Unit-testowana. Dzielona przez oba obrazy (dodaneCOPY durable_queue.pydoDockerfile.librarian; bot już maCOPY *.py).Librarian (nadawca) — trwały OUTBOX
/lib_temp_files) zanim ruszy wysyłka.Bot (odbiorca) — idempotentny, trwały INBOX
/conjureridempotentny: każdy wynik trafia do INBOX na dysku (PVC/data) przed ACK; kolejkuje tylko uuid, którego jeszcze nie dostarczono (duplikat → drop) ani nie ma w locie.mark_delivered(uuid)→ uuid zapisany w zbiorze "delivered" (przycinany doDELIVERED_MAX), INBOX wyczyszczony → resendy stają się no-opami.Efekt łączny
Librarian trzyma wynik aż bot potwierdzi; bot trzyma aż wynik jest na ekranie; duplikaty nigdy nie renderują się dwa razy. Razem z poprawką drogi powrotnej w deployu (deploy#8) — drogi wynik przestaje znikać.
Konfiguracja (env, opcjonalne)
CONJURER_RESULT_SEND_ATTEMPTS(3),CONJURER_RESULT_SEND_BACKOFF(2s),CONJURER_OUTBOX_RESEND_SECONDS(60),CONJURER_RESULT_INBOX/CONJURER_DELIVERED_DIR(podCONJURER_DATA_DIR),CONJURER_DELIVERED_MAX(10000),CONJURER_LIBRARIAN_OUTBOX(pod STATE_DIR).Testy
test_durable_queue(put/dedup/prune/atomowość/korupcja/sanityzacja klucza),test_librarian_outbox(retry/backoff, przetrwanie outage'u, ACK-only-remove),test_result_durable_delivery(persist-przed-ACK, dedup w locie, dedup po dostarczeniu, replay, pong nietrwały).Suite: 55 unit + 39 integration zielone.
Uwaga wdrożeniowa
Po restarcie bota awaiting_q jest in-memory — replayowany wynik nie trafi już do oryginalnego pytającego (ctx utracony), więc idzie na kanał zapasowy z notką. Dane są zachowane; ginie tylko routing do konkretnej osoby. To świadomy, bezpieczny kompromis.
🤖 Generated with Claude Code