mirror of https://github.com/openclaw/openclaw.git
fix(gateway): address health snapshot review feedback
When a caller provides a runtimeSnapshot while a refresh is already in-flight, await the current refresh and return the follow-up result instead of returning stale data from the in-flight promise. This ensures callers that supply fresh runtime state never receive a snapshot that omits their updates. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
3a1464f358
commit
b2ee64c434
|
|
@ -150,4 +150,37 @@ describe("refreshGatewayHealthSnapshot", () => {
|
|||
// Only one call; no pending snapshot.
|
||||
expect(mockGetHealthSnapshot).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("returns the follow-up result (not stale) when runtimeSnapshot is provided during flight", async () => {
|
||||
const snap1 = makeRuntimeSnapshot(false);
|
||||
const snap2 = makeRuntimeSnapshot(true);
|
||||
|
||||
const staleResult = makeHealthSummary({ ts: 1 });
|
||||
const freshResult = makeHealthSummary({ ts: 2 });
|
||||
|
||||
let resolveFirst!: (v: HealthSummary) => void;
|
||||
const firstDone = new Promise<HealthSummary>((r) => {
|
||||
resolveFirst = r;
|
||||
});
|
||||
|
||||
mockGetHealthSnapshot
|
||||
.mockImplementationOnce(() => firstDone)
|
||||
.mockResolvedValueOnce(freshResult);
|
||||
|
||||
// Start first refresh (in-flight).
|
||||
const p1 = refreshGatewayHealthSnapshot({ runtimeSnapshot: snap1 });
|
||||
|
||||
// Second call arrives with a fresher snapshot while first is in-flight.
|
||||
const p2 = refreshGatewayHealthSnapshot({ runtimeSnapshot: snap2 });
|
||||
|
||||
// Complete the first (stale) refresh.
|
||||
resolveFirst(staleResult);
|
||||
|
||||
const [r1, r2] = await Promise.all([p1, p2]);
|
||||
|
||||
// First caller gets the stale result (it started the refresh).
|
||||
expect(r1.ts).toBe(1);
|
||||
// Second caller must get the fresh follow-up result, not the stale one.
|
||||
expect(r2.ts).toBe(2);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -115,6 +115,18 @@ export async function refreshGatewayHealthSnapshot(opts?: {
|
|||
void refreshGatewayHealthSnapshot({ probe: opts?.probe });
|
||||
}
|
||||
});
|
||||
} else if (opts?.runtimeSnapshot !== undefined) {
|
||||
// Caller provided fresh runtime data that the in-flight refresh won't include.
|
||||
// Wait for the current refresh to complete (its finally block will kick off a
|
||||
// follow-up using pendingRuntimeSnapshot), then return the follow-up result so
|
||||
// the caller receives a snapshot that includes the latest runtime state.
|
||||
await healthRefresh;
|
||||
// After the finally block runs, healthRefresh is either the follow-up promise
|
||||
// (if pendingRuntimeSnapshot was set) or null.
|
||||
if (healthRefresh) {
|
||||
return healthRefresh;
|
||||
}
|
||||
return healthCache!;
|
||||
}
|
||||
return healthRefresh;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue