From bd8aeb06f5aafc90c1734d0a365afa5ac572e056 Mon Sep 17 00:00:00 2001 From: jubnl Date: Tue, 22 Sep 2026 06:29:49 +0200 Subject: [PATCH] refactor(roadtrip, reservations): return await on transactional; document the single-flight promises --- server/src/nest/reservations/reservations.service.ts | 2 +- server/src/nest/roadtrip/charging.service.ts | 2 ++ server/src/nest/roadtrip/roadtrip-hazards.service.ts | 2 ++ server/src/nest/roadtrip/roadtrip.service.ts | 4 ++-- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/server/src/nest/reservations/reservations.service.ts b/server/src/nest/reservations/reservations.service.ts index 79fd52fe9..0c069d545 100644 --- a/server/src/nest/reservations/reservations.service.ts +++ b/server/src/nest/reservations/reservations.service.ts @@ -779,7 +779,7 @@ export class ReservationsService { return { reservation, accommodationCreated, stayMirror }; } - async updatePositions(tripId: string | number, positions: { id: number; day_plan_position?: number }[], dayId?: number | string | null): Promise { + async updatePositions(tripId: string | number, positions: { id: number; day_plan_position?: number }[], dayId?: number | string | null) { if (dayId) { // Per-day positions for multi-day reservations, scoped the way the legacy // branch below already scopes its update. The table carries no trip_id and diff --git a/server/src/nest/roadtrip/charging.service.ts b/server/src/nest/roadtrip/charging.service.ts index 6523926fd..ca59742a4 100644 --- a/server/src/nest/roadtrip/charging.service.ts +++ b/server/src/nest/roadtrip/charging.service.ts @@ -66,6 +66,8 @@ export class ChargingService { private loadTariffs(source: string): Promise { const cached = this.tariffs.get(source); if (cached && cached.expires > Date.now()) return cached.value; + // Memoised in-flight fetch, not a missing await: the promise itself is cached + // so concurrent callers within the TTL share one request; the caller awaits it. const value = this.fetchTariffs(source); this.tariffs.set(source, { expires: Date.now() + 300000, value }); return value; diff --git a/server/src/nest/roadtrip/roadtrip-hazards.service.ts b/server/src/nest/roadtrip/roadtrip-hazards.service.ts index 71f693e4a..d3a5adea0 100644 --- a/server/src/nest/roadtrip/roadtrip-hazards.service.ts +++ b/server/src/nest/roadtrip/roadtrip-hazards.service.ts @@ -33,6 +33,8 @@ export class RoadtripHazardsService { async read(): Promise { if (this.cached && Date.now() - Date.parse(this.cached.fetchedAt) < 600000) return this.cached; if (this.pending !== undefined) return this.pending; + // Memoised in-flight load, not a missing await: concurrent readers join the + // pending promise above, and this frame awaits it below. this.pending = this.load(); try { this.cached = await this.pending; return this.cached; } finally { this.pending = undefined; } diff --git a/server/src/nest/roadtrip/roadtrip.service.ts b/server/src/nest/roadtrip/roadtrip.service.ts index 3f65a6bd7..331bf7ce0 100644 --- a/server/src/nest/roadtrip/roadtrip.service.ts +++ b/server/src/nest/roadtrip/roadtrip.service.ts @@ -104,7 +104,7 @@ export class RoadtripService { track?: { place_id: number; stray_km?: number | null } | null; }, ): Promise { - return this.uow.transactional(async () => { + return await this.uow.transactional(async () => { // Inside the same transaction as the chain it describes. A day that says it follows // a road whose vias never landed is worse than a day that says nothing. if (input.track === null) { @@ -222,7 +222,7 @@ export class RoadtripService { dayId: string | number, input: { vias: { id: number; after_order_index: number }[]; remove?: number[] }, ): Promise { - return this.uow.transactional(async () => { + return await this.uow.transactional(async () => { // Read before writing: the OLD anchor is what says which of two merged // legs came first, and after the updates that information is gone. const before = new Map(