更新: 2026年03月 · 11 分で読める · 5,442 文字
AWS Lambda のタイムアウトエラーを根本解決する実装パターン
AWS Lambda は実行時間に制限があり、デフォルトでは3秒、最大15分のタイムアウト制限があります。本記事では、タイムアウトが発生する具体的な原因と、本番環境で即座に適用できる対策コードを紹介します。
Lambda タイムアウトが発生する4つの主要な原因
タイムアウトエラーは単なる処理が遅いだけではなく、根本的な構成の問題に起因することが多いです。まずは原因を特定することが重要です。
1. 外部 API 呼び出しの応答待ち
データベースやサードパーティ API へのリクエストが想定より遅延するケースです。ネットワークレイテンシー、API サーバーの過負荷、タイムアウト設定の不適切さが主な要因です。
2. VPC 内のリソースへのアクセス遅延
Lambda が VPC 内に配置されている場合、ENI(Elastic Network Interface)の割り当てに時間がかかることがあります。これは初回実行時やコンカレンシー増加時に顕著です。
3. メモリ不足による処理速度の低下
Lambda のメモリ割り当てが低いと、CPU 性能も比例して低下し、処理時間が延長されます。特に画像処理や大規模ファイル処理で顕著です。
4. コード内の無限ループやデッドロック
バグにより、処理が完了せずに実行時間が延び続ける場合です。ログ出力がない「沈黙するハング」状態になることもあります。
実装レベルでのタイムアウト対策コード
タイムアウト値の適切な設定
CloudFormation または AWS SAM を使用して、Lambda 関数のタイムアウト値を明示的に設定します。デフォルトの3秒では、ほとんどの実務用途に不十分です。
# CloudFormation テンプレート (YAML)
Resources:
MyLambdaFunction:
Type: AWS::Lambda::Function
Properties:
FunctionName: my-timeout-function
Runtime: python3.12
Handler: index.lambda_handler
Timeout: 60 # 60秒に設定
MemorySize: 512 # メモリも十分に割り当てる
Code:
ZipFile: |
def lambda_handler(event, context):
return {"statusCode": 200}
外部 API 呼び出しにタイムアウトを設定する
HTTP リクエスト自体にタイムアウトを設定しないと、Lambda タイムアウトまで無限に待機し続けます。以下は Python での実装例です。
import requests
import json
from datetime import datetime
def lambda_handler(event, context):
"""
外部APIへのリクエストでタイムアウトを適切に設定する例
"""
try:
# connect_timeout: 接続確立の時間制限(秒)
# timeout: 全体のタイムアウト(秒)
response = requests.get(
'https://api.example.com/data',
timeout=(5, 10), # (接続タイムアウト, 読み込みタイムアウト)
headers={'User-Agent': 'AWS-Lambda'},
params={'key': event.get('query_param')}
)
response.raise_for_status()
return {
'statusCode': 200,
'body': json.dumps(response.json())
}
except requests.exceptions.Timeout:
# タイムアウトエラーは明示的にハンドルする
print(f"API タイムアウト発生: {datetime.now().isoformat()}")
return {
'statusCode': 504,
'body': json.dumps({'error': 'API request timeout'})
}
except requests.exceptions.RequestException as e:
print(f"API エラー: {str(e)}")
return {
'statusCode': 500,
'body': json.dumps({'error': 'API request failed'})
}
非同期処理とビジー待ちの回避
長時間の処理は Lambda 内で完結させず、SQS や Step Functions を使用して非同期に分割します。以下は Lambda から SQS にメッセージを送信し、別の Lambda で処理する例です。
import boto3
import json
from datetime import datetime
sqs_client = boto3.client('sqs')
def lambda_handler(event, context):
"""
重い処理をSQSキューに送信して非同期実行する
"""
queue_url = 'https://sqs.ap-northeast-1.amazonaws.com/123456789/MyQueue'
try:
# 処理対象のデータをSQSに送信
message_body = {
'task_id': event.get('task_id'),
'data': event.get('payload'),
'timestamp': datetime.now().isoformat()
}
response = sqs_client.send_message(
QueueUrl=queue_url,
MessageBody=json.dumps(message_body)
)
return {
'statusCode': 202, # Accepted
'body': json.dumps({
'message': 'Task queued for processing',
'messageId': response['MessageId']
})
}
except Exception as e:
print(f"SQS送信エラー: {str(e)}")
return {
'statusCode': 500,
'body': json.dumps({'error': 'Failed to queue task'})
}
Context オブジェクトを活用した残り時間チェック
Lambda の context オブジェクトには、残りの実行時間を取得できる get_remaining_time_in_millis() メソッドがあります。これを使い、タイムアウト直前に処理を中断できます。
import json
import time
def lambda_handler(event, context):
"""
残り時間を確認しながら処理を実行する
"""
# Lambda 関数の設定タイムアウト: 60秒とする
MAX_EXECUTION_TIME_MS = 55000 # 55秒(余裕を持たせる)
items_to_process = range(100)
processed_items = []
try:
for item in items_to_process:
# 5秒ごとに残り時間をチェック
remaining_time = context.get_remaining_time_in_millis()
if remaining_time < MAX_EXECUTION_TIME_MS:
print(f"タイムアウト間近: 残り時間 {remaining_time}ms")
# 処理を中断して結果を返す
break
# 実際の処理(ここでは1秒待機をシミュレート)
print(f"アイテム {item} を処理中...")
time.sleep(1)
processed_items.append(item)
return {
'statusCode': 200,
'body': json.dumps({
'processed_count': len(processed_items),
'total_count': len(list(items_to_process)),
'message': 'Processing completed or interrupted gracefully'
})
}
except Exception as e:
print(f"処理エラー: {str(e)}")
return {
'statusCode': 500,
'body': json.dumps({'error': str(e)})
}
VPC 内実行時のタイムアウト問題への対策
Lambda を VPC 内で実行すると、ENI 割り当ての遅延が発生します。以下の対策を実装してください。
Lambda 用の VPC エンドポイント設置
AWS のマネージドサービス(S3、DynamoDB など)には VPC エンドポイントを経由してアクセスし、インターネットゲートウェイを経由したルーティングを避けます。
# CloudFormation テンプレート (YAML)
Resources:
S3VPCEndpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
VpcId: vpc-xxxxx
ServiceName: com.amazonaws.ap-northeast-1.s3
RouteTableIds:
- rtb-xxxxx
PolicyText:
Statement:
- Effect: Allow
Principal: '*'
Action: 's3:*'
Resource: '*'
メモリとコンカレンシー設定の最適化
メモリを1024MB 以上に設定し、Reserved Concurrency を設定して ENI 割り当てを予約します。
# AWS CLI コマンド
aws lambda update-function-configuration \
--function-name my-vpc-function \
--memory-size 1024 \
--timeout 60
# コンカレンシー予約の設定
aws lambda put-function-concurrency \
--function-name my-vpc-function \
--reserved-concurrent-executions 10
デバッグと監視の実装
CloudWatch ログでの詳細なトレーシング
タイムアウト発生時の原因特定のため、処理の各ステップでログ出力を行います。
import logging
import json
from datetime import datetime
logger = logging.getLogger()
logger.setLevel(logging.INFO)
def lambda_handler(event, context):
"""
詳細ログ出力を含む実装
"""
start_time = datetime.now()
logger.info(f"Lambda 実行開始: 関数名={context.function_name}, 要求ID={context.request_id}")
logger.info(f"設定タイムアウト: {context.function_version}秒, メモリ: {context.memory_limit_in_mb}MB")
try:
logger.info(f"ステップ1: データ取得開始")
# 処理A
time_after_step1 = (datetime.now() - start_time).total_seconds()
logger.info(f"ステップ1完了: {time_after_step1:.2f}秒経過")
logger.info(f"ステップ2: API呼び出し開始")
# 処理B
time_after_step2 = (datetime.now() - start_time).total_seconds()
logger.info(f"ステップ2完了: {time_after_step2:.2f}秒経過")
logger.info("処理完了")
return {'statusCode': 200, 'message': 'Success'}
except Exception as e:
elapsed = (datetime.now() - start_time).total_seconds()
logger.error(f"エラー発生: {str(e)}, 経過時間: {elapsed:.2f}秒")
raise
よくある質問
A: デフォルトは 3 秒、最大は 15 分(900 秒)です。本番運用では最低でも 30~60 秒の設定を推奨します。API 呼び出しを含む場合は 120 秒以上の余裕を持たせてください。
A: どちらも同じタイムアウト現象を示しています。CloudWatch ログに「Task timed out after」というメッセージが出力される場合は、Lambda の実行時間がタイムアウト値を超えたことを意味します。
A: 以下の順で対策してください:(1) メモリを 1024MB 以上に増やす、(2) Reserved Concurrency を設定する、(3) VPC エンドポイントを設置する、(4) 処理を非同期化する。これらで 90% 以上のケースが解決します。
まとめ
- Lambda タイムアウトは「外部 API 待機」「VPC ENI 割り当て遅延」「メモリ不足」「無限ループ」の 4 つが主要原因
- HTTP リクエストには必ず timeout パラメータを設定し、Lambda 内の無限待機を防ぐ
- context.get_remaining_time_in_millis() で残り時間を監視し、グレースフルシャットダウンを実装する
- VPC 内実行時はメモリを 1024MB 以上に、Reserved Concurrency を設定して ENI 割り当て遅延を回避する
- 長時間処理は SQS や Step Functions で非同期化し、Lambda 内では完結させない
- CloudWatch ログで各ステップの実行時間を記録し、ボトルネックを可視化する