使用 JSON 事件运行 Lambda 函数

AWSBeginner
立即练习

介绍

结账团队需要一个计算订单总额的函数。你将部署一个简短的 Python 处理程序,发送两份 JSON 输入,再更新计算逻辑以加入处理费。使用整数分保持算术简单,最后删除你的函数和日志。

请先完成 在 LabEx 上开始学习 AWS、通过 IAM 角色使用临时凭证 和 在 CloudWatch Logs 中查找失败请求。这个全新环境提供 CLI、工作目录和执行角色。

部署订单计算逻辑

本步骤中,你将替换未完成的处理程序,并部署函数。调用函数时,AWS Lambda 会运行你的代码。事件(event) 是为该次调用提供的输入;处理程序(handler) 是 Lambda 使用这个输入调用的 Python 函数。设置 app.handler 表示 app.py 中名为 handler 的函数。

进入准备好的工作目录并检查代码框架。它目前返回空对象,因此无法计算订单。

cd /home/labex/project
cat app.py

Python 使用缩进将语句归入函数。event["quantity"] 从传入的 JSON 对象读取值。* 将数量乘以单价;return 将计算出的对象发送给调用方。context 提供调用信息,不过这次计算暂时不需要它。

使用这个完整的处理程序替换代码框架。cat > app.py 将 <<'PY' 与结束的 PY 之间的行写入文件。结束行必须单独占一行。

cat > app.py <<'PY'
import json

def handler(event, context):
    order_id = event["order_id"]
    quantity = event["quantity"]
    unit_price = event["unit_price_cents"]
    total = quantity * unit_price
    print("EVENT " + json.dumps(event))
    return {"order_id": order_id, "total_cents": total}
PY

print 语句将输入写入执行日志,不会返回响应。不要在日志中记录客户秘密。这些事件仅包含合成的标识符和数字。

创建 Zip 包,也就是 Lambda 部署的归档文件。将 app.py 放在顶层,以便找到处理程序。执行角色 是 Lambda 运行代码时使用的身份。准备好的角色支持日志记录;后续实验中你将配置数据访问。将它的 ARN 读入 shell 变量。ARN 标识特定资源;使用变量可以避免手动复制。

zip -q function.zip app.py
ROLE_ARN=$(aws iam get-role --role-name labex-fn01-execution --query 'Role.Arn' --output text)

使用 Python 3.12 运行时和五秒超时进行部署。fileb:// 按字节读取归档文件。运行时决定语言环境;超时限制一次调用的运行时间。

aws lambda create-function --function-name labex-fn01-quote --runtime python3.12 --handler app.handler --role "$ROLE_ARN" --zip-file fileb://function.zip --timeout 5 --query '{Name:FunctionName,Runtime:Runtime,Handler:Handler,Timeout:Timeout,CodeSize:CodeSize}'

预期看到 Name labex-fn01-quote、Runtime python3.12、Handler app.handler、Timeout 5,以及正数的 CodeSize。创建函数会部署代码,但不会调用处理程序。

AWS View 显示函数、处理程序和代码指纹。调用日志仍为空。参考日志组是无关的平台数据,必须保持不变。

调用两个 JSON 事件

本步骤中,你将使用两个不同订单调用已部署的函数,并理解响应。JSON 表示具有具名字段的对象。数字不带引号,字符串带引号。每次调用收到自己的事件。

部署存储代码包;调用提供事件并运行处理程序。

编写第一个事件:两件商品,每件 375 分。

cat > small.json <<'JSON'
{"order_id":"fn01-small","quantity":2,"unit_price_cents":375}
JSON

调用函数并保存响应。--cli-binary-format raw-in-base64-out 让 CLI 接受普通 JSON 作为载荷。file:// 读取事件文本;最后的文件名用于接收返回的载荷。

aws lambda invoke --function-name labex-fn01-quote --cli-binary-format raw-in-base64-out --payload file://small.json small-response.json
cat small-response.json

命令报告 StatusCode 200。响应文件应包含 {"order_id":"fn01-small","total_cents":750}。服务请求状态与处理程序返回的数据是不同的证据;也要检查载荷。

不重新部署代码,发送第二个订单。五件商品,每件 120 分,应得到不同的总额。

