diff --git a/src/modules/parcel-sync/services/eterra-client.ts b/src/modules/parcel-sync/services/eterra-client.ts index 809413b..9734ed0 100644 --- a/src/modules/parcel-sync/services/eterra-client.ts +++ b/src/modules/parcel-sync/services/eterra-client.ts @@ -130,7 +130,7 @@ export class EterraClient { private maxRetries: number; private username: string; private password: string; - private reloginAttempted = false; + private cacheKey: string; private layerFieldsCache = new Map(); private constructor( @@ -147,6 +147,7 @@ export class EterraClient { this.username = username; this.password = password; this.maxRetries = maxRetries; + this.cacheKey = makeCacheKey(username, password); } /* ---- Factory --------------------------------------------------- */ @@ -919,8 +920,7 @@ export class EterraClient { ); } catch (error) { const err = error as AxiosError; - if (err?.response?.status === 401 && !this.reloginAttempted) { - this.reloginAttempted = true; + if (err?.response?.status === 401) { await this.login(this.username, this.password); response = await this.requestWithRetry(() => this.client.get(url, { timeout: this.timeoutMs }), @@ -984,23 +984,28 @@ export class EterraClient { ); } + /** Touch session TTL in global store (prevents expiry during long pagination) */ + private touchSession(): void { + const cached = sessionStore.get(this.cacheKey); + if (cached) cached.lastUsed = Date.now(); + } + private async requestJson( request: () => Promise<{ data: EsriQueryResponse | string; status: number; }>, ): Promise { + this.touchSession(); let response; try { response = await this.requestWithRetry(request); } catch (error) { const err = error as AxiosError; - if (err?.response?.status === 401 && !this.reloginAttempted) { - this.reloginAttempted = true; + if (err?.response?.status === 401) { + // Always attempt relogin on 401 (session may expire multiple times during long syncs) await this.login(this.username, this.password); response = await this.requestWithRetry(request); - } else if (err?.response?.status === 401) { - throw new Error("Session expired (401)"); } else throw error; } const data = response.data as EsriQueryResponse | string; @@ -1019,17 +1024,15 @@ export class EterraClient { private async requestRaw( request: () => Promise<{ data: T | string; status: number }>, ): Promise { + this.touchSession(); let response; try { response = await this.requestWithRetry(request); } catch (error) { const err = error as AxiosError; - if (err?.response?.status === 401 && !this.reloginAttempted) { - this.reloginAttempted = true; + if (err?.response?.status === 401) { await this.login(this.username, this.password); response = await this.requestWithRetry(request); - } else if (err?.response?.status === 401) { - throw new Error("Session expired (401)"); } else throw error; } const data = response.data as T | string; diff --git a/src/modules/parcel-sync/services/weekend-deep-sync.ts b/src/modules/parcel-sync/services/weekend-deep-sync.ts index 3fe9b67..8a67f99 100644 --- a/src/modules/parcel-sync/services/weekend-deep-sync.ts +++ b/src/modules/parcel-sync/services/weekend-deep-sync.ts @@ -299,17 +299,6 @@ export async function runWeekendDeepSync(): Promise { `[weekend-sync] Sesiune #${state.totalSessions} pornita. ${state.cities.length} orase in coada.`, ); - // Create eTerra client (shared across steps) - let client: EterraClient; - try { - client = await EterraClient.create(username, password); - } catch (err) { - const msg = err instanceof Error ? err.message : String(err); - console.error(`[weekend-sync] Nu se poate conecta la eTerra: ${msg}`); - await saveState(state); - return; - } - // Sort cities: priority first, then shuffle within same priority const sorted = [...state.cities].sort((a, b) => { if (a.priority !== b.priority) return a.priority - b.priority; @@ -348,9 +337,10 @@ export async function runWeekendDeepSync(): Promise { await sleep(pause); } - // Execute step + // Execute step — fresh client per step (sessions expire after ~10 min) console.log(`[weekend-sync] ${city.name}: ${stepName}...`); try { + const client = await EterraClient.create(username, password); const result = await executeStep(city, stepName, client); city.steps[stepName] = result.success ? "done" : "error"; if (!result.success) city.errorMessage = result.message;