Aws lambda AWS Step功能-等待事件发生
我有一个用例,其中我有一个AWS Step函数,当文件上传到S3时会触发该函数,从那里开始,第一步运行ffprobe,从外部服务(如transloadit)获取文件的持续时间,其中输出被写回S3 我可以从该事件创建一个新的step函数,但考虑到ffprobe可能需要更长的时间才能恢复,我想知道是否有可能在原始step函数中有一个等待承诺,然后继续下一步Aws lambda AWS Step功能-等待事件发生,aws-lambda,aws-step-functions,Aws Lambda,Aws Step Functions,我有一个用例,其中我有一个AWS Step函数,当文件上传到S3时会触发该函数,从那里开始,第一步运行ffprobe,从外部服务(如transloadit)获取文件的持续时间,其中输出被写回S3 我可以从该事件创建一个新的step函数,但考虑到ffprobe可能需要更长的时间才能恢复,我想知道是否有可能在原始step函数中有一个等待承诺,然后继续下一步 对于如何解决这一问题,我们非常感谢您的任何建议。无法提出简单的解决方案,只有很少的方向需要探索 首先,Step函数有一种处理长时间运行的后台工作
对于如何解决这一问题,我们非常感谢您的任何建议。无法提出简单的解决方案,只有很少的方向需要探索 首先,Step函数有一种处理长时间运行的后台工作的特定方法:活动。它基本上是一个队列 如果您想要100%无服务器,这将是复杂或丑陋的
- 或者,如您所说,为每个文件创建新的步骤函数
- 或者,使用自定义错误代码和
子句在状态机中执行S3轮询循环Retry
视频持续时间
。
为即时反应定义SQS队列或为持续时间结果轮询S3
状态函数伪码:
{
StartAt: ffprobe
ffprobe: {
Type: Task
Resource: arn:...lambda:launch-ffprobe
Next: wait-duration
}
wait-duration: {
Type: Task
Resource: arn...activity:video-duration
End: true
}
}
statemap = dict/map filename to result
thread1:
loop:
taskToken, input = SF.GetActivityTask('video-duration') # long poll
sync(key=input.filename, waiter=taskToken)
thread2:
loop:
msg = SQS.ReceiveMessage(...) # or poll S3
sync(key=msg.filename, duration=msg.result)
function sync(key, waiter, duration):
state = statemap[key]
if waiter:
state.waiter = waiter
if duration:
state.duration = duration
if state.waiter and state.duration:
SF.SendTaskSuccess(state.waiter, state.duration)
if filename is video:
SF.StartExecution(...)
else if filename is duration:
content = S3.GetObject(filename)
SQS.SendMessage(queue, content)
后台工作人员伪代码:
{
StartAt: ffprobe
ffprobe: {
Type: Task
Resource: arn:...lambda:launch-ffprobe
Next: wait-duration
}
wait-duration: {
Type: Task
Resource: arn...activity:video-duration
End: true
}
}
statemap = dict/map filename to result
thread1:
loop:
taskToken, input = SF.GetActivityTask('video-duration') # long poll
sync(key=input.filename, waiter=taskToken)
thread2:
loop:
msg = SQS.ReceiveMessage(...) # or poll S3
sync(key=msg.filename, duration=msg.result)
function sync(key, waiter, duration):
state = statemap[key]
if waiter:
state.waiter = waiter
if duration:
state.duration = duration
if state.waiter and state.duration:
SF.SendTaskSuccess(state.waiter, state.duration)
if filename is video:
SF.StartExecution(...)
else if filename is duration:
content = S3.GetObject(filename)
SQS.SendMessage(queue, content)
S3触发器伪代码:
{
StartAt: ffprobe
ffprobe: {
Type: Task
Resource: arn:...lambda:launch-ffprobe
Next: wait-duration
}
wait-duration: {
Type: Task
Resource: arn...activity:video-duration
End: true
}
}
statemap = dict/map filename to result
thread1:
loop:
taskToken, input = SF.GetActivityTask('video-duration') # long poll
sync(key=input.filename, waiter=taskToken)
thread2:
loop:
msg = SQS.ReceiveMessage(...) # or poll S3
sync(key=msg.filename, duration=msg.result)
function sync(key, waiter, duration):
state = statemap[key]
if waiter:
state.waiter = waiter
if duration:
state.duration = duration
if state.waiter and state.duration:
SF.SendTaskSuccess(state.waiter, state.duration)
if filename is video:
SF.StartExecution(...)
else if filename is duration:
content = S3.GetObject(filename)
SQS.SendMessage(queue, content)
好吧,我会从
您可以使用AWS Lambda函数替换此中的API网关,例如由S3事件触发(文档:)。只需确保您的任务具有适当的超时。当您发送transloadit请求时,请根据上载的文件密钥将步骤的taskToken保存在s3中的可预测密钥处。例如,如果媒体文件位于“s3://my media bucket/foobar/media-001.mp3”,则可以创建一个包含当前步骤的任务标记的JSON文件,并使用相同的密钥将其存储在不同的bucket中,例如“s3://ffprobe tasks/foobar/media-001.mp3.JSON”。在将媒体发送到transloadit的步骤结束时,不要调用该步骤的成功或失败,让它继续运行
然后,当您收到transloadit结果就绪的s3通知时,您可以确定s3键以获取任务令牌('s3://ffprobe tasks/foobar/media-001.mp3'),加载JSON(并从s3中删除它),然后发送该任务的成功消息。step函数将继续执行到下一个状态。当我尝试组合SFN来编排AWS批处理作业时,我也遇到了这个问题。 上面建议的实践是有问题的,因为您应该传递taskToken,所以您需要从状态机内部的lambda轮询队列中的taskToken,并将其传递给S3或其他地方,另一个lambda将提交活动状态 问题是:当您轮询taskToken时,您无法知道它是否属于您的状态机实例。 您可以在同一台sate机器的另一个实例上获取令牌。
就我个人而言,我认为如果AWS能够支持这一功能,那将是一件好事,因为他们很容易做到这一点。您通常希望将异步任务作为一个步骤功能活动来启动。这里的关键字是initiate——换句话说,一旦您的活动有一个挂起的操作,即触发您的异步操作。原因是您需要与挂起活动关联的任务令牌-然后,只要您的“未来”可以以某种方式包含此令牌(例如,您可以将其设置为引用或请求ID),那么您就可以使用or调用“完成”活动,成功或失败 启动任务有两种方法:
import boto3
import time
client = boto3.client('stepfunctions')
activity = "arn:aws:states:us-east-1:123456789012:activity:ManualStep"
def lambda_handler(event, context):
print(event)
# This will block until an activity task becomes available
task = client.get_activity_task(activityArn=activity, workerName="test")
print(task)
# Perform your task here
# In this example we continue on in the same function,
# but the continuation could be a separate event,
# just as long as you can retrieve the task token
time.sleep(60)
response = client.send_task_success(taskToken=task['taskToken'], output=task['input'])
print(response)
return "done"
AWS Step函数现在支持将长时间运行的步骤作为第一类进行异步回调 这与上面@mixja的答案相似,但简化了。工作流中的单个状态可以直接调用Lambda、SNS、SQS或ECS,并等待调用
sendstasksucture
有一个为SQS编写的文档,其中一个step函数发送消息并暂停工作流执行,直到有东西提供回调。Lambda是等价的(假设像transloadit这样的主处理发生在Lambda本身之外)
步骤函数定义如下所示
"Invoke transloadit": {
"Type": "Task",
"Resource": "arn:aws:states:::lambda:invoke.waitForTaskToken",
"Parameters": {
"FunctionName": "InvokeTransloadit",
"Payload": {
"some_other_param": "...",
"token.$": "$$.Task.Token"
}
},
"Next": "NEXT_STATE"
}
然后在你的Lambda中,你会做类似的事情
def lambda_handler(event, context):
token = event['token']
# invoke transloadit via SSM, ECS, passing token along
然后,在主长时间运行的流程中,您将发出一个带有令牌的回调,比如来自shell script/CLI的aws stepfunctions send task success--task token$token,或者类似的API调用