84 lines
3.8 KiB
Markdown
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á.
|