enhance(backend): ActivityPub 周りで連合先から HTTP 429 Too Many Requests を受け取った際にジョブをリトライするように (#12917)

* enhance(backend): ActivityPub 周りで HTTP 429 Too Many Requests を受け取った際にリトライするように

* add to changelog

---------

Co-authored-by: syuilo <Syuilotan@yahoo.co.jp>
This commit is contained in:
riku6460 2024-01-06 09:40:08 +09:00 committed by GitHub
parent d415fd29a3
commit 24645e3d3d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 13 additions and 8 deletions

View File

@ -20,6 +20,7 @@
- Enhance: チャンネルノートのピン留めをノートのメニューからできるよ - Enhance: チャンネルノートのピン留めをノートのメニューからできるよ
### Server ### Server
- Enhance: 連合先のレートリミットに引っかかった際にリトライするようになりました
- Enhance: ActivityPub Deliver queueでBodyを事前処理するように (#12916) - Enhance: ActivityPub Deliver queueでBodyを事前処理するように (#12916)
## 2023.12.2 ## 2023.12.2

View File

@ -97,6 +97,8 @@ export class ApInboxService {
} catch (err) { } catch (err) {
if (err instanceof Error || typeof err === 'string') { if (err instanceof Error || typeof err === 'string') {
this.logger.error(err); this.logger.error(err);
} else {
throw err;
} }
} }
} }
@ -256,7 +258,7 @@ export class ApInboxService {
const targetUri = getApId(activity.object); const targetUri = getApId(activity.object);
this.announceNote(actor, activity, targetUri); await this.announceNote(actor, activity, targetUri);
} }
@bindThis @bindThis
@ -288,7 +290,7 @@ export class ApInboxService {
} catch (err) { } catch (err) {
// 対象が4xxならスキップ // 対象が4xxならスキップ
if (err instanceof StatusError) { if (err instanceof StatusError) {
if (err.isClientError) { if (!err.isRetryable) {
this.logger.warn(`Ignored announce target ${targetUri} - ${err.statusCode}`); this.logger.warn(`Ignored announce target ${targetUri} - ${err.statusCode}`);
return; return;
} }
@ -373,7 +375,7 @@ export class ApInboxService {
}); });
if (isPost(object)) { if (isPost(object)) {
this.createNote(resolver, actor, object, false, activity); await this.createNote(resolver, actor, object, false, activity);
} else { } else {
this.logger.warn(`Unknown type: ${getApType(object)}`); this.logger.warn(`Unknown type: ${getApType(object)}`);
} }
@ -404,7 +406,7 @@ export class ApInboxService {
await this.apNoteService.createNote(note, resolver, silent); await this.apNoteService.createNote(note, resolver, silent);
return 'ok'; return 'ok';
} catch (err) { } catch (err) {
if (err instanceof StatusError && err.isClientError) { if (err instanceof StatusError && !err.isRetryable) {
return `skip ${err.statusCode}`; return `skip ${err.statusCode}`;
} else { } else {
throw err; throw err;

View File

@ -216,7 +216,7 @@ export class ApNoteService {
return { status: 'ok', res }; return { status: 'ok', res };
} catch (e) { } catch (e) {
return { return {
status: (e instanceof StatusError && e.isClientError) ? 'permerror' : 'temperror', status: (e instanceof StatusError && !e.isRetryable) ? 'permerror' : 'temperror',
}; };
} }
}; };

View File

@ -7,6 +7,7 @@ export class StatusError extends Error {
public statusCode: number; public statusCode: number;
public statusMessage?: string; public statusMessage?: string;
public isClientError: boolean; public isClientError: boolean;
public isRetryable: boolean;
constructor(message: string, statusCode: number, statusMessage?: string) { constructor(message: string, statusCode: number, statusMessage?: string) {
super(message); super(message);
@ -14,5 +15,6 @@ export class StatusError extends Error {
this.statusCode = statusCode; this.statusCode = statusCode;
this.statusMessage = statusMessage; this.statusMessage = statusMessage;
this.isClientError = typeof this.statusCode === 'number' && this.statusCode >= 400 && this.statusCode < 500; this.isClientError = typeof this.statusCode === 'number' && this.statusCode >= 400 && this.statusCode < 500;
this.isRetryable = !this.isClientError || this.statusCode === 429;
} }
} }

View File

@ -111,7 +111,7 @@ export class DeliverProcessorService {
if (res instanceof StatusError) { if (res instanceof StatusError) {
// 4xx // 4xx
if (res.isClientError) { if (!res.isRetryable) {
// 相手が閉鎖していることを明示しているため、配送停止する // 相手が閉鎖していることを明示しているため、配送停止する
if (job.data.isSharedInbox && res.statusCode === 410) { if (job.data.isSharedInbox && res.statusCode === 410) {
this.federatedInstanceService.fetch(host).then(i => { this.federatedInstanceService.fetch(host).then(i => {

View File

@ -85,7 +85,7 @@ export class InboxProcessorService {
} catch (err) { } catch (err) {
// 対象が4xxならスキップ // 対象が4xxならスキップ
if (err instanceof StatusError) { if (err instanceof StatusError) {
if (err.isClientError) { if (!err.isRetryable) {
throw new Bull.UnrecoverableError(`skip: Ignored deleted actors on both ends ${activity.actor} - ${err.statusCode}`); throw new Bull.UnrecoverableError(`skip: Ignored deleted actors on both ends ${activity.actor} - ${err.statusCode}`);
} }
throw new Error(`Error in actor ${activity.actor} - ${err.statusCode}`); throw new Error(`Error in actor ${activity.actor} - ${err.statusCode}`);

View File

@ -71,7 +71,7 @@ export class WebhookDeliverProcessorService {
if (res instanceof StatusError) { if (res instanceof StatusError) {
// 4xx // 4xx
if (res.isClientError) { if (!res.isRetryable) {
throw new Bull.UnrecoverableError(`${res.statusCode} ${res.statusMessage}`); throw new Bull.UnrecoverableError(`${res.statusCode} ${res.statusMessage}`);
} }