集成函数计算异步调用

Serverless 工作流的任务步骤中,异步调用函数计算可以更灵活地适应一些任务场景,例如长时任务、人工审核等,帮助您避免限流等错误,同时可以简化流程中的错误处理和重试逻辑。本文介绍Serverless 工作流集成函数异步调用的背景信息、集成模式和使用示例等。

前提条件

您已完成以下操作:

  • 可选:开启异步调用

    当您的函数开启了有状态异步调用时,您还可以在任务执行过程中停止函数实例,并获得对整个执行流程更细粒度的可观测性。

  • 授予函数计算访问Serverless 工作流的权限,确保当函数异步执行完成后可以正常回调Serverless 工作流继续执行后续流程。权限策略如下所示:

    {
        "Statement": [
            {
                "Effect": "Allow",
                "Action": [
                    "fnf:ReportTaskSucceeded",
                    "fnf:ReportTaskFailed"
                ],
                "Resource": [
                    "*"
                ]
            }
        ],
        "Version": "1"
    }

    关于授权的详细信息,请参见授予函数计算访问其他云服务的权限

背景信息

默认情况下,Serverless 工作流编排函数计算任务是采用同步调用实现的任务流程,即Serverless 工作流调用函数计算时会等待函数执行完成后同步获得返回的输出,才可以进入到下一个调用的任务。流程定义如下:

version: v1
type: flow
steps:
  - type: task
    name: mytask
    resourceArn: acs:fc:{region}:{account}:services/{serviceName}.{qualifier}/functions/{functionName}

默认情况下,采用同步调用函数计算时可能会存在以下问题:

  • 由于函数计算存在资源调用限制,即函数计算的阿里云账号(主账号)在单个地域内默认的按量实例上限数为300。

    当您使用Serverless 工作流调用函数时,也存在一些其他的函数调用,这些调用会共享相同的配额,因此可能会造成限流等报错。从而您需要在Serverless 工作流的流程中定义较复杂的重试策略,但也无法保证流程是否会执行成功。

  • 当部分任务的执行时间较长,采用同步调用时,Serverless 工作流会与函数计算建立长链接,由于网络波动可能会导致一些非预期错误。

Serverless 工作流支持函数计算的异步调用与集成模式的结合,帮助您解决以上问题,同时也可以满足以下需求:

  • 在某些场景下,无需等待任务执行完成后再执行后续步骤。

  • 在流程执行的过程中,如果遇到非预期错误,可以忽略该步骤的函数调用,直接执行后续操作。

适用场景

任务步骤对函数计算异步调用功能的集成有请求响应(requestResponse)模式、同步(sync)模式和回调(waitForCallback)模式,分别适用于不同场景。

集成模式

模式(pattern)参数

适用场景

请求响应模式(默认模式)

requestResponse

流程示例如下:

- type: task
    ...
    pattern: requestResponse 
    serviceParams:
        InvocationType: Async

长时间执行的任务、无需了解任务执行结果。

同步模式

sync

流程示例如下:

- type: task
    ...
    pattern: sync 
    serviceParams:
        InvocationType: Async

长时间执行的任务、可能被限流的任务。

回调模式

waitForCallback

流程示例如下:

- type: task
    ...
    pattern: waitForCallback
    serviceParams:
        InvocationType: Async

任务在执行到某些情况下,可以继续后续的步骤,例如人工审核。

任务服务参数

下文示例中,Serverless 工作流使用函数计算作为任务节点,通过resourceArn指定目标服务为函数计算,并通过serviceParams字段指定调用函数计算的特殊参数。serviceParams支持以下参数信息:

  • InvocationType:表示函数计算中函数的调用方式。取值为Sync(同步调用)或Async(异步调用)。

  • 可选:StatefulAsyncInvocationID:表示有状态异步执行的ID。该参数可以帮助您在函数计算控制台内搜索目标任务的名称。

    说明

    当您的参数InvocationType设置为Async时,表示Serverless 工作流中调用的函数的异步调用类型为有状态。该ID需在函数范围内唯一。

异步调用函数的集成模式

请求响应模式

当流程执行到该步骤时,会异步调用函数,然后开始函数的执行,同时流程会直接进入后续步骤的执行,不会等待回调或任务执行完成。

version: v1
type: flow
steps:
  - type: task
    name: mytask
    resourceArn: acs:fc:{region}:{account}:services/{serviceName}.{qualifier}/functions/{functionName}
    pattern: requestResponse  # Async invocation with sync pattern
    serviceParams:
        InvocationType: Async

该示例展示了当mytask步骤执行时会触发函数执行的流程。触发成功后,将进入下一步骤,函数执行流程可能仍然正在执行。

同步模式

当流程执行到该步骤时,会异步调用函数,然后开始函数的执行,然后流程会进入等待状态。当函数执行完成后,Serverless 工作流的流程会获得通知然后开始下一步骤的执行。

version: v1
type: flow
steps:
  - type: task
    name: mytask
    resourceArn: acs:fc:{region}:{account}:services/{serviceName}.{qualifier}/functions/{functionName}
    pattern: sync  # Async invocation with sync pattern
    serviceParams:
        InvocationType: Async

该示例展示了当该步骤执行时会触发一个Serverless 工作流流程。触发成功后将等待该流程的执行结果,执行完成后将进入下一步骤。当mytask步骤执行时会触发函数执行的流程。触发成功后,将等待该流程的执行结果,执行完成后才进入下一步骤。

说明

同步集成模式的整体行为与同步调用函数行为无差异,仅在调用函数时函数的调用方式中有区别。

等待回调模式

当流程执行到该步骤时,会异步调用函数,然后开始函数的执行并传入任务令牌,之后流程会进入等待状态。无论函数执行是否完成,直到您手动通过任务令牌通知流程执行结果后才会继续执行下一个步骤。

version: v1
type: flow
steps:
  - type: task
    name: mytask
    resourceArn: acs:fc:{region}:{account}:services/{serviceName}.{qualifier}/functions/{functionName}
    pattern: waitForCallback  # Async invocation with sync pattern
    serviceParams:
        InvocationType: Async

该示例展示了当mytask步骤执行时会触发函数执行的流程。触发成功后,将暂停流程执行,等待回调(通过ReportTaskSucceedReportTaskFailed)。在收到回调请求并处理完成后,流程将进入下一步骤。回调由您发起,此时函数执行流程可能已经执行完成,也可能还在执行。

推荐使用示例

Serverless 工作流异步调用函数计算功能配合有状态的异步调用可以最大限度的支持任务类场景。当您开启有状态异步调用功能并且采用异步调用的方式时,可以在调用过程及结束后查看函数执行情况,具有更强的任务执行可观测能力;也可以操作停止函数执行,使流程具有更强的操作能力。Serverless 工作流的流程定义语言如下所示:

version: v1
type: flow
steps:
  - type: task
    name: mytask
    resourceArn: acs:fc:::services/{serviceName}.{qualifier}/functions/{functionName}
    pattern: sync  # Async invocation with sync pattern
    inputMappings:
      - target: id
        source: $context.execution.name
    serviceParams:
        InvocationType: Async
        StatefulAsyncInvocationID: $.id