Reconectare și ciclu de viață
Reconectare și ciclu de viață
RealtimeClient este construit să rămână conectat pe toată durata de viață a procesului tău. Se reconectează automat, expune controale explicite de suspend și resume pentru gazde mobile / atente la baterie și pune la dispoziție un punct de injecție CursorStore, astfel încât livrarea viitoare at-least-once (E-1b / E-10) să poată conecta un strat de persistență fără să schimbi codul tău.
Auto-reconectare cu backoff exponențial
Când socket-ul cade, clientul se reconectează automat. Programul este fix:
| Constantă | Valoare | Înțeles |
|---|---|---|
DEFAULT_RECONNECT_DELAY | 1000 ms | Prima reîncercare are loc la 1 secundă după deconectare. |
RECONNECT_BACKOFF_FACTOR | 2 | Fiecare reîncercare următoare dublează întârzierea. |
MAX_RECONNECT_DELAY | 30000 ms | Plafon — întârzierea nu trece niciodată de 30 de secunde. |
Așadar, intervalele dintre încercările de reconectare merg 1s → 2s → 4s → 8s → 16s → 30s → 30s → … până când socket-ul revine, moment în care întârzierea se resetează la 1 secundă pentru următoarea deconectare. Evenimentul connected se declanșează de fiecare dată când socket-ul se redeschide; disconnected se declanșează de fiecare dată când cade.
realtime.on('connected', () => console.log('realtime: live'));
realtime.on('disconnected', () => console.warn('realtime: căzut — se reconectează'));
realtime.on('error', (err) => console.error('realtime: eroare socket', err));
Închide clientul
Apelează realtime.close() când ai terminat. Marchează clientul ca închis, anulează orice timer de reconectare în așteptare și închide socket-ul subiacent. După close(), clientul este permanent închis — construiește unul nou dacă vrei să o iei de la capăt.
process.on('SIGTERM', () => realtime.close());
Suspendare și reluare
suspend() și resume() sunt primitivele potrivite când vrei să opreşti temporar primirea evenimentelor fără să renunți permanent la conexiune — de exemplu când o aplicație trece în fundal, când dispozitivul se trezește din sleep sau când un controler predă un dispozitiv altei instanțe.
// Aplicația a trecut în fundal — închide socket-ul, dar păstrează listenerii.
appLifecycle.on('background', () => realtime.suspend());
// Aplicația a revenit în prim-plan — reconectează-te imediat.
appLifecycle.on('foreground', () => realtime.resume());
Ce face fiecare apel:
suspend()— închide socket-ul, anulează orice timer de reconectare în așteptare și refuză să se reconecteze până cândresume()este apelat. No-op dacă este deja suspendat.resume()— șterge flag-ul de suspendare, resetează întârzierea de backoff la 1 secundă și se conectează imediat. No-op dacă nu este suspendat în prezent.
Listenerii rămân înregistrați între ciclurile suspend / resume — doar socket-ul subiacent ciclează.
suspend()nu marchează clientul ca închis. După resume() aceeași instanță este reutilizată; nu trebuie să-ți re-adaugi listenerii.Mesajele incorecte sunt aruncate în tăcere
Cadrele de protocol server-către-dispozitiv (schemele de pe pagina Scheme) sunt validate strict cu zod. Un cadru care nu trece validarea este aruncat și logat prin console.warn ([RealtimeClient] dropping invalid wire frame), astfel încât un mesaj incorect al gateway-ului să nu poată ajunge niciodată la un listener ca obiect parțial tipat. Socket-ul rămâne deschis.
Cadrele non-JSON sunt aruncate în tăcere, fără log.
Cursor store
RealtimeClientOptions.cursorStore este hook-ul de persistență pentru cursorul ultimului eveniment văzut. Clientul actual (E-1a) doar păstrează referința — căile de citire / scriere sunt conectate de munca de livrare at-least-once din E-1b / E-10. Implementarea interfeței astăzi este forward-compatibilă:
import { RealtimeClient, type CursorStore } from '@e-bon/realtime';
const cursorStore: CursorStore = {
async load() {
return (await fs.readFile('cursor', 'utf8').catch(() => null)) ?? null;
},
async save(cursor: string) {
await fs.writeFile('cursor', cursor, 'utf8');
},
};
const realtime = new RealtimeClient('https://api.e-bon.ro', {
apiKey: process.env.EBON_API_KEY!,
cursorStore,
});
Implementările pot fi sprijinite pe AsyncStorage, localStorage, un fișier sau orice altceva care satisface contractul cu două metode:
interface CursorStore {
load(): Promise<string | null>;
save(cursor: string): Promise<void>;
}
Unde mergi mai departe
- Evenimente — cele opt forme de payload partenere pe care le poți asculta.
- Scheme — cadrele server→dispozitiv și dispozitiv→server.