Files
janssen/EmailsImport/jnj_tower_ingest_v1.4.md
2026-06-16 14:32:28 +02:00

84 lines
3.8 KiB
Markdown

# jnj_tower_ingest v1.4.0
**Soubor:** `jnj_tower_ingest_v1.4.py`
**Datum:** 2026-06-16
**Autor:** vladimir.buzalka
**Běží:** Docker kontejner `python-runner` na Unraid Tower (192.168.1.76), u MongoDB.
## Co to je
Sjednocený **Tower-side ingest** JNJ e-mailů — fáze v jednom běhu (cron `*/5`):
| Fáze | Co dělá |
|---|---|
| **1. PARSE** | `.msg` z `/mnt/JNJEMAILS` → tělo do Mongo `emaily."vbuzalka@its.jnj.com"`. Inkrementálně přes mtime watermark. Přílohy do SeaweedFS (v1.3). **+ v1.4: detekce neodeslaného e-mailu.** |
| **2. SYNC** | nejnovější SQLite (read-only) → zrcadlo `jnj_messages` + `jnj_folder`/stav do `emaily`. NULL-safe. |
| **RECONCILE** (volitelně `--reconcile`) | **v1.4:** smaže provizorní no-ID Sent duplikáty, ke kterým existuje dvojče s reálným Message-ID. |
| **3. ENRICH** | sdílený `5_enrich_fulltext_emails --mailbox` → PG fulltext. Jen při nových dokumentech. |
Pořadí **parse → sync → (reconcile) → enrich**. Klíč = Internet Message-ID = Mongo `_id`.
## Novinka v1.4 (a) — detekce NEODESLANÉHO e-mailu
PARSE při čtení těla hledá stopy chyby odeslání (`SendAsDenied`, „could not be sent",
`TransportSend operation has failed`, `MapiExceptionSendAsDenied`). Když je najde,
dokument dostane:
- `send_failed: true`
- `send_error: "SendAsDenied (ec=1244) 0x80070005-…"` (vytažený kód, pokud je)
Dotaz na neodeslané: `{ send_failed: true }`.
> Pozn.: chybové tělo se v `.msg` objeví **až** poté, co ho Outlook do položky dopíše;
> na Tower ho přinese **re-upload z `jnj_mailbox_sync v1.3`** (+ overwrite na app.py v2.4).
> Archivní kopie zachycená před selháním chybu nenese.
## Novinka v1.4 (b) — fáze RECONCILE (smaž provizorní duplikáty)
Sent položka **bez Message-ID** (`_id` začíná `filename:`/`entryid:`) je jen **přechodný
snímek** (zachycený dřív, než Exchange doplnil Message-ID). Když k ní existuje **dvojče
s reálným Message-ID** — stejní `to` příjemci + stejný `normalized_subject` + `received_at`
do **24 h** — je provizorní kopie redundantní a **smaže se**. **Neodeslané** (bez dvojčete)
**zůstanou** (a mají `send_failed`).
- Match je na **stabilním obsahu** (e-mailové adresy + normalizovaný předmět + čas),
**ne na EntryID** (ten se mezi provizorní a finální kopií liší).
- Běží **jen s `--reconcile`** (default vypnuto — bezpečné pro cron).
- S `--dry-run` jen **vypíše plán** (nic nemaže). Bez `--dry-run` + s `--reconcile` **maže**.
## Argumenty
`--dry-run`, `--full`, `--limit N`, `--reindex`, `--force`,
`--parse-only` / `--sync-only` / `--enrich-only`, `--no-enrich`, `--enrich-always`,
**`--reconcile`** (nově).
## Spouštění
```bash
# Běžný inkrementální běh (cron) — reconcile NEběží:
docker exec python-runner python3 /scripts/jnj_tower_ingest_v1.4.py
# RECONCILE — nejdřív plán (nic nemaže):
docker exec -it python-runner python3 /scripts/jnj_tower_ingest_v1.4.py --reconcile --dry-run --sync-only
# RECONCILE — ostře (po kontrole plánu):
docker exec -it python-runner python3 /scripts/jnj_tower_ingest_v1.4.py --reconcile --sync-only
```
(`--sync-only --reconcile` = jen sync + úklid duplikátů, bez parse/enrich; reconcile
potřebuje `jnj_folder` ze sync. Pro samostatný úklid lze i bez `--sync-only`.)
## Revert
`jnj_tower_ingest_v1.3.py` (bez send_failed + reconcile), starší v `Trash/`.
## Historie verzí
- **1.0.0** — sjednocení parse + sync (mtime watermark).
- **1.1.0** — + fáze ENRICH.
- **1.2.0** — SYNC NULL-safe.
- **1.3.0** — PARSE: přílohy do SeaweedFS.
- **1.4.0** — (a) PARSE detekuje neodeslaný e-mail → `send_failed` + `send_error`.
(b) Fáze RECONCILE (`--reconcile`): smaže provizorní no-ID Sent kopie s ID-dvojčetem
(match to+předmět+čas, ne EntryID); neodeslané ponechá.