diff --git a/src/handler.ts b/src/handler.ts index a893b28..f8cb262 100644 --- a/src/handler.ts +++ b/src/handler.ts @@ -1,5 +1,7 @@ +import type { APIGatewayProxyEventV2 } from 'aws-lambda'; import { createSlackApp } from './app.ts'; import { loadEnv } from './env.ts'; +import { isSlackRetryDueToTimeout } from './lib/slackRetry.ts'; const env = loadEnv(); const { receiver } = createSlackApp(env); @@ -9,11 +11,16 @@ const { receiver } = createSlackApp(env); // AwsLambdaReceiverのハンドラーを2引数のasync関数でラップする // ref: https://github.com/slackapi/bolt-js/issues/2761 export const handler = async ( - event: Record, + event: APIGatewayProxyEventV2, context: unknown, ) => { + if (isSlackRetryDueToTimeout(event.headers)) { + console.log('skipped: slack retry (http_timeout)', { + retryNum: event.headers['x-slack-retry-num'], + }); + return { statusCode: 200, body: 'ok (retry skipped)' }; + } + const boltHandler = await receiver.start(); - // boltHandlerは内部的にcallbackを使用しないが、型定義上3引数が必須 - // biome-ignore lint/suspicious/noExplicitAny: AwsEventの型がexportされていないため - return boltHandler(event as any, context, () => {}); + return boltHandler(event, context, () => {}); }; diff --git a/src/lib/__tests__/slackRetry.test.ts b/src/lib/__tests__/slackRetry.test.ts new file mode 100644 index 0000000..abe3b3e --- /dev/null +++ b/src/lib/__tests__/slackRetry.test.ts @@ -0,0 +1,28 @@ +import assert from 'node:assert/strict'; +import { describe, it } from 'node:test'; +import { isSlackRetryDueToTimeout } from '../slackRetry.ts'; + +describe('isSlackRetryDueToTimeout', () => { + it('http_timeoutのリトライの場合はtrueを返す', () => { + const headers = { + 'x-slack-retry-num': '1', + 'x-slack-retry-reason': 'http_timeout', + }; + assert.equal(isSlackRetryDueToTimeout(headers), true); + }); + + it('http_timeout以外のリトライの場合はfalseを返す', () => { + const headers = { + 'x-slack-retry-num': '1', + 'x-slack-retry-reason': 'http_error', + }; + assert.equal(isSlackRetryDueToTimeout(headers), false); + }); + + it('x-slack-retry-numヘッダーがない場合はfalseを返す', () => { + const headers = { + 'content-type': 'application/json', + }; + assert.equal(isSlackRetryDueToTimeout(headers), false); + }); +}); diff --git a/src/lib/slackRetry.ts b/src/lib/slackRetry.ts new file mode 100644 index 0000000..d2a6308 --- /dev/null +++ b/src/lib/slackRetry.ts @@ -0,0 +1,10 @@ +import type { APIGatewayProxyEventV2 } from 'aws-lambda'; + +export function isSlackRetryDueToTimeout( + headers: APIGatewayProxyEventV2['headers'], +): boolean { + return ( + !!headers['x-slack-retry-num'] && + headers['x-slack-retry-reason'] === 'http_timeout' + ); +}