mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-14 21:26:15 -08:00
fix(server-storage): the immediate offline check runs once per retry interval
A response whose headers arrived but whose body was cut off reports success and then offline, which started the next immediate instance check at once: repeated cut-off answers kept requests going and the connection indicator flickering. The check on going offline now runs at most once per retry interval; later failures wait for the timed retry. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
769ed4b246
commit
252ef9506f
3 files changed
+44
-8
No files matched your search
@@ -342,8 +342,8 @@ settings and guards read them in every build.
|
||||
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
|
||||
the instance as soon as it goes offline, so a blip costs no retry
|
||||
interval (only the instance: a read that keeps failing waits for the
|
||||
retry). Sign-out always navigates to sign-in, also when a guard kept the
|
||||
interval (only the instance, and once per retry interval: a read or a
|
||||
check that keeps failing waits for the retry). Sign-out always navigates to sign-in, also when a guard kept the
|
||||
page the first time. Both turn
|
||||
the guard's 401 (`isServerAccessChallenge`) into `reportAccessDenied()`,
|
||||
as the storage API client does with any 401, so a token changed on the
|
||||
|
||||
@@ -269,6 +269,31 @@ describe('ServerStorageSession', () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it('checks at once only once per retry interval', async () => {
|
||||
const { session, status } = setup('none');
|
||||
await session.start();
|
||||
// Headers arrive, the body is cut off: success, then offline.
|
||||
fetchMock.mockResolvedValue({
|
||||
status: 200,
|
||||
ok: true,
|
||||
headers: new Headers(),
|
||||
json: async () => {
|
||||
throw new TypeError('body cut off');
|
||||
},
|
||||
});
|
||||
fetchMock.mockClear();
|
||||
|
||||
status.reportOffline();
|
||||
for (let round = 0; round < 5; round += 1) {
|
||||
TestBed.tick();
|
||||
for (let turn = 0; turn < 10; turn += 1) {
|
||||
await Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
expect(fetchMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('reloads when another instance answers at the address', async () => {
|
||||
const { session, status } = setup('none');
|
||||
const reload = jest
|
||||
|
||||
@@ -38,6 +38,7 @@ export class ServerStorageSession {
|
||||
private readonly translate = inject(TranslateService);
|
||||
private readonly router = inject(Router);
|
||||
private reloading = false;
|
||||
private lastQuickCheck = 0;
|
||||
private lastNotice = { key: '', at: 0 };
|
||||
|
||||
readonly api = new ServerApiClient({
|
||||
@@ -72,16 +73,11 @@ export class ServerStorageSession {
|
||||
}
|
||||
});
|
||||
effect(() => {
|
||||
// Gone offline, the token and writes wait for the instance
|
||||
// check: after a blip it passes at once, not at the next retry.
|
||||
// Only the check: a read failing on its own waits for the retry.
|
||||
if (
|
||||
this.status.state() === 'offline' &&
|
||||
!this.config.startedOffline
|
||||
) {
|
||||
untracked(
|
||||
() => void this.ensureVerified().catch(() => undefined)
|
||||
);
|
||||
untracked(() => this.checkSoon());
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -112,6 +108,21 @@ export class ServerStorageSession {
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gone offline, the token and writes wait for the instance check:
|
||||
* after a blip it passes at once, not at the next retry. Only the
|
||||
* check, and once per retry interval: a read or a check that keeps
|
||||
* failing (a body cut off after its headers) waits for the retry.
|
||||
*/
|
||||
private checkSoon(): void {
|
||||
const now = Date.now();
|
||||
if (now - this.lastQuickCheck < RETRY_INTERVAL_MS) {
|
||||
return;
|
||||
}
|
||||
this.lastQuickCheck = now;
|
||||
void this.ensureVerified().catch(() => undefined);
|
||||
}
|
||||
|
||||
/** Re-reads synced user data; also the offline retry. */
|
||||
async refresh(): Promise<void> {
|
||||
if (this.config.startedOffline) {
|
||||
|
||||
Reference in new issue
Block a user