一般社団法人 全国個人事業主支援協会

COLUMN コラム

nest.jsには、タイムアウト設定が行えます。

https://zenn.dev/kazumasa/books/3f8519dfd26d6a/viewer/44d66b

インターセプター

  • タイミング: リクエストがコントローラーに到達した「後」や、コントローラーの処理が実行されている「最中」、および「後」に実行されます。
  • 役割: リクエストの変換、レスポンスの変換、エラーハンドリング、タイムアウト処理など。
  • 処理例: レスポンスのフォーマット変更、リクエストのログ記録、エラーハンドリング、タイムアウトの設定など。

 

ただし、この実装を行った場合、

確かにタイムアウト判定はされるものの、

そのリクエストの処理自体は途中で終了とはならず、最後まで処理をしてしまいます。

 

そのため、

サービスロジック内でキャンセルをトリガーするような実装が必要になります。

サービスロジック内でキャンセルをトリガーする

Promise ベースのコードの場合、キャンセル用のフラグを手動でチェックする仕組みを作る必要があります。インターセプター内でキャンセル用のトークンを生成し、それをサービスに渡します。

import {
CallHandler,
ExecutionContext,
Injectable,
NestInterceptor,
RequestTimeoutException,
} from ‘@nestjs/common’;
import { Observable, throwError, catchError, firstValueFrom, timeout } from ‘rxjs’;

@Injectable()
export class TimeoutInterceptor implements NestInterceptor {
private activeTasks = new Map<string, AbortController>();

constructor(private readonly timeoutMs: number = 5000) {}

intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
const requestId = context.switchToHttp().getRequest().id;
const abortController = new AbortController();

// サービスにキャンセル用のトークン(AbortController)を渡す
context.switchToHttp().getRequest().abortController = abortController;

this.activeTasks.set(requestId, abortController);

return next.handle().pipe(
timeout(this.timeoutMs),
catchError((err) => {
if (err.name === ‘TimeoutError’) {
abortController.abort(); // タイムアウト時に処理を中断
return throwError(() => new RequestTimeoutException());
}
return throwError(() => err);
}),
// 完了後にキャンセル情報を削除
catchError(() => {
this.activeTasks.delete(requestId);
return throwError(() => new Error(‘Request Failed’));
}),
);
}
}

 

The following two tabs change content below.

河内 真吾

最新記事 by 河内 真吾 (全て見る)

この記事をシェアする

  • Twitterでシェア
  • Facebookでシェア
  • LINEでシェア