mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-14 21:26:15 -08:00
fix(server-storage): page-hide keepalive writes report an outage too
sendKeepalive() turned a failed fetch, a timeout or a gateway's 502/503/504 into a failed outcome without telling the status, so the instance stayed verified: when the hidden tab came back, its refresh skipped the /instance check and resent the queued writes, which could reach a replacement database behind the same address. Like requests, a keepalive write now reports these as offline, so the instance is checked before anything goes out again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
da9f99f3f2
commit
752ef756d6
3 files changed
+20
-2
No files matched your search
@@ -348,8 +348,9 @@ settings and guards read them in every build.
|
||||
trouble. A page started from memory first checks that the instance at the
|
||||
address is the remembered one (`ensureVerified`), and reloads if not,
|
||||
before sign-in sends the token. So does a page that went offline (any
|
||||
backend call can tell: the storage API, `HttpClient` calls through the
|
||||
interceptor and `PwaService`'s raw fetches report no answer, or a
|
||||
backend call can tell: the storage API with its page-hide `keepalive`
|
||||
writes, `HttpClient` calls through the interceptor and `PwaService`'s raw
|
||||
fetches report no answer, or a
|
||||
gateway's 502/503/504 that is not the backend's own JSON, as offline)
|
||||
before its next read: until then it sends neither the token nor writes (a
|
||||
replaced volume at the same address is another database), and it checks
|
||||
|
||||
@@ -106,6 +106,17 @@ describe('ServerApiClient', () => {
|
||||
await expect(
|
||||
slow.sendKeepalive('PUT', '/user-state/a/b', { value: 1 })
|
||||
).resolves.toEqual({ status: 'failed' });
|
||||
// An outage: the instance is checked before the next write.
|
||||
expect(status.reportOffline).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('reports a gateway answering for a down backend on a keepalive write', async () => {
|
||||
const down = jest.fn().mockResolvedValue(response(502));
|
||||
|
||||
await expect(
|
||||
client(down).sendKeepalive('PUT', '/user-state/a/b', { value: 1 })
|
||||
).resolves.toEqual({ status: 'failed' });
|
||||
expect(status.reportOffline).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('reports how a keepalive write ended', async () => {
|
||||
|
||||
@@ -208,6 +208,11 @@ export class ServerApiClient {
|
||||
)) as Partial<ServerUserStateWriteResponse>;
|
||||
return { status: 'saved', tag: body?.tag };
|
||||
}
|
||||
if (GATEWAY_UNAVAILABLE.has(response.status)) {
|
||||
// As for requests: the backend may come back as another
|
||||
// instance, checked before the next write goes out.
|
||||
this.options.status.reportOffline();
|
||||
}
|
||||
const { code, current } =
|
||||
response.status === 412 || response.status === 404
|
||||
? await readErrorBody(response)
|
||||
@@ -219,6 +224,7 @@ export class ServerApiClient {
|
||||
? { status: 'conflict', current }
|
||||
: { status: 'failed' };
|
||||
} catch {
|
||||
this.options.status.reportOffline();
|
||||
return { status: 'failed' };
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user