Automatically retry on temporary errors when using the presence API server

This commit is contained in:
Samuel Elliott
2022-10-26 17:11:01 +01:00
parent 9d290563d8
commit 6f9afb041d
3 changed files with 41 additions and 9 deletions

View File

@@ -441,6 +441,14 @@ function createApp(
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify(response, replacer));
} catch (err) {
if (err && 'type' in err && 'code' in err && (err as any).type === 'system') {
const code: string = (err as any).code;
if (code === 'ETIMEDOUT' || code === 'ENOTFOUND' || code === 'EAI_AGAIN') {
res.setHeader('Retry-After', '60');
}
}
res.statusCode = 500;
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify({

View File

@@ -15,6 +15,7 @@ const debugSplatnet2 = createDebug('nxapi:nso:presence:splatnet2');
const MAX_CONNECT_ATTEMPTS = Infinity; // 10
const RECONNECT_INTERVAL = 5000; // 5 seconds
const MAX_PROXY_AUTO_RETRY = 10;
interface SavedPresence {
presence: Presence;
@@ -529,17 +530,40 @@ export class ZncProxyDiscordPresence extends Loop {
}
async init() {
await this.update();
return LoopResult.OK;
return await this.update() ?? LoopResult.OK;
}
async update() {
const [presence, user, data] = await getPresenceFromUrl(this.presence_url);
this.last_data = data;
protected proxy_temporary_errors = 0;
await this.discord.updatePresenceForDiscord(presence, user);
await this.updatePresenceForSplatNet2Monitor(presence, this.presence_url);
async update() {
try {
const [presence, user, data] = await getPresenceFromUrl(this.presence_url);
this.last_data = data;
this.proxy_temporary_errors = 0;
await this.discord.updatePresenceForDiscord(presence, user);
await this.updatePresenceForSplatNet2Monitor(presence, this.presence_url);
} catch (err) {
if (err instanceof ErrorResponse) {
const retry_after = err.response.headers.get('Retry-After');
if (!retry_after || !/^\d+$/.test(retry_after)) throw err;
debug('Received error response - suggests waiting %ds before retrying', retry_after, err.data);
this.proxy_temporary_errors++;
if (this.proxy_temporary_errors > MAX_PROXY_AUTO_RETRY) throw err;
// Still report the error to ZncDiscordPresenceClient to prevent presence being stuck
// on repeated errors
this.discord.onError(err);
await new Promise(rs => setTimeout(this.timeout_resolve = rs, parseInt(retry_after) * 1000));
return LoopResult.OK_SKIP_INTERVAL;
}
throw err;
}
}
async onStop() {

View File

@@ -49,7 +49,7 @@ export default abstract class Loop {
}
private skip_interval_once = false;
private timeout_resolve: ((value: void) => void) | null = null;
protected timeout_resolve: ((value: void) => void) | null = null;
skipIntervalInCurrentLoop() {
debug('Skip update interval', this.is_loop_active);