fix(maria): lacat intre reindexari, scriere atomica a indexului, XML invalid raportat
Descoperit la prima sincronizare reala din Drive: `maria-sync.timer` a pornit peste rularea manuala si doua procese faceau embeddings in paralel pe acelasi Ollama, ambele urmand sa scrie acelasi rag_index.json. Embedding-ul a incetinit de la ~7s la ~20s din concurenta, iar ultimul care termina ar fi suprascris munca celuilalt. - config.exclusive(): lacat `flock` intre procese, luat la intrarea in sync.py si indexer.py. Nu asteapta — a doua rulare iese curat cu "o reindexare e deja in curs", fiindca ar reface exact acelasi lucru. Verificat pe procese reale. - indexer scrie indexul atomic (tmp + os.replace): consumer-ul reciteste fisierul la 30s si putea prinde un JSON pe jumatate scris. - build() intoarce `warnings` pentru XML-urile care nu se pot parsa, iar rularea din linia de comanda le scrie in stderr. Pana acum, un XML invalid se indexa tacut ca text simplu, cu o singura linie pierduta in log. Context de performanta, masurat pe LXC 171 fara alta incarcare: un embedding `nomic-embed-text` ia ~7,3s, deci o reindexare completa a celor 173 de chunk-uri dureaza ~21 de minute — mai mult decat intervalul timer-ului. Nu e o problema practica (amprenta reindexeaza doar la schimbare, iar lacatul opreste suprapunerea), dar explica de ce prima rulare pare blocata. docs/rclone-google-drive-headless.md: procedura de conectare a unui container headless la Drive prin `rclone authorize`, cu transcriptul rularii reale de pe Windows, capcanele (sync e distructiv pe destinatie, connection string in loc de cale pe nume, unde stau secretele) si de ce nu contul de serviciu. Indexata in CLAUDE.md. 6 teste noi (lacat, eliberare la exceptie, scriere atomica, avertismente). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q4uzvgm7AyJch5WH8QHRhY
This commit is contained in:
@@ -112,3 +112,70 @@ def test_md_foloseste_taierea_pe_paragrafe():
|
||||
text = "primul paragraf\n\n" + "al doilea paragraf " * 20
|
||||
assert len(indexer.chunk_document("x.md", text)) >= 1
|
||||
assert indexer.chunk_document("x.md", text) == indexer.chunk_text(text)
|
||||
|
||||
|
||||
# --------------------------------------------- concurenta intre reindexari
|
||||
def test_lacatul_refuza_a_doua_reindexare():
|
||||
"""Timer-ul nu trebuie sa porneasca peste o sincronizare manuala."""
|
||||
import config
|
||||
|
||||
with config.exclusive():
|
||||
with pytest.raises(config.Busy):
|
||||
with config.exclusive():
|
||||
pass
|
||||
|
||||
|
||||
def test_lacatul_se_elibereaza_dupa_iesire():
|
||||
import config
|
||||
|
||||
with config.exclusive():
|
||||
pass
|
||||
with config.exclusive(): # trebuie sa mearga din nou
|
||||
pass
|
||||
|
||||
|
||||
def test_lacatul_se_elibereaza_si_la_exceptie():
|
||||
import config
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
with config.exclusive():
|
||||
raise ValueError("ceva")
|
||||
with config.exclusive():
|
||||
pass
|
||||
|
||||
|
||||
def test_indexul_se_scrie_atomic(write, monkeypatch):
|
||||
"""Consumer-ul reciteste indexul la 30s; nu are voie sa prinda JSON pe jumatate."""
|
||||
import config
|
||||
import indexer
|
||||
|
||||
write("x.md", "un paragraf oarecare")
|
||||
monkeypatch.setattr(indexer, "embed", lambda text: [0.1, 0.2])
|
||||
vazute = []
|
||||
real_replace = indexer.os.replace
|
||||
|
||||
def spion(src, dst):
|
||||
vazute.append((str(src), str(dst)))
|
||||
return real_replace(src, dst)
|
||||
|
||||
monkeypatch.setattr(indexer.os, "replace", spion)
|
||||
indexer.build()
|
||||
assert vazute and vazute[0][1] == str(config.INDEX_FILE)
|
||||
assert not config.INDEX_FILE.with_suffix(".json.tmp").exists()
|
||||
|
||||
|
||||
def test_xml_invalid_e_raportat_ca_avertisment(write, monkeypatch):
|
||||
import indexer
|
||||
|
||||
write("stricat.xml", "<root><a>x</a></root><in-plus/>")
|
||||
monkeypatch.setattr(indexer, "embed", lambda text: [0.0])
|
||||
out = indexer.build()
|
||||
assert any("stricat.xml" in w for w in out.get("warnings", []))
|
||||
|
||||
|
||||
def test_xml_valid_nu_produce_avertismente(write, monkeypatch):
|
||||
import indexer
|
||||
|
||||
write("bun.xml", "<root><a>x</a></root>")
|
||||
monkeypatch.setattr(indexer, "embed", lambda text: [0.0])
|
||||
assert "warnings" not in indexer.build()
|
||||
|
||||
Reference in New Issue
Block a user