mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-21 06:12:17 +03:00
fix(codex): fail fast and release per-account Responses WS leases (#12911)
* fix(codex): fail fast and release per-account Responses WS leases * chore(changelog): add fragment for Codex WS lease fail-fast fix Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * fix(codex): carry the reasoning-rule context through the leased WS path --------- Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
This commit is contained in:
@@ -430,6 +430,9 @@ class ResponsesWsSession {
|
||||
this.firstResponseBody = null;
|
||||
this.currentRequestBody = null;
|
||||
this.preparedContext = null;
|
||||
this.leaseId = null;
|
||||
this.leaseReleased = false;
|
||||
this.leaseReleaseInFlight = false;
|
||||
// #7388: logging must be scoped per logical turn (one `response.create`
|
||||
// through its terminal event), not once for the lifetime of the WS
|
||||
// connection — a single boolean here silently dropped every turn after
|
||||
@@ -640,6 +643,23 @@ class ResponsesWsSession {
|
||||
toStringOrNull(responseBody.service_tier) || toStringOrNull(responseBody.serviceTier),
|
||||
};
|
||||
|
||||
// A reused WS connection re-runs prepare per logical turn, and each prepare
|
||||
// acquires a fresh per-account lease. Release the previous turn before
|
||||
// adopting the new lease so one session cannot hoard account slots.
|
||||
const previousLeaseId = this.leaseId;
|
||||
const newLeaseId = toStringOrNull(prepared.json?.leaseId);
|
||||
if (this.closed) {
|
||||
this.leaseId = null;
|
||||
this.releaseLeaseId(newLeaseId);
|
||||
return prepared;
|
||||
}
|
||||
this.leaseId = newLeaseId;
|
||||
if (previousLeaseId && previousLeaseId !== newLeaseId) {
|
||||
this.releaseLeaseId(previousLeaseId);
|
||||
}
|
||||
this.leaseReleased = false;
|
||||
this.leaseReleaseInFlight = false;
|
||||
|
||||
return prepared;
|
||||
}
|
||||
|
||||
@@ -770,6 +790,35 @@ class ResponsesWsSession {
|
||||
}
|
||||
}
|
||||
|
||||
releaseLease() {
|
||||
if (this.leaseReleased || this.leaseReleaseInFlight || !this.leaseId) return;
|
||||
this.leaseReleaseInFlight = true;
|
||||
const leaseId = this.leaseId;
|
||||
void callInternal(this.fetchImpl, this.baseUrl, this.bridgeSecret, "release", { leaseId })
|
||||
.then((response) => {
|
||||
if (!response.ok) throw new Error("lease release rejected");
|
||||
this.leaseReleased = true;
|
||||
this.leaseId = null;
|
||||
})
|
||||
.catch(() => {
|
||||
this.leaseReleaseInFlight = false;
|
||||
const retry = setTimeout(() => this.releaseLease(), 1000);
|
||||
retry.unref?.();
|
||||
});
|
||||
}
|
||||
|
||||
releaseLeaseId(leaseId) {
|
||||
if (!leaseId) return;
|
||||
void callInternal(this.fetchImpl, this.baseUrl, this.bridgeSecret, "release", { leaseId })
|
||||
.then((response) => {
|
||||
if (!response.ok) throw new Error("lease release rejected");
|
||||
})
|
||||
.catch(() => {
|
||||
const retry = setTimeout(() => this.releaseLeaseId(leaseId), 1000);
|
||||
retry.unref?.();
|
||||
});
|
||||
}
|
||||
|
||||
async persistHistory({
|
||||
status = 200,
|
||||
success = true,
|
||||
@@ -820,6 +869,7 @@ class ResponsesWsSession {
|
||||
close(code = 1000, reason = "normal_closure") {
|
||||
if (this.closed) return;
|
||||
this.closed = true;
|
||||
this.releaseLease();
|
||||
|
||||
clearInterval(this.pingTimer);
|
||||
this.cleanupBuffers();
|
||||
@@ -847,6 +897,7 @@ class ResponsesWsSession {
|
||||
dispose() {
|
||||
if (this.closed) return;
|
||||
this.closed = true;
|
||||
this.releaseLease();
|
||||
clearInterval(this.pingTimer);
|
||||
this.cleanupBuffers();
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user