在AWS Lambda中使用threading.Thread执行DynamoDB删除操作失效问题
问题描述
环境
- Python: 3.9.12
- botocore: 1.29.136
- 运行环境:AWS Lambda
- 部署方式:Serverless Framework
我有个耗时较长的删除任务,想实现:接收客户端请求后立刻返回成功码,再用后台线程完成任务。但线程方式执行时,没有任何异常提示却完全失效——调用delete_devices函数后就卡住了;改成单线程直接执行则一切正常。
失效代码示例
def delete_all_data(self, request_data): # 部分代码... # 通过查询获取devices_to_delete thread = threading.Thread(target=self.delete_all, args=(request_data['key1'], devices_to_delete,)) # 部分代码... thread.start() return SUCCESS def delete_all(self, owner, devices): # 部分代码... self.delete_devices(devices) # 部分代码... def delete_devices(self, devices): # _device为通过boto3.resource('dynamodb').Table('device_tbl')获取的DynamoDB表对象 try: for item in devices: self._device.delete_item(Key={'device_key': item['device_key']}) # 部分代码...
正常工作代码示例
def delete_all_data(self, request_data): # 部分代码... # 通过查询获取devices_to_delete self.delete_devices(devices_to_delete) # 部分代码... return SUCCESS def delete_devices(self, devices): try: for item in devices: self._device.delete_item(Key={'device_key': item['device_key']}) # 部分代码...
问题原因与解决办法
核心原因
AWS Lambda的执行容器是请求驱动的短生命周期模型:只要主执行线程返回了响应,AWS就会立刻开始回收容器资源,直接终止所有后台线程,不会等后台任务跑完。这就是为什么你启动线程后直接返回,线程里的任务根本没机会执行,甚至刚启动就被掐断了。
另外,boto3的客户端/资源对象和主线程的事件循环绑定,后台线程用这些对象时容易出现资源竞争或上下文丢失,导致请求卡住没响应。
正确实现方案
别用Python线程处理Lambda的后台任务,推荐这两种靠谱的方式:
用AWS SQS解耦异步任务
- 收到请求后,把任务关键数据(比如
devices_to_delete里的device_key列表)发送到SQS队列 - 立刻返回成功响应给客户端
- 单独写一个Lambda函数监听这个SQS队列,收到消息后执行删除设备的耗时操作
- 收到请求后,把任务关键数据(比如
用Lambda异步调用触发任务
- 主线程里调用
boto3.client('lambda').invoke(),设置InvocationType='Event',异步触发专门处理删除任务的Lambda - 主线程直接返回成功,异步Lambda负责执行耗时操作
- 主线程里调用
临时测试修复(不推荐生产用)
如果非要在当前Lambda里用线程,必须让主线程等后台线程跑完再返回,但这样就失去了“立即响应”的意义:
def delete_all_data(self, request_data): # 部分代码... thread = threading.Thread(target=self.delete_all, args=(request_data['key1'], devices_to_delete,)) thread.start() thread.join() # 强制等待线程执行完成 return SUCCESS
内容的提问来源于stack exchange,提问作者Jason
相关产品推荐
相关产品推荐

