e-bon
e-bon.ro
Depanare

Timeout-uri de comenzi și sweep-ul de 180s

Ce înseamnă de fapt `command.timeout` față de `command.failed`, cum funcționează sweep-ul de 30 de secunde și cum `Idempotency-Key` îți permite să reîncerci în siguranță.

O comandă este „blocată" atunci când statusul ei rămâne în pending sau sent suficient de mult timp încât sweep-ul de timeout al API-ului o trece la timeout și emite un eveniment webhook command.timeout. Această rețetă explică exact când se întâmplă asta și cum recuperezi în siguranță.

Codul de eroare așteptat pe comanda cu timeout: E500 — TimeoutCommand, cu errorMessage setat la "Command timed out after 180s". E500 este retryable, deci o reîncercare cu același Idempotency-Key este sigură.

Înțelege cum funcționează sweep-ul de timeout

  • Sweep-ul de timeout rulează la fiecare 30 de secunde.
  • Orice comandă blocată în status pending sau sent mai mult de 180 de secunde este trecută automat la timeout.
  • Când se întâmplă asta, e-bon transmite un eveniment în timp real cu { errorCode: 'E500', retryable: true } către organizația ta și declanșează un webhook command.timeout.

Deci diferența e:

  • command.failed — dispozitivul a raportat activ un eșec (un FiscalError din E1xxE9xx). Comanda a fost încercată.
  • command.timeout — dispozitivul n-a confirmat niciodată comanda în 180 de secunde de la creare. Sweep-ul a marcat-o ca inaccesibilă.

Identifică cauza probabilă

  • Dispozitiv offline — aplicația E-BON nu e conectată la cloud (fără WebSocket, aplicația e ucisă, telefonul doarme), deci comanda n-a ajuns niciodată la imprimantă.
  • Operație fiscală lungă care a depășit bugetul de 180s — extrem de rar în practică; doar rapoartele mari (export-uri P7B pe perioade lungi) se apropie.
  • Coadă blocată pe dispozitiv — o comandă anterioară a eșuat într-un mod care a blocat coada locală; comenzile ulterioare stau în pending până se eliberează coada.

Verifică o comandă cu timeout

curl https://api.e-bon.ro/api/v1/commands/{commandId} \
  -H "Authorization: Bearer <jwt>"

O comandă cu timeout returnează:

{
  "id": "cmd_abc123",
  "status": "timeout",
  "error": "Command timed out after 180s",
  "errorCode": "E500",
  "errorMessage": "Command timed out after 180s",
  "updatedAt": "2026-04-23T08:13:55.000Z"
}

Pentru a relua comanda idempotent, reîncearcă endpoint-ul original (de ex. POST /api/v1/devices/{deviceId}/commands) cu același header Idempotency-Key folosit prima dată:

curl -X POST https://api.e-bon.ro/api/v1/devices/{deviceId}/commands \
  -H "Authorization: Bearer <jwt>" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 8f3a9d3e-1b8c-4f02-9b2e-1234567890ab" \
  -d '{ "type": "print_receipt", "payload": { /* … */ } }'

Dacă cererea originală a reușit pe server și doar răspunsul s-a pierdut la tine, primești înapoi exact același ID de comandă — nu se creează un duplicat.

Aplică remedierea

Verifică să fie dispozitivul online

Deschide pagina Dispozitive în portal. Dacă dispozitivul e offline, rezolvă asta mai întâi — noua comandă se va aduna în coadă și va expira la fel. Cea mai frecventă cauză pentru „dispozitiv offline" este aplicația E-BON Android ucisă în background.

Decide între reîncercare și anulare

Pentru comenzi non-fiscale (modificări de antet/subsol, actualizări de cote TVA, retipăriri de antet pentru un raport recent) e aproape întotdeauna sigur să reîncerci — handler-ele de pe dispozitiv sunt idempotente pentru ele. Pentru print_receipt, reîncearcă doar dacă ai reutilizat același Idempotency-Key pe cererea originală; altfel verifică dacă bonul a fost deja tipărit înainte să reîncerci, pentru a evita ieșire fiscală duplicată.

Reîncearcă cu același Idempotency-Key

Re-trimite POST-ul original cu același header Idempotency-Key. API-ul îți întoarce înregistrarea de comandă existentă dacă deja există sau creează una proaspătă dacă cererea anterioară chiar n-a ajuns niciodată la server.

Așteaptă un ciclu complet de sweep (~30s) înainte să declari eșec

Sweeper-ul rulează la fiecare 30 de secunde, deci o comandă care se finalizează între sweep-uri poate părea preț de o clipă blocată înainte ca statusul să-i devină completed. Folosește GET /api/v1/commands/{id} sau abonează-te la evenimentele webhook command.completed / command.failed / command.timeout în loc de polling agresiv.

Context: Referința erorilor › E500 TimeoutCommand și Evenimente webhook › command.timeout. Contractul header-ului Idempotency-Key e descris în Prezentare API.

Cere ajutor dacă ești încă blocat

Deschide un caz de suport la support@e-bon.ro sau e-bon.ro/contact cu commandId-ul afectat, ID-ul dispozitivului și marcajul de timp al cererii originale.