Durable Functions (Azure Functions) 的绑定Bindings for Durable Functions (Azure Functions)

Durable Functions 扩展引入了两个新的触发器绑定,用于控制业务流程协调程序和活动函数的执行。The Durable Functions extension introduces two new trigger bindings that control the execution of orchestrator and activity functions. 它还引入了输出绑定,充当 Durable Functions 运行时的客户端。It also introduces an output binding that acts as a client for the Durable Functions runtime.

业务流程触发器Orchestration trigger

业务流程触发器可用于创作持久业务流程协调程序函数The orchestration trigger enables you to author durable orchestrator functions. 此触发器支持启动新的业务流程协调程序函数实例和恢复“等待”任务的现有业务流程协调程序函数实例。This trigger supports starting new orchestrator function instances and resuming existing orchestrator function instances that are "awaiting" a task.

使用适用于 Azure Functions 的 Visual Studio 工具时,使用 OrchestrationTriggerAttribute .NET 属性配置业务流程触发器。When you use the Visual Studio tools for Azure Functions, the orchestration trigger is configured using the OrchestrationTriggerAttribute .NET attribute.

使用脚本语言(例如 JavaScript 或 C# scripting)编写业务流程协调程序函数时,由 function.json 文件中 bindings 数组的以下 JSON 对象定义业务流程协调程序触发器:When you write orchestrator functions in scripting languages (for example, JavaScript or C# scripting), the orchestration trigger is defined by the following JSON object in the bindings array of the function.json file:

{
    "name": "<Name of input parameter in function signature>",
    "orchestration": "<Optional - name of the orchestration>",
    "type": "orchestrationTrigger",
    "direction": "in"
}
  • orchestration 是客户端想要启动此业务流程协调程序函数的新实例时必须使用的业务流程名称。orchestration is the name of the orchestration that clients must use when they want to start new instances of this orchestrator function. 此属性是可选的。This property is optional. 如果未指定,则使用该函数的名称。If not specified, the name of the function is used.

本质上,此触发器绑定轮询函数应用的默认存储帐户中的一系列队列。Internally this trigger binding polls a series of queues in the default storage account for the function app. 这些队列是扩展的内部实现详细信息,因此未在绑定属性中显式配置这些队列。These queues are internal implementation details of the extension, which is why they are not explicitly configured in the binding properties.

触发器行为Trigger behavior

以下是有关业务流程触发器的一些注意事项:Here are some notes about the orchestration trigger:

  • 单线程 - 单个调度程序线程用于单个主机实例上的所有业务流程协调程序函数执行 。Single-threading - A single dispatcher thread is used for all orchestrator function execution on a single host instance. 为此,必须确保业务流程协调程序函数代码有效,且不执行任何 I/O 操作。For this reason, it is important to ensure that orchestrator function code is efficient and doesn't perform any I/O. 还必须确保此线程不执行任何异步工作,等待特定于 Durable Functions 的任务类型除外。It is also important to ensure that this thread does not do any async work except when awaiting on Durable Functions-specific task types.
  • 有害消息处理 - 业务流程触发器中不支持有害消息。Poison-message handling - There is no poison message support in orchestration triggers.
  • 消息可见性 - 业务流程触发器消息会取消排队并在可配置的持续时间内保持可见 。Message visibility - Orchestration trigger messages are dequeued and kept invisible for a configurable duration. 只要函数应用正常运行,这些消息的可见性就会自动更新。The visibility of these messages is renewed automatically as long as the function app is running and healthy.
  • 返回值 - 返回值序列化为 JSON,并持久保存到 Azure 表存储中的业务流程历史记录表 。Return values - Return values are serialized to JSON and persisted to the orchestration history table in Azure Table storage. 业务流程客户端绑定可以查询这些值,后文会对此进行介绍。These return values can be queried by the orchestration client binding, described later.

警告

业务流程协调程序函数不得使用业务流程触发器绑定之外的任何输入或输出绑定。Orchestrator functions should never use any input or output bindings other than the orchestration trigger binding. 这样做有可能导致 Durable Task 扩展出现问题,因为这些绑定可能不遵从单线程处理和 I/O 规则。Doing so has the potential to cause problems with the Durable Task extension because those bindings may not obey the single-threading and I/O rules. 若要使用其他绑定,请将它们添加到从业务流程协调程序函数调用的活动函数。If you'd like to use other bindings, add them to an Activity function called from your Orchestrator function.

警告

绝不应当将 JavaScript 业务流程协调程序函数声明为 asyncJavaScript orchestrator functions should never be declared async.

触发器用法 (.NET)Trigger usage (.NET)

业务流程触发器绑定同时支持输入和输出。The orchestration trigger binding supports both inputs and outputs. 下面是有关输入和输出处理的一些须知事项:Here are some things to know about input and output handling:

  • 输入 - .NET 业务流程函数仅支持以 DurableOrchestrationContext 作为参数类型。inputs - .NET orchestration functions support only DurableOrchestrationContext as a parameter type. 不支持在函数签名中直接反序列化输入。Deserialization of inputs directly in the function signature is not supported. 代码必须使用 GetInput<T> (.NET) 或 getInput (JavaScript) 方法提取业务流程协调程序函数输入。Code must use the GetInput<T> (.NET) or getInput (JavaScript) method to fetch orchestrator function inputs. 这些输入必须是 JSON 可序列化类型。These inputs must be JSON-serializable types.
  • 输出 - 业务流程触发器支持输出值以及输入 。outputs - Orchestration triggers support output values as well as inputs. 函数的返回值用于分配输出值,且必须是 JSON 可序列化的。The return value of the function is used to assign the output value and must be JSON-serializable. 如果 .NET 函数返回 Taskvoid,则会将 null 值保存为输出。If a .NET function returns Task or void, a null value will be saved as the output.

触发器示例Trigger sample

以下示例代码演示了最简单的“Hello World”业务流程协调程序函数的形式:The following example code shows what the simplest "Hello World" orchestrator function might look like:

C#C#

[FunctionName("HelloWorld")]
public static string Run([OrchestrationTrigger] IDurableOrchestrationContext context)
{
    string name = context.GetInput<string>();
    return $"Hello {name}!";
}

备注

前面的代码适用于 Durable Functions 2.x。The previous code is for Durable Functions 2.x. 对于 Durable Functions 1.x,必须使用 DurableOrchestrationContext 而不是 IDurableOrchestrationContextFor Durable Functions 1.x, you must use DurableOrchestrationContext instead of IDurableOrchestrationContext. 有关版本之间差异的详细信息,请参阅 Durable Functions 版本一文。For more information about the differences between versions, see the Durable Functions Versions article.

JavaScript(仅限 Functions 2.0)JavaScript (Functions 2.0 only)

const df = require("durable-functions");

module.exports = df.orchestrator(function*(context) {
    const name = context.df.getInput();
    return `Hello ${name}!`;
});

备注

JavaScript 中的 context 对象并非表示 DurableOrchestrationContext,而是表示整个函数上下文The context object in JavaScript does not represent the DurableOrchestrationContext, but the function context as a whole. 可以通过 context 对象的 df 属性访问业务流程方法。You can access orchestration methods via the context object's df property.

备注

JavaScript 业务流程协调程序应使用 returnJavaScript orchestrators should use return. durable-functions 库将负责调用 context.done 方法。The durable-functions library takes care of calling the context.done method.

大多数业务流程协调程序函数会调用活动函数,因此下面的“Hello World”示例演示了如何调用活动函数:Most orchestrator functions call activity functions, so here is a "Hello World" example that demonstrates how to call an activity function:

C#C#

[FunctionName("HelloWorld")]
public static async Task<string> Run(
    [OrchestrationTrigger] IDurableOrchestrationContext context)
{
    string name = context.GetInput<string>();
    string result = await context.CallActivityAsync<string>("SayHello", name);
    return result;
}

备注

前面的代码适用于 Durable Functions 2.x。The previous code is for Durable Functions 2.x. 对于 Durable Functions 1.x,必须使用 DurableOrchestrationContext 而不是 IDurableOrchestrationContextFor Durable Functions 1.x, you must use DurableOrchestrationContext instead of IDurableOrchestrationContext. 有关版本之间差异的详细信息,请参阅 Durable Functions 版本一文。For more information about the differences between versions, see the Durable Functions versions article.

JavaScript(仅限 Functions 2.0)JavaScript (Functions 2.0 only)

const df = require("durable-functions");

module.exports = df.orchestrator(function*(context) {
    const name = context.df.getInput();
    const result = yield context.df.callActivity("SayHello", name);
    return result;
});

活动触发器Activity trigger

使用活动触发器可以创作业务流程协调程序函数调用的函数(称为活动函数)。The activity trigger enables you to author functions that are called by orchestrator functions, known as activity functions.

如果使用 Visual Studio,则使用 ActivityTriggerAttribute .NET 属性配置活动触发器。If you're using Visual Studio, the activity trigger is configured using the ActivityTriggerAttribute .NET attribute.

如果使用 VS Code 或 Azure 门户进行开发,则由 function.json 文件中 bindings 数组的以下 JSON 对象定义活动触发器:If you're using VS Code or the Azure portal for development, the activity trigger is defined by the following JSON object in the bindings array of function.json:

{
    "name": "<Name of input parameter in function signature>",
    "activity": "<Optional - name of the activity>",
    "type": "activityTrigger",
    "direction": "in"
}
  • activity 是活动的名称。activity is the name of the activity. 此值是业务流程协调程序函数用来调用此活动函数的名称。This value is the name that orchestrator functions use to invoke this activity function. 此属性是可选的。This property is optional. 如果未指定,则使用该函数的名称。If not specified, the name of the function is used.

本质上,此触发器绑定轮询函数应用的默认存储帐户中的一个轮询队列。Internally this trigger binding polls a queue in the default storage account for the function app. 这个队列是扩展的内部实现详细信息,因此未在绑定属性中显式配置此队列。This queue is an internal implementation detail of the extension, which is why it is not explicitly configured in the binding properties.

触发器行为Trigger behavior

以下是有关活动触发器的一些注意事项:Here are some notes about the activity trigger:

  • 线程处理 - 与业务流程触发器不同,活动触发器没有关于线程处理或 I/O 的任何限制 。Threading - Unlike the orchestration trigger, activity triggers don't have any restrictions around threading or I/O. 可以将它们视为常规功能。They can be treated like regular functions.
  • 有害消息处理 - 活动触发器中不支持有害消息 。Poison-message handling - There is no poison message support in activity triggers.
  • 消息可见性 - 活动触发器消息会取消排队并在可配置的持续时间内保持可见 。Message visibility - Activity trigger messages are dequeued and kept invisible for a configurable duration. 只要函数应用正常运行,这些消息的可见性就会自动更新。The visibility of these messages is renewed automatically as long as the function app is running and healthy.
  • 返回值 - 返回值序列化为 JSON,并持久保存到 Azure 表存储中的业务流程历史记录表 。Return values - Return values are serialized to JSON and persisted to the orchestration history table in Azure Table storage.

警告

活动函数的存储后端属于实现详细信息,用户代码不得直接与这些存储实体进行交互。The storage backend for activity functions is an implementation detail and user code should not interact with these storage entities directly.

触发器用法 (.NET)Trigger usage (.NET)

类似于业务流程触发器,活动触发器绑定也同时支持输入和输出。The activity trigger binding supports both inputs and outputs, just like the orchestration trigger. 下面是有关输入和输出处理的一些须知事项:Here are some things to know about input and output handling:

  • 输入 - .NET 活动函数以本机方式使用 DurableActivityContext 作为参数类型。inputs - .NET activity functions natively use DurableActivityContext as a parameter type. 或者,可以使用任何 JSON 可序列化的参数类型声明活动函数。Alternatively, an activity function can be declared with any parameter type that is JSON-serializable. 如果使用 DurableActivityContext,可以调用 GetInput<T> 来提取和反序列化活动函数输入。When you use DurableActivityContext, you can call GetInput<T> to fetch and deserialize the activity function input.
  • 输出 - 活动函数支持输出值以及输入。outputs - Activity functions support output values as well as inputs. 函数的返回值用于分配输出值,且必须是 JSON 可序列化的。The return value of the function is used to assign the output value and must be JSON-serializable. 如果 .NET 函数返回 Taskvoid,则会将 null 值保存为输出。If a .NET function returns Task or void, a null value will be saved as the output.
  • 元数据 - .NET 活动函数可以绑定到 string instanceId 参数,以获取父业务流程的实例 ID。metadata - .NET activity functions can bind to a string instanceId parameter to get the instance ID of the parent orchestration.

触发器示例Trigger sample

以下示例代码演示了简单的“Hello World”活动函数的形式:The following example code shows what a simple "Hello World" activity function might look like:

C#C#

[FunctionName("SayHello")]
public static string SayHello([ActivityTrigger] IDurableActivityContext helloContext)
{
    string name = helloContext.GetInput<string>();
    return $"Hello {name}!";
}

备注

前面的代码适用于 Durable Functions 2.x。The previous code is for Durable Functions 2.x. 对于 Durable Functions 1.x,必须使用 DurableActivityContext 而不是 IDurableActivityContextFor Durable Functions 1.x, you must use DurableActivityContext instead of IDurableActivityContext. 有关版本之间差异的详细信息,请参阅 Durable Functions 版本一文。For more information about the differences between versions, see the Durable Functions Versions article.

.NET ActivityTriggerAttribute 绑定的默认参数类型是 IDurableActivityContextThe default parameter type for the .NET ActivityTriggerAttribute binding is IDurableActivityContext. 但是,.NET 活动触发器还支持直接绑定到 JSON 可序列化类型(包括基元类型),因此相同的函数可以简化为如下所示:However, .NET activity triggers also support binding directly to JSON-serializeable types (including primitive types), so the same function could be simplified as follows:

[FunctionName("SayHello")]
public static string SayHello([ActivityTrigger] string name)
{
    return $"Hello {name}!";
}

JavaScript(仅限 Functions 2.0)JavaScript (Functions 2.0 only)

module.exports = async function(context) {
    return `Hello ${context.bindings.name}!`;
};

JavaScript 绑定可以还作为附加参数进行传入,因此,同一函数可以简化如下:JavaScript bindings can also be passed in as additional parameters, so the same function could be simplified as follows:

module.exports = async function(context, name) {
    return `Hello ${name}!`;
};

使用输入和输出绑定Using input and output bindings

除了活动触发器绑定以外,还可以使用普通的输入和输出绑定。You can use regular input and output bindings in addition to the activity trigger binding. 例如,可将输入提取到活动绑定,并使用“事件中心”输出绑定向事件中心发送消息:For example, you can take the input to your activity binding, and send a message to an EventHub using the EventHub output binding:

{
  "bindings": [
    {
      "name": "message",
      "type": "activityTrigger",
      "direction": "in"
    },
    {
      "type": "eventHub",
      "name": "outputEventHubMessage",
      "connection": "EventhubConnectionSetting",
      "eventHubName": "eh_messages",
      "direction": "out"
  }
  ]
}
module.exports = async function (context) {
    context.bindings.outputEventHubMessage = context.bindings.message;
};

业务流程客户端Orchestration client

通过业务流程客户端绑定,可以编写与业务流程协调程序函数进行交互的函数。The orchestration client binding enables you to write functions that interact with orchestrator functions. 这些函数有时称为客户端函数These functions are sometimes referred to as client functions. 例如,可以通过以下方式对业务流程实例进行操作:For example, you can act on orchestration instances in the following ways:

  • 启动它们。Start them.
  • 查询它们的状态。Query their status.
  • 终止它们。Terminate them.
  • 当它们正在运行时,向它们发送事件。Send events to them while they're running.
  • 清除实例历史记录。Purge instance history.

如果使用 Visual Studio,可以使用 Durable Functions 1.0 的 OrchestrationClientAttribute .NET 属性绑定到业务流程客户端。If you're using Visual Studio, you can bind to the orchestration client by using the OrchestrationClientAttribute .NET attribute for Durable Functions 1.0. 从 Durable Functions 2.0 开始,可以使用 DurableClientAttribute .NET 属性绑定到业务流程客户端。Starting in the Durable Functions 2.0, you can bind to the orchestration client by using the DurableClientAttribute .NET attribute.

如果使用脚本语言(例如, .csx.js 文件)进行开发,由 function.jsonbindings 数组中的以下 JSON 对象定义业务流程触发器:If you're using scripting languages (for example, .csx or .js files) for development, the orchestration trigger is defined by the following JSON object in the bindings array of function.json:

{
    "name": "<Name of input parameter in function signature>",
    "taskHub": "<Optional - name of the task hub>",
    "connectionName": "<Optional - name of the connection string app setting>",
    "type": "orchestrationClient",
    "direction": "in"
}
  • taskHub - 用于多个函数应用共享同一存储帐户但需要彼此独立的方案。taskHub - Used in scenarios where multiple function apps share the same storage account but need to be isolated from each other. 如果未指定,则使用 host.json 中的默认值。If not specified, the default value from host.json is used. 此值必须与目标业务流程协调程序函数所使用的值匹配。This value must match the value used by the target orchestrator functions.
  • connectionName - 包含存储帐户连接字符串的应用设置的名称。connectionName - The name of an app setting that contains a storage account connection string. 此连接字符串表示的存储帐户必须与目标业务流程协调程序函数所用的存储帐户相同。The storage account represented by this connection string must be the same one used by the target orchestrator functions. 如果未指定,则使用函数应用的默认存储帐户连接字符串。If not specified, the default storage account connection string for the function app is used.

备注

在大多数情况下,建议忽略这些属性,并依靠默认行为。In most cases, we recommend that you omit these properties and rely on the default behavior.

客户端使用情况Client usage

在 .NET 函数中,通常会绑定到 IDurableOrchestrationClient,后者可提供对 Durable Functions 支持的所有业务流程客户端 API 的完全访问权限。In .NET functions, you typically bind to IDurableOrchestrationClient, which gives you full access to all orchestration client APIs supported by Durable Functions. 在较旧的 Durable Functions 2.x 版本中,应改为绑定到 DurableOrchestrationClient 类。In the older Durable Functions 2.x releases, you instead bind to the DurableOrchestrationClient class. 在 JavaScript 中,相同的 API 是由从 getClient 返回的对象公开的。In JavaScript, the same APIs are exposed by the object returned from getClient. 客户端对象上的 API 包括:APIs on the client object include:

  • StartNewAsync
  • GetStatusAsync
  • TerminateAsync
  • RaiseEventAsync
  • PurgeInstanceHistoryAsync
  • CreateCheckStatusResponse
  • CreateHttpManagementPayload

另外,还可以将 .NET 函数绑定到 IAsyncCollector<T>,其中 TStartOrchestrationArgsJObjectAlternatively, .NET functions can bind to IAsyncCollector<T> where T is StartOrchestrationArgs or JObject.

有关这些操作的详细信息,请参阅 IDurableOrchestrationClient API 文档。For more information on these operations, see the IDurableOrchestrationClient API documentation.

客户端示例(Visual Studio 开发)Client sample (Visual Studio development)

下面的示例是启动“HelloWorld”业务流程的队列触发型函数。Here is an example queue-triggered function that starts a "HelloWorld" orchestration.

[FunctionName("QueueStart")]
public static Task Run(
    [QueueTrigger("durable-function-trigger")] string input,
    [DurableClient] IDurableOrchestrationClient starter)
{
    // Orchestration input comes from the queue message content.
    return starter.StartNewAsync("HelloWorld", input);
}

备注

前面的 C# 代码适用于 Durable Functions 2.x。The previous C# code is for Durable Functions 2.x. 对于 Durable Functions 1.x,必须使用 OrchestrationClient 属性而不是 DurableClient 属性,并且必须使用 DurableOrchestrationClient 参数类型而不是 IDurableOrchestrationClientFor Durable Functions 1.x, you must use OrchestrationClient attribute instead of the DurableClient attribute, and you must use the DurableOrchestrationClient parameter type instead of IDurableOrchestrationClient. 有关版本之间差异的详细信息,请参阅 Durable Functions 版本一文。For more information about the differences between versions, see the Durable Functions Versions article.

客户端示例(非 Visual Studio)Client sample (not Visual Studio)

如果未使用 Visual Studio 进行开发,则可以创建以下 function.json 文件。If you're not using Visual Studio for development, you can create the following function.json file. 此示例演示如何配置使用持久业务流程客户端绑定的队列触发型函数:This example shows how to configure a queue-triggered function that uses the durable orchestration client binding:

{
  "bindings": [
    {
      "name": "input",
      "type": "queueTrigger",
      "queueName": "durable-function-trigger",
      "direction": "in"
    },
    {
      "name": "starter",
      "type": "durableClient",
      "direction": "in"
    }
  ]
}

备注

前面的 JSON 适用于 Durable Functions 2.x。The previous JSON is for Durable Functions 2.x. 对于 Durable Functions 1.x,必须使用 orchestrationClient 而不是 durableClient 作为触发器类型。For Durable Functions 1.x, you must use orchestrationClient instead of the durableClient as the trigger type. 有关版本之间差异的详细信息,请参阅 Durable Functions 版本一文。For more information about the differences between versions, see the Durable Functions Versions article.

下面是启动新业务流程协调程序函数实例的语言特定示例。Following are language-specific samples that start new orchestrator function instances.

C# 脚本示例C# Script Sample

下面的示例演示如何使用持久业务流程客户端绑定从队列触发的 C# 函数启动新函数实例:The following sample shows how to use the durable orchestration client binding to start a new function instance from a queue-triggered C# function:

#r "Microsoft.Azure.WebJobs.Extensions.DurableTask"

using Microsoft.Azure.WebJobs.Extensions.DurableTask;

public static Task Run(string input, IDurableOrchestrationClient starter)
{
    return starter.StartNewAsync("HelloWorld", input);
}

备注

前面的代码适用于 Durable Functions 2.x。The previous code is for Durable Functions 2.x. 对于 Durable Functions 1.x,必须使用 DurableOrchestrationClient 参数类型而不是 IDurableOrchestrationClientFor Durable Functions 1.x, you must use the DurableOrchestrationClient parameter type instead of IDurableOrchestrationClient. 有关版本之间差异的详细信息,请参阅 Durable Functions 版本一文。For more information about the differences between versions, see the Durable Functions Versions article.

JavaScript 示例JavaScript Sample

下面的示例演示如何使用持久业务流程客户端绑定从 JavaScript 函数启动新函数实例:The following sample shows how to use the durable orchestration client binding to start a new function instance from a JavaScript function:

const df = require("durable-functions");

module.exports = async function (context) {
    const client = df.getClient(context);
    return instanceId = await client.startNew("HelloWorld", undefined, context.bindings.input);
};

有关启动实例的更多详细信息,请参阅实例管理More details on starting instances can be found in Instance management.

实体触发器Entity trigger

使用实体触发器可以创作实体函数Entity triggers allow you to author entity functions. 此触发器支持处理特定实体实例的事件。This trigger supports processing events for a specific entity instance.

使用适用于 Azure Functions 的 Visual Studio 工具时,需使用 EntityTriggerAttribute .NET 属性配置实体触发器。When you use the Visual Studio tools for Azure Functions, the entity trigger is configured using the EntityTriggerAttribute .NET attribute.

备注

从 Durable Functions 2.x 开始提供实体触发器。Entity triggers are available starting in Durable Functions 2.x.

本质上,此触发器绑定轮询函数应用的默认存储帐户中的一系列队列。Internally this trigger binding polls a series of queues in the default storage account for the function app. 这些队列是扩展的内部实现详细信息,因此未在绑定属性中显式配置这些队列。These queues are internal implementation details of the extension, which is why they are not explicitly configured in the binding properties.

触发器行为Trigger behavior

以下是有关实体触发器的一些注意事项:Here are some notes about the entity trigger:

  • 单线程:使用单个调度程序线程来处理特定实体的操作。Single-threaded: A single dispatcher thread is used to process operations for a particular entity. 如果将多个消息同时发送到单个实体,将会逐个处理操作。If multiple messages are sent to a single entity concurrently, the operations will be processed one-at-a-time.
  • 有害消息处理 - 实体触发器中不支持有害消息。Poison-message handling - There is no poison message support in entity triggers.
  • 消息可见性 - 实体触发器消息会取消排队并在可配置的持续时间内保持可见。Message visibility - Entity trigger messages are dequeued and kept invisible for a configurable duration. 只要函数应用正常运行,这些消息的可见性就会自动更新。The visibility of these messages is renewed automatically as long as the function app is running and healthy.
  • 返回值 - 实体函数不支持返回值。Return values - Entity functions do not support return values. 可以使用特定的 API 来保存状态,或者将值传回到业务流程。There are specific APIs that can be used to save state or pass values back to orchestrations.

在执行实体期间对实体所做的任何状态更改将在执行完成后自动保留。Any state changes made to an entity during its execution will be automatically persisted after execution has completed.

触发器用法 (.NET)Trigger usage (.NET)

每个实体函数具有参数类型 IDurableEntityContext,其中包含以下成员:Every entity function has a parameter type of IDurableEntityContext, which has the following members:

  • EntityName:当前正在执行的实体的名称。EntityName: the name of the currently executing entity.
  • EntityKey:当前正在执行的实体的键。EntityKey: the key of the currently executing entity.
  • EntityId:当前正在执行的实体的 ID。EntityId: the ID of the currently executing entity.
  • OperationName:当前操作的名称。OperationName: the name of the current operation.
  • HasState:实体是否存在,即,是否存在某种状态。HasState: whether the entity exists, that is, has some state.
  • GetState<TState>() :获取实体的当前状态。GetState<TState>(): gets the current state of the entity. 如果它不存在,则会创建它并将它初始化为 default<TState>If it does not already exist, it is created and initialized to default<TState>. TState 参数必须是基元或 JSON 可序列化类型。The TState parameter must be a primitive or JSON-serializeable type.
  • GetState<TState>(initfunction) :获取实体的当前状态。GetState<TState>(initfunction): gets the current state of the entity. 如果它不存在,则会通过调用提供的 initfunction 参数来创建它。If it does not already exist, it is created by calling the provided initfunction parameter. TState 参数必须是基元或 JSON 可序列化类型。The TState parameter must be a primitive or JSON-serializeable type.
  • SetState(arg) :创建或更新实体的状态。SetState(arg): creates or updates the state of the entity. arg 参数必须是 JSON 可序列化对象或基元。The arg parameter must be a JSON-serializeable object or primitive.
  • DeleteState() :删除实体的状态。DeleteState(): deletes the state of the entity.
  • GetInput<TInput>() :获取当前操作的输入。GetInput<TInput>(): gets the input for the current operation. TInput 类型参数必须是基元或 JSON 可序列化类型。The TInput type parameter must be a primitive or JSON-serializeable type.
  • Return(arg) :将值返回到调用该操作的业务流程。Return(arg): returns a value to the orchestration that called the operation. arg 参数必须是基元或 JSON 可序列化对象。The arg parameter must be a primitive or JSON-serializeable object.
  • SignalEntity(EntityId, scheduledTimeUtc, operation, input) :向实体发送单向消息。SignalEntity(EntityId, scheduledTimeUtc, operation, input): sends a one-way message to an entity. operation 参数必须是非 NULL 字符串,可选 scheduledTimeUtc 必须是调用操作的 UTC 日期时间,input 参数必须是基元或 JSON 可序列化对象。The operation parameter must be a non-null string, the optional scheduledTimeUtc must be a UTC datetime at which to invoke the operation, and the input parameter must be a primitive or JSON-serializeable object.
  • CreateNewOrchestration(orchestratorFunctionName, input) :启动新的业务流程。CreateNewOrchestration(orchestratorFunctionName, input): starts a new orchestration. input 参数必须是基元或 JSON 可序列化对象。The input parameter must be a primitive or JSON-serializeable object.

传递给实体函数的 IDurableEntityContext 对象可以使用 Entity.Current 异步本地属性进行访问。The IDurableEntityContext object passed to the entity function can be accessed using the Entity.Current async-local property. 在使用基于类的编程模型时,此方法很方便。This approach is convenient when using the class-based programming model.

触发器示例(基于 C# 函数的语法)Trigger sample (C# function-based syntax)

以下代码是作为持久函数实现的简单 Counter 实体示例。The following code is an example of a simple Counter entity implemented as a durable function. 此函数定义三个操作:addresetget,每个操作针对整数状态运行。This function defines three operations, add, reset, and get, each of which operate on an integer state.

[FunctionName("Counter")]
public static void Counter([EntityTrigger] IDurableEntityContext ctx)
{
    switch (ctx.OperationName.ToLowerInvariant())
    {
        case "add":
            ctx.SetState(ctx.GetState<int>() + ctx.GetInput<int>());
            break;
        case "reset":
            ctx.SetState(0);
            break;
        case "get":
            ctx.Return(ctx.GetState<int>()));
            break;
    }
}

有关基于函数的语法及其用法的详细信息,请参阅基于函数的语法For more information on the function-based syntax and how to use it, see Function-Based Syntax.

触发器示例(基于 C# 类的语法)Trigger sample (C# class-based syntax)

以下示例是使用类和方法的 Counter 实体的等效实现。The following example is an equivalent implementation of the Counter entity using classes and methods.

[JsonObject(MemberSerialization.OptIn)]
public class Counter
{
    [JsonProperty("value")]
    public int CurrentValue { get; set; }

    public void Add(int amount) => this.CurrentValue += amount;

    public void Reset() => this.CurrentValue = 0;

    public int Get() => this.CurrentValue;

    [FunctionName(nameof(Counter))]
    public static Task Run([EntityTrigger] IDurableEntityContext ctx)
        => ctx.DispatchAsync<Counter>();
}

此实体的状态是 Counter 类型的对象,该对象包含存储计数器当前值的字段。The state of this entity is an object of type Counter, which contains a field that stores the current value of the counter. 为了将此对象持久保存在存储中,Json.NET 库会将其序列化和反序列化。To persist this object in storage, it is serialized and deserialized by the Json.NET library.

有关基于类的语法及其用法的详细信息,请参阅定义实体类For more information on the class-based syntax and how to use it, see Defining entity classes.

备注

使用实体类时,必须将具有 [FunctionName] 属性的函数入口点方法声明为 staticThe function entry point method with the [FunctionName] attribute must be declared static when using entity classes. 非静态入口点方法可能会导致多次进行对象初始化,并可能导致其他不确定的行为。Non-static entry point methods may result in multiple object initialization and potentially other undefined behaviors.

实体类使用特殊的机制来与绑定和 .NET 依赖项注入交互。Entity classes have special mechanisms for interacting with bindings and .NET dependency injection. 有关详细信息,请参阅实体构造For more information, see Entity construction.

触发器示例 (JavaScript)Trigger sample (JavaScript)

以下代码是作为持久函数(以 JavaScript 编写)实现的简单 Counter 实体示例。The following code is an example of a simple Counter entity implemented as a durable function written in JavaScript. 此函数定义三个操作:addresetget,每个操作针对整数状态运行。This function defines three operations, add, reset, and get, each of which operate on an integer state.

function.jsonfunction.json

{
  "bindings": [
    {
      "name": "context",
      "type": "entityTrigger",
      "direction": "in"
    }
  ],
  "disabled": false
}

index.jsindex.js

const df = require("durable-functions");

module.exports = df.entity(function(context) {
    const currentValue = context.df.getState(() => 0);
    switch (context.df.operationName) {
        case "add":
            const amount = context.df.getInput();
            context.df.setState(currentValue + amount);
            break;
        case "reset":
            context.df.setState(0);
            break;
        case "get":
            context.df.return(currentValue);
            break;
    }
});

备注

durable-functions npm 包版本 1.3.0 开始,JavaScript 中提供了持久实体 。Durable entities are available in JavaScript starting with version 1.3.0 of the durable-functions npm package.

实体客户端Entity client

使用实体客户端绑定可以异步触发实体函数The entity client binding enables you to asynchronously trigger entity functions. 这些函数有时称为客户端函数These functions are sometimes referred to as client functions.

如果使用 Visual Studio,则可以使用 DurableClientAttribute .NET 属性绑定到实体客户端。If you're using Visual Studio, you can bind to the entity client by using the DurableClientAttribute .NET attribute.

备注

还可以使用 [DurableClientAttribute] 绑定到业务流程客户端The [DurableClientAttribute] can also be used to bind to the orchestration client.

如果使用脚本语言(例如, .csx.js 文件)进行开发,由 function.jsonbindings 数组中的以下 JSON 对象定义实体触发器:If you're using scripting languages (for example, .csx or .js files) for development, the entity trigger is defined by the following JSON object in the bindings array of function.json:

{
    "name": "<Name of input parameter in function signature>",
    "taskHub": "<Optional - name of the task hub>",
    "connectionName": "<Optional - name of the connection string app setting>",
    "type": "durableClient",
    "direction": "in"
}
  • taskHub - 用于多个函数应用共享同一存储帐户但需要彼此独立的方案。taskHub - Used in scenarios where multiple function apps share the same storage account but need to be isolated from each other. 如果未指定,则使用 host.json 中的默认值。If not specified, the default value from host.json is used. 此值必须与目标实体函数所使用的值匹配。This value must match the value used by the target entity functions.
  • connectionName - 包含存储帐户连接字符串的应用设置的名称。connectionName - The name of an app setting that contains a storage account connection string. 此连接字符串表示的存储帐户必须与目标实体函数所用的存储帐户相同。The storage account represented by this connection string must be the same one used by the target entity functions. 如果未指定,则使用函数应用的默认存储帐户连接字符串。If not specified, the default storage account connection string for the function app is used.

备注

在大多数情况下,建议忽略可选属性,并依赖默认行为。In most cases, we recommend that you omit the optional properties and rely on the default behavior.

实体客户端的用法Entity client usage

在 .NET 函数中,通常会绑定到 IDurableEntityClient,后者可提供对持久实体支持的所有客户端 API 的完全访问权限。In .NET functions, you typically bind to IDurableEntityClient, which gives you full access to all client APIs supported by Durable Entities. 也可以绑定到 IDurableOrchestrationClient 接口,该接口提供对实体和业务流程的客户端 API 的访问。You can also bind to the IDurableOrchestrationClient interface, which provides access to client APIs for both entities and orchestrations. 客户端对象上的 API 包括:APIs on the client object include:

  • ReadEntityStateAsync<T> :读取实体的状态。ReadEntityStateAsync<T>: reads the state of an entity. 它会返回响应,指出目标实体是否存在,以及在存在的情况下,其状态是什么。It returns a response that indicates whether the target entity exists, and if so, what its state is.
  • SignalEntityAsync:将单向消息发送到实体,并等待消息排队。SignalEntityAsync: sends a one-way message to an entity, and waits for it to be enqueued.
  • ListEntitiesAsync:查询多个实体的状态。ListEntitiesAsync: queries for the state of multiple entities. 可以按“名称” 和“上次操作时间” 来查询实体。Entities can be queried by name and last operation time.

不需在发送信号之前创建目标实体 - 实体状态可以在处理信号的实体函数内部创建。There is no need to create the target entity before sending a signal - the entity state can be created from within the entity function that handles the signal.

备注

必须知道,从客户端发送的“信号”会直接排队,稍后以异步方式对其进行处理。It's important to understand that the "signals" sent from the client are simply enqueued, to be processed asynchronously at a later time. 具体说来,SignalEntityAsync 通常会在实体开始操作之前返回,因此不可能获取返回值或观察异常。In particular, the SignalEntityAsync usually returns before the entity even starts the operation, and it is not possible to get back the return value or observe exceptions. 如果需要更强的保证(例如,在使用工作流的情况下),则应使用业务流程协调程序函数,此类函数会等待实体操作完成,可以处理返回值并观察异常。If stronger guarantees are required (e.g. for workflows), orchestrator functions should be used, which can wait for entity operations to complete, and can process return values and observe exceptions.

示例:客户端直接向实体发出信号 - C#Example: client signals entity directly - C#

下面是一个调用“计数器”实体的示例队列触发的函数。Here is an example queue-triggered function that invokes a "Counter" entity.

[FunctionName("AddFromQueue")]
public static Task Run(
    [QueueTrigger("durable-function-trigger")] string input,
    [DurableClient] IDurableEntityClient client)
{
    // Entity operation input comes from the queue message content.
    var entityId = new EntityId(nameof(Counter), "myCounter");
    int amount = int.Parse(input);
    return client.SignalEntityAsync(entityId, "Add", amount);
}

示例:客户端同接口向实体发出信号 - C#Example: client signals entity via interface - C#

我们建议尽量通过接口访问实体,因为这种方法提供更多的类型检查。Where possible, we recommend accessing entities through interfaces because it provides more type checking. 例如,假设前面所述的 Counter 实体实现 ICounter 接口,定义如下:For example, suppose the Counter entity mentioned earlier implemented an ICounter interface, defined as follows:

public interface ICounter
{
    void Add(int amount);
    void Reset();
    Task<int> Get();
}

public class Counter : ICounter
{
    // ...
}

然后,客户端代码可以使用 SignalEntityAsync<ICounter>,以生成类型安全的代理:Client code can then use SignalEntityAsync<ICounter> to generate a type-safe proxy:

[FunctionName("UserDeleteAvailable")]
public static async Task AddValueClient(
    [QueueTrigger("my-queue")] string message,
    [DurableClient] IDurableEntityClient client)
{
    var target = new EntityId(nameof(Counter), "myCounter");
    int amount = int.Parse(message);
    await client.SignalEntityAsync<ICounter>(target, proxy => proxy.Add(amount));
}

proxy 参数是动态生成的 ICounter 实例,它在内部将 Add 调用转换为等效的(非类型化)SignalEntityAsync 调用。The proxy parameter is a dynamically generated instance of ICounter, which internally translates the call to Add into the equivalent (untyped) call to SignalEntityAsync.

备注

SignalEntityAsync API 表示单向操作。The SignalEntityAsync APIs represent one-way operations. 如果实体接口返回 Task<T>,则 T 参数的值始终为 null 或 defaultIf an entity interfaces returns Task<T>, the value of the T parameter will always be null or default.

具体说来,向 Get 操作发出信号没有意义,因为这不会返回任何值。In particular, it does not make sense to signal the Get operation, as no value is returned. 客户端可以改用 ReadStateAsync 来直接访问计数器状态,或者可以启动一个调用 Get 操作的业务流程协调程序函数。Instead, clients can use either ReadStateAsync to access the counter state directly, or can start an orchestrator function that calls the Get operation.

示例:客户端向实体发出信号 - JavaScriptExample: client signals entity - JavaScript

下面是一个在 JavaScript 中指示“计数器”实体的队列触发函数示例。Here is an example queue-triggered function that signals a "Counter" entity in JavaScript.

function.jsonfunction.json

{
    "bindings": [
      {
        "name": "input",
        "type": "queueTrigger",
        "queueName": "durable-entity-trigger",
        "direction": "in",
      },
      {
        "name": "starter",
        "type": "durableClient",
        "direction": "in"
      }
    ],
    "disabled": false
  }

index.jsindex.js

const df = require("durable-functions");

module.exports = async function (context) {
    const client = df.getClient(context);
    const entityId = new df.EntityId("Counter", "myCounter");
    await context.df.signalEntity(entityId, "add", 1);
};

备注

durable-functions npm 包版本 1.3.0 开始,JavaScript 中提供了持久实体 。Durable entities are available in JavaScript starting with version 1.3.0 of the durable-functions npm package.

host.json 设置host.json settings

Durable Functions 的配置设置。Configuration settings for Durable Functions.

Durable Functions 1.xDurable Functions 1.x

{
  "durableTask": {
    "hubName": "MyTaskHub",
    "controlQueueBatchSize": 32,
    "partitionCount": 4,
    "controlQueueVisibilityTimeout": "00:05:00",
    "workItemQueueVisibilityTimeout": "00:05:00",
    "maxConcurrentActivityFunctions": 10,
    "maxConcurrentOrchestratorFunctions": 10,
    "maxQueuePollingInterval": "00:00:30",
    "azureStorageConnectionStringName": "AzureWebJobsStorage",
    "trackingStoreConnectionStringName": "TrackingStorage",
    "trackingStoreNamePrefix": "DurableTask",
    "traceInputsAndOutputs": false,
    "logReplayEvents": false,
    "eventGridTopicEndpoint": "https://topic_name.chinanorth2-1.eventgrid.chinacloudapi.cn/api/events",
    "eventGridKeySettingName":  "EventGridKey",
    "eventGridPublishRetryCount": 3,
    "eventGridPublishRetryInterval": "00:00:30",
    "eventGridPublishEventTypes": ["Started", "Completed", "Failed", "Terminated"]
  }
}

Durable Functions 2.xDurable Functions 2.x

{
 "extensions": {
  "durableTask": {
    "hubName": "MyTaskHub",
    "storageProvider": {
      "connectionStringName": "AzureWebJobsStorage",
      "controlQueueBatchSize": 32,
      "controlQueueBufferThreshold": 256,
      "controlQueueVisibilityTimeout": "00:05:00",
      "maxQueuePollingInterval": "00:00:30",
      "partitionCount": 4,
      "trackingStoreConnectionStringName": "TrackingStorage",
      "trackingStoreNamePrefix": "DurableTask",
      "workItemQueueVisibilityTimeout": "00:05:00",
    },
    "tracing": {
      "traceInputsAndOutputs": false,
      "traceReplayEvents": false,
    },
    "notifications": {
      "eventGrid": {
        "topicEndpoint": "https://topic_name.chinanorth2-1.eventgrid.chinacloudapi.cn/api/events",
        "keySettingName": "EventGridKey",
        "publishRetryCount": 3,
        "publishRetryInterval": "00:00:30",
        "publishEventTypes": [
          "Started",
          "Pending",
          "Failed",
          "Terminated"
        ]
      }
    },
    "maxConcurrentActivityFunctions": 10,
    "maxConcurrentOrchestratorFunctions": 10,
    "extendedSessionsEnabled": false,
    "extendedSessionIdleTimeoutInSeconds": 30,
    "useGracefulShutdown": false
  }
  }
}

任务中心名称必须以字母开头且只能包含字母和数字。Task hub names must start with a letter and consist of only letters and numbers. 如果未指定,则函数应用的默认任务中心名称是 DurableFunctionsHubIf not specified, the default task hub name for a function app is DurableFunctionsHub. 有关详细信息,请参阅任务中心For more information, see Task hubs.

属性Property 默认Default 说明Description
hubNamehubName DurableFunctionsHubDurableFunctionsHub 可以使用备用任务中心名称将多个 Durable Functions 应用程序彼此隔离,即使这些应用程序使用同一存储后端。Alternate task hub names can be used to isolate multiple Durable Functions applications from each other, even if they're using the same storage backend.
controlQueueBatchSizecontrolQueueBatchSize 3232 要从控制队列中一次性拉取的消息数。The number of messages to pull from the control queue at a time.
controlQueueBufferThresholdcontrolQueueBufferThreshold 256256 一次可以在内存中缓冲的控制队列消息数,此时调度程序将等待,然后再将任何其他消息出队。The number of control queue messages that can be buffered in memory at a time, at which point the dispatcher will wait before dequeuing any additional messages.
partitionCountpartitionCount 44 控制队列的分区计数。The partition count for the control queue. 可以是 1 到 16 之间的正整数。May be a positive integer between 1 and 16.
controlQueueVisibilityTimeoutcontrolQueueVisibilityTimeout 5 分钟5 minutes 已取消排队的控制队列消息的可见性超时。The visibility timeout of dequeued control queue messages.
workItemQueueVisibilityTimeoutworkItemQueueVisibilityTimeout 5 分钟5 minutes 已取消排队的工作项队列消息的可见性超时。The visibility timeout of dequeued work item queue messages.
maxConcurrentActivityFunctionsmaxConcurrentActivityFunctions 10 倍于当前计算机上的处理器数10X the number of processors on the current machine 可以在单个主机实例上并发处理的活动函数的最大数目。The maximum number of activity functions that can be processed concurrently on a single host instance.
maxConcurrentOrchestratorFunctionsmaxConcurrentOrchestratorFunctions 10 倍于当前计算机上的处理器数10X the number of processors on the current machine 可以在单个主机实例上并发处理的业务流程协调程序函数的最大数目。The maximum number of orchestrator functions that can be processed concurrently on a single host instance.
maxQueuePollingIntervalmaxQueuePollingInterval 30 秒30 seconds 最大的控制和工作项队列轮询时间间隔,采用 hh:mm:ss 格式。The maximum control and work-item queue polling interval in the hh:mm:ss format. 值越高,可能导致的消息处理延迟也越高。Higher values can result in higher message processing latencies. 值越低,可能导致的存储成本会越高,因为存储事务数增高。Lower values can result in higher storage costs because of increased storage transactions.
azureStorageConnectionStringNameazureStorageConnectionStringName AzureWebJobsStorageAzureWebJobsStorage 应用设置的名称,其中的 Azure 存储连接字符串用于管理基础的 Azure 存储资源。The name of the app setting that has the Azure Storage connection string used to manage the underlying Azure Storage resources.
trackingStoreConnectionStringNametrackingStoreConnectionStringName 连接字符串的名称,用于“历史记录”和“实例”表。The name of a connection string to use for the History and Instances tables. 如果未指定,则使用 azureStorageConnectionStringName 连接。If not specified, the azureStorageConnectionStringName connection is used.
trackingStoreNamePrefixtrackingStoreNamePrefix 指定 trackingStoreConnectionStringName 时用于“历史记录”和“实例”表的前缀。The prefix to use for the History and Instances tables when trackingStoreConnectionStringName is specified. 如果未设置,则默认前缀值为 DurableTaskIf not set, the default prefix value will be DurableTask. 如果 trackingStoreConnectionStringName 未指定,则“历史记录”和“实例”表会使用 hubName 值作为其前缀,trackingStoreNamePrefix 的任何设置都会被忽略。If trackingStoreConnectionStringName is not specified, then the History and Instances tables will use the hubName value as their prefix, and any setting for trackingStoreNamePrefix will be ignored.
traceInputsAndOutputstraceInputsAndOutputs falsefalse 一个指示是否跟踪函数调用的输入和输出的值。A value indicating whether to trace the inputs and outputs of function calls. 跟踪函数执行事件时的默认行为是在函数调用的序列化输入和输出中包括字节数。The default behavior when tracing function execution events is to include the number of bytes in the serialized inputs and outputs for function calls. 此行为提供的有关输入和输出情况的信息是最少的,不会导致日志膨胀,也不会无意中将敏感信息公开。This behavior provides minimal information about what the inputs and outputs look like without bloating the logs or inadvertently exposing sensitive information. 将此属性设置为 true 会导致默认函数日志记录将函数输入和输出的整个内容都记录下来。Setting this property to true causes the default function logging to log the entire contents of function inputs and outputs.
logReplayEventslogReplayEvents falsefalse 一个值,该值指示是否将业务流程重播事件写入到 Application Insights。A value indicating whether to write orchestration replay events to Application Insights.
eventGridTopicEndpointeventGridTopicEndpoint Azure 事件网格自定义主题终结点的 URL。The URL of an Azure Event Grid custom topic endpoint. 设置此属性后,业务流程生命周期通知事件就会发布到此终结点。When this property is set, orchestration life-cycle notification events are published to this endpoint. 此属性支持应用设置解析。This property supports App Settings resolution.
eventGridKeySettingNameeventGridKeySettingName 应用设置的名称,该设置包含的密钥用于在 EventGridTopicEndpoint 上通过 Azure 事件网格自定义主题进行身份验证。The name of the app setting containing the key used for authenticating with the Azure Event Grid custom topic at EventGridTopicEndpoint.
eventGridPublishRetryCounteventGridPublishRetryCount 00 发布到事件网格主题失败时要重试的次数。The number of times to retry if publishing to the Event Grid Topic fails.
eventGridPublishRetryIntervaleventGridPublishRetryInterval 5 分钟5 minutes 事件网格发布重试间隔(采用 hh:mm:ss 格式)。The Event Grid publishes retry interval in the hh:mm:ss format.
eventGridPublishEventTypeseventGridPublishEventTypes 要发布到事件网格的事件类型列表。A list of event types to publish to Event Grid. 如果未指定,则将发布所有事件类型。If not specified, all event types will be published. 允许的值包括 StartedCompletedFailedTerminatedAllowed values include Started, Completed, Failed, Terminated.
useGracefulShutdownuseGracefulShutdown falsefalse (预览)启用正常关闭以减少主机关闭导致进程内函数执行失败的机会。(Preview) Enable gracefully shutting down to reduce the chance of host shutdowns failing in-process function executions.

许多此类设置用于优化性能。Many of these settings are for optimizing performance. 有关详细信息,请参阅性能和缩放For more information, see Performance and scale.

后续步骤Next steps