
Amazon Data FirehoseのLambda変換で、失敗・破棄したレコードがどこへ行くのか確かめてみた
はじめに
おはようございます〜
クラウド事業統括本部/プロフェッショナルサービス事業本部/運用イノベーション部の三ツ口寛太です(╹◡╹)
今回は、Amazon Data FirehoseのLambda変換で、失敗・破棄したレコードがどこへ行くのかを、実際にレコードを送って確かめてみます🧑💻
Amazon Data Firehose(旧 Kinesis Data Firehose。2024年2月に名前が変わりました)には、S3などへ届ける前に、Lambdaでレコードを加工できる「データ変換」があります。
Lambdaは、レコードごとに Ok/Dropped/ProcessingFailed のどれかを返せます。ただ、返したレコードが実際にS3のどこに、どんな形で残るのかは、ドキュメントを読んだだけでは分かりにくいです。
最近、試験勉強をしていて、「使ってみたいな」と思っていたサービスでもあるので、実際に触って確かめてみることにしました!
わざと失敗するレコードを混ぜて送り、S3の中身を確認します💻
この記事で分かること
- 正常なレコードが、S3にどんな形で届くか
DroppedとProcessingFailedで、S3での扱いがどう違うか- 失敗したレコードのファイルに、何が書かれているか
- Lambdaが例外で落ちたとき、同じバッチの正常なレコードがどうなるか。何回リトライされるか
- 送ってから、S3に届くまでにかかった時間
こだわりポイント
- 1つのLambdaで、レコードの中身に応じて 成功/破棄/変換失敗/例外 の4パターンを意図的に作り分ける
- S3の出力先を
transformed/(変換後)、errors/(失敗)、source/(変換前のバックアップ)に分けて、どのレコードがどこへ行ったかを見分けやすくする - CloudFormation1枚で構築。操作は AWS CloudShell だけで完結(CLIのインストールや認証設定は不要)
- 送信時刻と配信時刻を毎回記録して、届くまでの時間も実測する
先に結論
- 正常なレコードは、Lambdaで変換した形のまま、改行区切り(JSON Lines)で
transformed/に届いた Droppedのレコードは、transformed/にもerrors/にも出なかった。ただし、バックアップを有効にしているとsource/には残ったProcessingFailedのレコードは、errors/processing-failed/に届いた。ファイルには元のデータが Base64(rawData) で残り、errorCodeはLambda.ProcessingFailedStatusだった- Lambdaが例外で落ちると、同じバッチの正常なレコードも巻き込まれて
errors/に入った(errorCodeはLambda.FunctionError)。Lambdaは4回(初回+リトライ3回)呼ばれた - 送信からS3に届くまでは、約80秒〜約2分20秒。Lambdaのバッファ(60秒)とS3のバッファ(60秒)が効いていた
今回の構成

