如何在AWS Step Functions中向SQS关联Lambda传递输入与回调Token?
我有一个关联Lambda函数的SQS FIFO队列,该SQS被AWS Step Functions包裹,通过回调完成执行,状态机模板如下:
{ "Comment": "A description of my state machine", "StartAt": "SQS SendMessage", "States": { "SQS SendMessage": { "Type": "Task", "Resource": "arn:aws:states:::sqs:sendMessage.waitForTaskToken", "Parameters": { "MessageBody": { "input.$": "$", "token.$": "$$.Task.Token" }, "QueueUrl": "https://sqs.eu-west-1.amazonaws.com/xxxx/myqueue.fifo", "MessageGroupId": "mygroupid" }, "End": true } } }
调用Step Functions时传入输入值"{\"foo\": \"bar\"}",Step Functions成功发送消息到SQS,但Lambda收到的响应中消息体为空:
{ "Records": [ { "messageId": "f24bdd16-4234b-47534-a67a-f12234234356", "receiptHandle": "some random string", "body": null, // 问题所在 "attributes": { "ApproximateReceiveCount": "1", "SentTimestamp": "1667313159855", "SequenceNumber": "49120530206362825178", "MessageGroupId": "mygroupid", "SenderId": "47X80CVTPC853VD6U5WSN:B9iwHdV1PkL1EbIDduFevS6KZ3YTrO0k", "MessageDeduplicationId": "njijzrghtu1hgatdkwjub3j08i2fzuqs0wj5q7kl9mlxfkrad3xz35mt43kyq602", "ApproximateFirstReceiveTimestamp": "1667313159855" }, "messageAttributes": {}, "md5OfBody": "kvzz7dtgoxv6kivo66260e3yn95igltj", "eventSource": "aws:sqs", "eventSourceARN": "arn:aws:sqs:eu-west-1:xxxxx:myqueue.fifo", "awsRegion": "eu-west-1" } ] }
期望在Lambda中获取输入值和回调Token,认为MessageBody应为string类型而非object,并将Token附加到MessageBody中,预期结果如下:
"body": "{\"foo\": \"bar\",\"token\": \"callbacktoken\"}"
或
"body": {"payload": {"foo": "bar"}, "token": "callbacktoken"}
尝试过以下写法但无效:
"MessageBody.$":"States.JsonToString('{\"input.$\": \"$\", \"token.$\": \"$$.Task.Token\"}', $")"
请问我的思路是否正确?正确的实现方式是什么?
你的思路方向是对的——SQS要求MessageBody必须是字符串类型,直接传入JSON对象会导致解析异常,最终Lambda收到的body为null。
正确实现方式
需要使用Step Functions的States.JsonToString函数,构造包含输入和Token的JSON结构后转换为字符串:
方式1:合并输入与Token为JSON字符串
修改状态机的MessageBody参数如下:
"MessageBody.$": "States.JsonToString({\"input\": $, \"token\": $$.Task.Token})"
此写法会将Step Functions的输入对象和Task Token合并为一个JSON对象,再转换为字符串发送到SQS。Lambda收到后,body字段会是类似"{\"input\":{\"foo\":\"bar\"},\"token\":\"callback-token-value\"}"的字符串,可直接在Lambda中解析为JSON对象使用。
方式2:自定义带payload的结构
如果需要更清晰的层级结构,可使用以下写法:
"MessageBody.$": "States.JsonToString({\"payload\": $, \"token\": $$.Task.Token})"
Lambda收到的body会是"{\"payload\":{\"foo\":\"bar\"},\"token\":\"callback-token-value\"}",完全匹配你预期的格式。
为什么之前的写法无效?
你之前的错误在于,在States.JsonToString的参数中错误使用了input.$这类路径引用语法——States.JsonToString的参数是直接构造JSON结构,变量引用只需写$或$$.Task.Token即可,. $后缀仅在Parameters的键值对中用来指定路径,不能嵌套在States.JsonToString的参数里。
内容的提问来源于stack exchange,提问作者Ramesh Murugesan

