diff --git a/README.md b/README.md index a2b206b..dae6456 100644 --- a/README.md +++ b/README.md @@ -45,11 +45,11 @@ Config salvata in `~/.config/pi-qmem/config.json` (0600): "localDbPath": "~/.local/share/pi-qmem/qmem.sqlite", "localFallback": true, "offlineQueue": true, - "connectTimeoutMs": 2500, + "connectTimeoutMs": 15000, "timeoutMs": 30000, "breakerBaseMs": 120000, "breakerMaxMs": 600000, - "breakerTripAfter": 2 + "breakerTripAfter": 3 } ``` @@ -63,7 +63,7 @@ Due timeout distinti, per non confondere "gateway giù" con "elaborazione lunga" | Fase | Chiave | Default | Significato | |---|---|---|---| -| **connect + headers** | `connectTimeoutMs` | **2500** | nessuna risposta entro questo tempo → **gateway non raggiungibile** (fallimento definitivo) | +| **connect + headers** | `connectTimeoutMs` | **15000** | nessuna risposta entro questo tempo → **gateway non raggiungibile** (fallimento definitivo). Vale per latenze di rete instabili (VPN/AP): un valore troppo stretto (2,5 s) apre il breaker anche se il gateway è su, con misure tipiche di 1,2–2,0 s per `status`/`search` | | **body** (dopo gli header) | `timeoutMs` | 30000 | budget per il rerank/export/ricerca: un superamento è un fallimento **ambiguo** | Comportamento: @@ -72,7 +72,7 @@ Comportamento: **circuit breaker** si apre subito e resta aperto `breakerBaseMs` (**2 min**), con escalation esponenziale fino a `breakerMaxMs` (10 min). - **5xx o body lento**: fallimenti **ambigui** → retry con `Retry-After` e breaker solo dopo - `breakerTripAfter` (default 2) fallimenti consecutivi. + `breakerTripAfter` (default 3) fallimenti consecutivi. - **Breaker aperto**: le chiamate ritornano in **~0 ms senza toccare la rete** (`error: "gateway_unreachable"`, `breaker_open: true`, `retry_in_ms`), quindi i tool passano subito al fallback locale e l'outbox accoda senza attese. diff --git a/extensions/shared.ts b/extensions/shared.ts index 8a29842..639d071 100644 --- a/extensions/shared.ts +++ b/extensions/shared.ts @@ -31,7 +31,7 @@ export interface MemoryConfig { apiKey: string; /** Budget (ms) per la risposta DOPO gli header: distingue l'elaborazione lunga (default 30000). */ timeoutMs?: number; - /** Timeout (ms) per connect+headers: oltre questo il gateway è "non raggiungibile" (default 2500). */ + /** Timeout (ms) per connect+headers: oltre questo il gateway è "non raggiungibile" (default 15000). */ connectTimeoutMs?: number; /** Attesa base del circuit breaker dopo un fallimento definitivo (default 120000 = 2 min). */ breakerBaseMs?: number; @@ -52,10 +52,10 @@ const CONFIG_DEFAULTS: MemoryConfig = { url: "https://qmem.enne2.net", apiKey: "", timeoutMs: 30_000, - connectTimeoutMs: 2500, + connectTimeoutMs: 15_000, breakerBaseMs: 120_000, breakerMaxMs: 600_000, - breakerTripAfter: 2, + breakerTripAfter: 3, correctMinScore: 0.6, localFallback: true, offlineQueue: true, @@ -147,7 +147,7 @@ export function breakerIsOpen(): boolean { /** Registra un fallimento; con `definitive` (connessione) apre immediatamente. */ export function tripBreaker(reason: string, definitive: boolean, cfg?: MemoryConfig): BreakerInfo { const s = loadBreaker(); - const tripAfter = Math.max(1, cfg?.breakerTripAfter ?? CONFIG_DEFAULTS.breakerTripAfter ?? 2); + const tripAfter = Math.max(1, cfg?.breakerTripAfter ?? CONFIG_DEFAULTS.breakerTripAfter ?? 3); s.failures = definitive ? Math.max((s.failures ?? 0) + 1, tripAfter) : (s.failures ?? 0) + 1; s.lastError = reason; s.lastChange = new Date().toISOString(); @@ -249,7 +249,7 @@ export async function gatewayRequest( }; if (idempotencyKey) headers["Idempotency-Key"] = idempotencyKey; - const connectMs = Math.max(200, opts?.connectTimeoutMs ?? cfg.connectTimeoutMs ?? 2500); + const connectMs = Math.max(200, opts?.connectTimeoutMs ?? cfg.connectTimeoutMs ?? 15_000); const bodyMs = Math.max(500, opts?.timeoutMs ?? cfg.timeoutMs ?? 30_000); const url = `${cfg.url}${route}`; let lastError: unknown = null; diff --git a/skills/qmem/SKILL.md b/skills/qmem/SKILL.md index aed57fc..6f362fe 100644 --- a/skills/qmem/SKILL.md +++ b/skills/qmem/SKILL.md @@ -41,11 +41,11 @@ In quel caso: dalle sessioni pi + ultimo enrich): verifica prima dell'uso; - comandi: `/qmem:local status | import | find | queue | flush | breaker [reset] | enrich | pull` (`import` dalle sessioni, `enrich`/`pull` dal gateway quando torna online); -- **circuit breaker**: quando il gateway non risponde entro `connectTimeoutMs` (default 2,5 s) le +- **circuit breaker**: quando il gateway non risponde entro `connectTimeoutMs` (default 15 s) le chiamate successive falliscono in ~0 ms **senza toccare la rete** per ~2 minuti (stato in `~/.local/share/pi-qmem/breaker.json`): il fallback locale è immediato. Un 5xx o un body lento - sono invece "ambigui" (retry con `Retry-After`, apertura dopo 2 fallimenti). Reset: - `/qmem:local breaker reset`. + sono invece "ambigui" (retry con `Retry-After`, apertura dopo 3 fallimenti). Reset: + `/qmem:local breaker reset` (CLI: `node scripts/qmem-sqlite.mjs breaker --reset`). `qmem_store` accoda in locale: con il gateway giù il record entra nell'**outbox** locale (SQLite), è subito ricercabile (marcato ⏳) e viene inviato al gateway al