cat > large.json <<'JSON'
{"order_id":"fn01-large","quantity":5,"unit_price_cents":120}
JSON
aws lambda invoke --function-name labex-fn01-quote --cli-binary-format raw-in-base64-out --payload file://large.json large-response.json
cat large-response.json

预期得到 {"order_id":"fn01-large","total_cents":600}。输入值驱动了同一个函数的计算。

在 AWS View 中比较订单 ID、数量、价格和总额。调用记录发生变化时,函数配置保持不变。为任意一个订单打开 Show logs,查看它的输入和返回结果。

更新代码并追踪结果

本步骤中,你将加入 100 分的处理费,并确认新调用运行了更新后的计算逻辑。编辑本地 app.py 不会改变已部署代码;需要更新代码包并发送到 Lambda。

使用这个修订版本替换处理程序。仅计算逻辑发生变化:+ 100 在乘法之后加入处理费。

cat > app.py <<'PY'
import json

def handler(event, context):
    order_id = event["order_id"]
    quantity = event["quantity"]
    unit_price = event["unit_price_cents"]
    total = quantity * unit_price + 100
    print("EVENT " + json.dumps(event))
    return {"order_id": order_id, "total_cents": total}
PY
zip -q function.zip app.py
aws lambda update-function-code --function-name labex-fn01-quote --zip-file fileb://function.zip --query '{Name:FunctionName,CodeSHA:CodeSha256}'

部署返回名称和代码 SHA 指纹。AWS View 显示已变化的指纹;较早调用的结果仍保留在日志中。

作为 Console 对照,官方示例将 Python 文件与 Deploy 和 Test 控件并列显示。其中的 lambda_function.py 和 lambda_handler 对应本实验的 app.py 和 handler;这里继续使用 Terminal 工作流程。

官方 Lambda Console 示例,显示 Python 文件与部署控件。

来源:AWS Lambda 指南。

使用第一个订单的数量和价格,并提供新的关联 ID。

cat > revised.json <<'JSON'
{"order_id":"fn01-revised","quantity":2,"unit_price_cents":375}
JSON
aws lambda invoke --function-name labex-fn01-quote --cli-binary-format raw-in-base64-out --payload file://revised.json revised-response.json
cat revised-response.json

预期得到 {"order_id":"fn01-revised","total_cents":850}:商品总额 750 分,加上 100 分处理费。第一次响应仍为 750;更新代码不会改写历史。

执行日志存储在 /aws/lambda/<function-name> 中。读取包含这个订单 ID 的消息,将它的事件与计算响应关联起来。

aws logs filter-log-events --log-group-name /aws/lambda/labex-fn01-quote --filter-pattern '"fn01-revised"' --query 'events[].message'

预期看到 EVENT 输入,以及总额为 850 的返回对象。完整日志流还包含调用开始、结束和运行时报告,它们与订单响应相互独立。

返回 AWS View。比较三条实际记录,为 fn01-revised 打开 Show logs,并将输入与 850 分的结果对应起来。参考日志保持不变。

已部署的修订版本返回 850 分,而此前计算的总额和参考日志保持不变。

删除函数并保留参考日志

本步骤中,你将仅删除函数和它的执行日志组,再确认无关的参考日志仍然存在。函数与日志组是独立资源;仅删除函数不会移除存储的日志。

删除指定的函数,再成功读取清单。

aws lambda delete-function --function-name labex-fn01-quote
aws lambda list-functions --query 'Functions[].FunctionName'

预期得到空列表。身份验证或连接错误不能证明删除完成。

移除本实验的执行日志,并列出剩余日志组。

aws logs delete-log-group --log-group-name /aws/lambda/labex-fn01-quote
aws logs describe-log-groups --query 'logGroups[].logGroupName'

应只剩下 /labex/labex-fn01-reference。读取它的消息,证明清理保留了无关数据。

aws logs get-log-events --log-group-name /labex/labex-fn01-reference --log-stream-name platform --query 'events[].message'

预期看到 INFO platform reference keep unchanged。AWS View 不再显示已部署函数或调用日志,参考日志仍然存在。准备好的角色和身份是环境配套资源;凭证撤销和关闭环境在资源检查之后执行。

总结

你编写了 Python 处理程序,部署了 Zip 包,并根据两个 JSON 事件计算总额。你更新了已部署的计算逻辑,将新结果与执行日志关联,并在保留参考数据的同时,仅删除函数及其日志组。