- クライアント(CloudShellから
aws firehose put-record-batch)→ Firehose(Direct PUT)→ Lambda(変換)→ S3 - 変換後は
transformed/、失敗はerrors/、変換前のバックアップはsource/に出力 - CloudWatch Logsに、Lambdaのログと、Firehoseの配信ログを出力
構築されるリソースと主な設定値
| リソース | 設定値 | 設定の意図 |
|---|---|---|
| S3バケット | パブリックアクセスブロック、SSE-S3 | 配信先。変換後・失敗・バックアップを、プレフィックスで分けて置く |
| Lambda(変換) | Python 3.12、128MB、タイムアウト60秒、インラインコード | レコードの中身で、戻り値のパターンを作り分ける |
| Firehose | Direct PUT、S3宛先、バッファ 1MB/60秒、圧縮なし | 圧縮しないほうがS3上でそのまま読める。60秒は既定値 |
| Lambdaプロセッサ | バッファ 1MB/60秒、NumberOfRetries は 3 |
Lambdaに渡すまでのバッファとリトライ回数を明示する |
| 出力先プレフィックス | 正常:transformed/、失敗:errors/!{firehose:error-output-type}/、バックアップ:source/ |
どのレコードがどこに行ったかを見分けやすくする |
| IAMロール(Firehose) | S3書き込み、lambda:InvokeFunction、ログ出力 |
必要な権限に絞る |
| CloudWatch Logs | Lambda用、Firehose配信用(保持7日) | 呼び出し回数と例外の確認に使う |
Lambdaの動き(入力レコード → 戻り値)
| 入力(JSON) | Lambdaの戻り値 | 備考 |
|---|---|---|
{"id":1,"user":"a","amount":1000} |
Ok |
amount_with_tax(税込金額)と processed_at を足し、末尾に改行を付ける |
{"id":14,"action":"drop"} |
Dropped |
意図的な破棄 |
{"id":15,"action":"fail"} |
ProcessingFailed |
意図的な失敗 |
this is not json |
ProcessingFailed |
JSONとして読めない |
{"id":22,"action":"raise"} |
(例外を投げる) | バッチ全体が失敗する。リトライの確認用 |
テンプレート
テンプレート全文(firehose-lambda-transform.yamlの中身)
AWSTemplateFormatVersion: "2010-09-09"
Description: Amazon Data Firehose + Lambda data transformation lab (failed record behavior)
Parameters:
ProjectName:
Type: String
Default: fh-lab
AllowedPattern: "^[a-z0-9][a-z0-9-]{1,18}[a-z0-9]$"
Description: Resource name prefix (lowercase letters, digits, hyphens, 3-20 chars)
BackupMode:
Type: String
Default: Enabled
AllowedValues:
- Enabled
- Disabled
Description: Back up all source records to S3 (source/ prefix)
LambdaRetries:
Type: Number
Default: 3
MinValue: 0
MaxValue: 300
Description: Firehose retries when the Lambda invocation itself fails (NumberOfRetries)
Conditions:
BackupEnabled: !Equals [!Ref BackupMode, Enabled]
Resources:
# ---------- 配信先S3 ----------
DestBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub ${ProjectName}-${AWS::AccountId}-${AWS::Region}
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
# ---------- 変換用Lambda ----------
TransformLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub /aws/lambda/${ProjectName}-transform
RetentionInDays: 7
TransformRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: write-logs
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- logs:CreateLogStream
- logs:PutLogEvents
Resource: !GetAtt TransformLogGroup.Arn
TransformFunction:
Type: AWS::Lambda::Function
DependsOn: TransformLogGroup
Properties:
FunctionName: !Sub ${ProjectName}-transform
Runtime: python3.12
Handler: index.handler
Role: !GetAtt TransformRole.Arn
Timeout: 60
MemorySize: 128
Code:
ZipFile: |
import base64
import json
from datetime import datetime, timezone
TAX_RATE = 1.10
def result(record_id, status, data):
return {"recordId": record_id, "result": status, "data": data}
def handler(event, context):
out = []
counts = {"Ok": 0, "Dropped": 0, "ProcessingFailed": 0}
for r in event["records"]:
rid = r["recordId"]
raw = base64.b64decode(r["data"])
# JSONとして読めないレコードは変換失敗にする
try:
body = json.loads(raw)
except ValueError:
body = None
if not isinstance(body, dict):
out.append(result(rid, "ProcessingFailed", r["data"]))
counts["ProcessingFailed"] += 1
continue
action = body.get("action")
# Lambda自体が例外で落ちるケース(バッチ全体が失敗する)
if action == "raise":
raise RuntimeError("intentional failure for lab")
if action == "drop":
out.append(result(rid, "Dropped", r["data"]))
counts["Dropped"] += 1
continue
if action == "fail":
out.append(result(rid, "ProcessingFailed", r["data"]))
counts["ProcessingFailed"] += 1
continue
# 正常系:税込金額と処理時刻を足す。末尾に改行を付けてJSON Linesにする
body["amount_with_tax"] = round(body.get("amount", 0) * TAX_RATE)
body["processed_at"] = datetime.now(timezone.utc).isoformat()
encoded = base64.b64encode(
(json.dumps(body, ensure_ascii=False) + "\n").encode("utf-8")
).decode("utf-8")
out.append(result(rid, "Ok", encoded))
counts["Ok"] += 1
print(json.dumps({"received": len(event["records"]), **counts}))
return {"records": out}
# ---------- Firehose ----------
FirehoseLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub /aws/kinesisfirehose/${ProjectName}
RetentionInDays: 7
FirehoseLogStream:
Type: AWS::Logs::LogStream
Properties:
LogGroupName: !Ref FirehoseLogGroup
LogStreamName: DestinationDelivery
FirehoseRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service: firehose.amazonaws.com
Action: sts:AssumeRole
Condition:
StringEquals:
sts:ExternalId: !Ref AWS::AccountId
Policies:
- PolicyName: deliver-to-s3-and-invoke-lambda
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- s3:AbortMultipartUpload
- s3:GetBucketLocation
- s3:GetObject
- s3:ListBucket
- s3:ListBucketMultipartUploads
- s3:PutObject
Resource:
- !GetAtt DestBucket.Arn
- !Sub ${DestBucket.Arn}/*
- Effect: Allow
Action:
- lambda:InvokeFunction
- lambda:GetFunctionConfiguration
Resource: !GetAtt TransformFunction.Arn
- Effect: Allow
Action: logs:PutLogEvents
Resource: !GetAtt FirehoseLogGroup.Arn
DeliveryStream:
Type: AWS::KinesisFirehose::DeliveryStream
Properties:
DeliveryStreamName: !Sub ${ProjectName}-stream
DeliveryStreamType: DirectPut
ExtendedS3DestinationConfiguration:
BucketARN: !GetAtt DestBucket.Arn
RoleARN: !GetAtt FirehoseRole.Arn
Prefix: transformed/!{timestamp:yyyy/MM/dd/HH}/
ErrorOutputPrefix: errors/!{firehose:error-output-type}/!{timestamp:yyyy/MM/dd/HH}/
BufferingHints:
IntervalInSeconds: 60
SizeInMBs: 1
CompressionFormat: UNCOMPRESSED
CloudWatchLoggingOptions:
Enabled: true
LogGroupName: !Ref FirehoseLogGroup
LogStreamName: !Ref FirehoseLogStream
ProcessingConfiguration:
Enabled: true
Processors:
- Type: Lambda
Parameters:
- ParameterName: LambdaArn
ParameterValue: !GetAtt TransformFunction.Arn
- ParameterName: NumberOfRetries
ParameterValue: !Ref LambdaRetries
- ParameterName: BufferSizeInMBs
ParameterValue: "1"
- ParameterName: BufferIntervalInSeconds
ParameterValue: "60"
S3BackupMode: !Ref BackupMode
S3BackupConfiguration: !If
- BackupEnabled
- BucketARN: !GetAtt DestBucket.Arn
RoleARN: !GetAtt FirehoseRole.Arn
Prefix: source/!{timestamp:yyyy/MM/dd/HH}/
ErrorOutputPrefix: backup-errors/!{firehose:error-output-type}/!{timestamp:yyyy/MM/dd/HH}/
BufferingHints:
IntervalInSeconds: 60
SizeInMBs: 1
CompressionFormat: UNCOMPRESSED
- !Ref AWS::NoValue
Outputs:
DeliveryStreamName:
Value: !Ref DeliveryStream
BucketName:
Value: !Ref DestBucket
FunctionName:
Value: !Ref TransformFunction
FirehoseLogGroupName:
Value: !Ref FirehoseLogGroup
重要な部分の解説
1. Lambdaの戻り値は、recordId・result・data の3つ
def result(record_id, status, data):
return {"recordId": record_id, "result": status, "data": data}
result は Ok/Dropped/ProcessingFailed の3種類です。recordId は、入力と同じ値を返す必要があります。正常なレコードの末尾に改行(\n)を付けているのは、Firehoseがレコードをそのままつなげて書くためです(付けないと、S3上で1行にくっついてしまいます)。
2. 失敗の出力先は ErrorOutputPrefix で決まる
ErrorOutputPrefix: errors/!{firehose:error-output-type}/!{timestamp:yyyy/MM/dd/HH}/
!{firehose:error-output-type} の部分に、失敗の種類(今回は processing-failed)が入ります。ErrorOutputPrefix に式を書くときは、これを1つ以上含める必要があります。また、バックアップ(S3BackupConfiguration)を指定すると、ErrorOutputPrefix の既定値は用意されないので、自分で書きます。
3. リトライとバッファは、Lambdaプロセッサのパラメータで指定する
- ParameterName: NumberOfRetries
ParameterValue: !Ref LambdaRetries
- ParameterName: BufferSizeInMBs
ParameterValue: "1"
- ParameterName: BufferIntervalInSeconds
ParameterValue: "60"
NumberOfRetries は、Lambdaの呼び出し自体が失敗したときのリトライ回数です(既定は3)。
やってみた
1. デプロイ
CloudFormationのコンソールからテンプレートをアップロードして、スタックを作成します。
デプロイ完了するまでは夕飯何にするか考えましょう。🍚

無事に完了しました!
念の為Firehoseの設定値を確認します。


想定通り作成できています!
2. CloudShellの準備
コンソールの右上で東京リージョンを確認し、CloudShell(>_)を開きます。次の「共通設定」を貼り付けます(BUCKET はスタックの出力タブの値)。
STREAM=fh-lab-stream
BUCKET=fh-lab-<アカウントID>-ap-northeast-1
aws configure set cli_binary_format raw-in-base64-out
# S3の中身を、ファイルごとに全部表示する小さなコマンド
show() {
for k in $(aws s3 ls s3://$BUCKET/$1 --recursive | awk '{print $4}'); do
echo "--- $k"
aws s3 cp s3://$BUCKET/$k -
echo
done
}
3. 検証1:正常なレコードだけ送る
3件の正常なレコードを送ります。
cat > records1.json <<'EOF'
[
{"Data": "{\"id\":1,\"user\":\"a\",\"amount\":1000}"},
{"Data": "{\"id\":2,\"user\":\"b\",\"amount\":2500}"},
{"Data": "{\"id\":3,\"user\":\"c\",\"amount\":300}"}
]
EOF
date
aws firehose put-record-batch --delivery-stream-name $STREAM --records file://records1.json
FailedPutCount が 0(3件とも受け付けられた)ことを確認して、1〜2分待ちます。
transformed/ の中身です。
{"id": 1, "user": "a", "amount": 1000, "amount_with_tax": 1100, "processed_at": "2026-11-02T08:06:15.658179+00:00"}
{"id": 2, "user": "b", "amount": 2500, "amount_with_tax": 2750, "processed_at": "2026-11-02T08:06:15.658275+00:00"}
{"id": 3, "user": "c", "amount": 300, "amount_with_tax": 330, "processed_at": "2026-11-02T08:06:15.658297+00:00"}
1行ごとに改行された、JSON Linesの形になっています。税込金額も、計算どおり(1000→1100)です。
一方、source/(変換前のバックアップ)は、改行なしで1行につながっていました。
{"id":1,"user":"a","amount":1000}{"id":2,"user":"b","amount":2500}{"id":3,"user":"c","amount":300}
errors/ には何も出ていません。
届くまでの時間です(UTC)。
| 時刻 | できごと | 送信からの経過 |
|---|---|---|
| 08:05:09 | 送信 | — |
| 08:06:15 | Lambdaが処理 | 約66秒 |
| 08:06:16 | source/ に配信 |
約67秒 |
| 08:06:29 | transformed/ に配信 |
約80秒 |

4. 検証2:成功・破棄・変換失敗・不正なJSONを混ぜる
6件を1バッチで送ります。
cat > records2.json <<'EOF'
[
{"Data": "{\"id\":11,\"user\":\"a\",\"amount\":1000}"},
{"Data": "{\"id\":12,\"user\":\"b\",\"amount\":2000}"},
{"Data": "{\"id\":13,\"user\":\"c\",\"amount\":3000}"},
{"Data": "{\"id\":14,\"action\":\"drop\"}"},
{"Data": "{\"id\":15,\"action\":\"fail\"}"},
{"Data": "this is not json"}
]
EOF
date
aws firehose put-record-batch --delivery-stream-name $STREAM --records file://records2.json
transformed/ には、正常な3件(id 11〜13)だけが届きました。drop と fail、不正なJSONは出ていません。
errors/processing-failed/ には、2件が入っていました。
{"rawData":"eyJpZCI6MTUsImFjdGlvbiI6ImZhaWwifQ==","errorCode":"Lambda.ProcessingFailedStatus","errorMessage":"ProcessingFailed status set for record","attemptsMade":1,"arrivalTimestamp":1793606974810,"attemptEndingTimestamp":1793607035036,"lambdaARN":"arn:aws:lambda:ap-northeast-1:<アカウントID>:function:fh-lab-transform"}
{"rawData":"dGhpcyBpcyBub3QganNvbg==","errorCode":"Lambda.ProcessingFailedStatus","errorMessage":"ProcessingFailed status set for record","attemptsMade":1,"arrivalTimestamp":1793606974810,"attemptEndingTimestamp":1793607035036,"lambdaARN":"arn:aws:lambda:ap-northeast-1:<アカウントID>:function:fh-lab-transform"}
| 項目 | 内容 |
|---|---|
rawData |
元のデータをBase64にしたもの。デコードすると、{"id":15,"action":"fail"} と this is not json(送ったもの)になる |
errorCode |
Lambda.ProcessingFailedStatus |
errorMessage |
ProcessingFailed status set for record |
attemptsMade |
1 |
arrivalTimestamp/attemptEndingTimestamp |
Firehoseへの到着時刻と、処理を終えた時刻(ミリ秒)。差は約60秒で、Lambdaのバッファ時間と合う |
fail を返したレコードも、不正なJSONも、errorCode は同じ値でした。失敗の原因までは、このファイルからは区別できません。
そして気になっていた、Dropped(id 14)の行き先です。transformed/ にも errors/ にも出ませんでしたが、source/ には残っていました。バックアップを有効にしていると、Dropped を含めた全6件のソースが保存されます。
{"id":11,"user":"a","amount":1000}{"id":12,"user":"b","amount":2000}{"id":13,"user":"c","amount":3000}{"id":14,"action":"drop"}{"id":15,"action":"fail"}this is not json
Lambdaのログにも、件数が出ていました。
{"received": 3, "Ok": 3, "Dropped": 0, "ProcessingFailed": 0}
{"received": 6, "Ok": 3, "Dropped": 1, "ProcessingFailed": 2}
届くまでの時間です(UTC)。
| 時刻 | できごと | 送信からの経過 |
|---|---|---|
| 08:09:32 | 送信 | — |
| 08:10:35 | Lambdaが処理 | 約63秒 |
| 08:10:40 | source/ に配信 |
約68秒 |
| 08:10:48 | errors/ に配信 |
約76秒 |
| 08:11:38 | transformed/ に配信 |
約126秒 |
検証1は約80秒で届いたのに、今回は約126秒かかりました。
下のS3の画像は、ファイルの更新日時が**日本時間(JST、UTC+9)**で表示されています(上の表のUTCに9時間を足した時刻です。たとえば 08:10:48 UTC は 17:10:48 JST)。

5. 検証3:Lambdaが例外で落ちる
id 22 だけ例外を出すレコードを、正常な2件と同じバッチで送ります。
cat > records3.json <<'EOF'
[
{"Data": "{\"id\":21,\"user\":\"a\",\"amount\":1000}"},
{"Data": "{\"id\":22,\"action\":\"raise\"}"},
{"Data": "{\"id\":23,\"user\":\"c\",\"amount\":3000}"}
]
EOF
date
aws firehose put-record-batch --delivery-stream-name $STREAM --records file://records3.json
結果は、3件すべてが errors/processing-failed/ に入りました。例外を出したのは id 22 だけなのに、正常な id 21 と 23 も巻き込まれて、transformed/ には出ませんでした。
{"rawData":"eyJpZCI6MjEsInVzZXIiOiJhIiwiYW1vdW50IjoxMDAwfQ==","errorCode":"Lambda.FunctionError","errorMessage":"The Lambda function was successfully invoked but it returned an error result.","attemptsMade":4,"arrivalTimestamp":1793607247630,"attemptEndingTimestamp":1793607322696,"lambdaARN":"arn:aws:lambda:ap-northeast-1:<アカウントID>:function:fh-lab-transform"}
errorCodeは、ProcessingFailedのときと違うLambda.FunctionErrorattemptsMadeは 4(初回+リトライ3回)errorMessageにLambdaの例外の内容は入っていない(内容はLambdaのログで見る)
Lambdaの呼び出し回数は、CloudWatch Logsの START RequestId を数えて確認しました。
08:15:07 初回
08:15:09 リトライ1(約2秒後)
08:15:14 リトライ2(約5秒後)
08:15:22 リトライ3(約8秒後)
呼び出しの間隔は、だんだん長くなっていました。最後の呼び出し(08:15:22)は、失敗ファイルの attemptEndingTimestamp(08:15:22.696)と一致しています。

例外の内容は、ログにこのように出ていました。
[ERROR] RuntimeError: intentional failure for lab
Traceback (most recent call last):
File "/var/task/index.py", line 33, in handler
raise RuntimeError("intentional failure for lab")

届くまでの時間です(UTC)。
| 時刻 | できごと | 送信からの経過 |
|---|---|---|
| 08:14:05 | 送信 | — |
| 08:15:07 | Lambda 初回呼び出し | 約62秒 |
| 08:15:22 | 最終試行が終了 | 約77秒 |
| 08:16:24 | errors/ に配信 |
約139秒 |
6. 後片付け
CloudShellでバケットを空にしてから、スタックを削除しました。
aws s3 rm s3://$BUCKET/ --recursive
結果のまとめ
| 検証 | 送ったもの | transformed/ |
errors/ |
source/ |
配信までの時間 |
|---|---|---|---|---|---|
| 1 | 正常3 | 3行 | なし | 3件(連結) | 約80秒 |
| 2 | 正常3、drop 1、fail 1、不正JSON 1 | 正常3行のみ | 2件(Lambda.ProcessingFailedStatus) |
6件(drop含む) | 約126秒 |
| 3 | 正常2、例外1(同一バッチ) | なし | 3件すべて(Lambda.FunctionError、4回試行) |
3件 | 約139秒 |
注意点
- 各検証は1回ずつの実測です。届くまでの時間は、バッファの設定や、そのときの状況で変わります(検証1と2で、約80秒と約126秒の差が出ました)。
- バックアップ(
S3BackupMode)を無効にした場合の挙動は、今回は検証していません(有効のときの結果から、Droppedのデータが残るのはバックアップのおかげだと考えられます)。 - 今回は1つのバッチに失敗を混ぜました。バッチの分け方や大きさで、巻き込まれる範囲は変わります。
errors/とsource/には、元のデータがそのまま残ります(rawDataはBase64なので、デコードすれば読めます)。個人情報などを流す場合は、これらの置き場所の権限や保存期間に注意が必要です。- 検証用の構成です。本番では、失敗したレコードを再処理する仕組みや、アラームなども考えてください。
まとめ
- Lambda変換で返した結果ごとに、S3での行き先を実測しました。
Okはtransformed/へ、ProcessingFailedはerrors/processing-failed/へ、Droppedはどこにも配信されません。ただし、バックアップを有効にしていると、Droppedを含む全ソースがsource/に残りました。- 失敗ファイルには、元のデータが Base64(
rawData) で残るので、あとから中身を確認して再処理する材料になります。 - Lambdaが例外で落ちると、同じバッチの正常なレコードも巻き込まれて、すべて
errors/に入りました。Lambdaは、初回+リトライ3回の4回呼ばれました。 - なので、Lambdaの処理は、個々のレコードで
try/exceptして、失敗をProcessingFailedとして返す形にしておくのが良さそうです。そうすれば、1件の不具合で、同じバッチの正常なレコードまで失われる事態を避けられます。 - 配信には、Lambdaのバッファ(60秒)とS3のバッファ(60秒)が効いて、約80秒〜約2分20秒かかりました。リアルタイム性が必要なときは、バッファの設定を見直す必要があります。
この記事が、FirehoseのLambda変換で、失敗レコードの扱いを設計するときの参考になれば幸いです!
最後に
本日の写真はこちら!(ででん)

こちらは、ミニチュアアートを手がけられている田中達也さんの、ミニチュア展(横浜)に行った時の写真です!
これは緑のスプーンを木に見立てて、森の中を散策する狩人の作品ですかね。
発想力が豊かで、驚かされるような作品にたくさん出会えました。機会があれば是非足を運んでみてください!
最後まで見てくださりありがとうございました〜









