Durable Functions 中的函式鏈結- Hello 序列範例
本文內容
函式鏈結是指以特定順序執行一連串函式的模式。 通常,一個函式的輸出必須套用至另一個函式的輸入。 此文章說明當您完成 Durable Functions 快速入門 (C# 、JavaScript 、TypeScript 、Python 、PowerShell 或 Java ) 時所建立的鏈結序列。 如需 Durable Functions 的詳細資訊,請參閱 Durable Functions 概觀 。
必要條件
注意
適用於 Azure Functions 的第 4 版 Node.js 程式設計模型已正式推出。 新的 v4 模型旨在為 JavaScript 和 TypeScript 開發人員提供更靈活的直覺式體驗。 如需深入了解 v3 與 v4 之間的差異,請參閱移轉指南 。
在下列程式碼片段中,JavaScript (PM4) 表示程式設計模型 V4,這是新的體驗。
函式
本文說明範例應用程式中的函式如下:
E1_HelloSequence
:連續呼叫 E1_SayHello
多次的協調器函式 。 它會儲存 E1_SayHello
呼叫的輸出,並記錄結果。
E1_SayHello
:在字串前面加上「Hello」的活動函式 。
HttpStart
:HTTP 觸發的 耐久性用戶端 函式,可啟動協調器的執行個體。
E1_HelloSequence 協調器函式
[FunctionName("E1_HelloSequence")]
public static async Task<List<string>> Run(
[OrchestrationTrigger] IDurableOrchestrationContext context)
{
var outputs = new List<string>();
outputs.Add(await context.CallActivityAsync<string>("E1_SayHello", "Tokyo"));
outputs.Add(await context.CallActivityAsync<string>("E1_SayHello", "Seattle"));
outputs.Add(await context.CallActivityAsync<string>("E1_SayHello_DirectInput", "London"));
// returns ["Hello Tokyo!", "Hello Seattle!", "Hello London!"]
return outputs;
}
所有 C# 協調流程函式都必須有 DurableOrchestrationContext
類型的參數 (在 Microsoft.Azure.WebJobs.Extensions.DurableTask
組件中)。 此內容物件可讓您使用其 CallActivityAsync
方法來呼叫其他「活動」 函式並傳遞輸入參數。
程式碼中以不同的參數值連續呼叫 E1_SayHello
三次。 每次呼叫的傳回值會新增至函式最後傳回的 outputs
清單。
function.json
如果您使用 Visual Studio Code 或 Azure 入口網站進行開發,以下是適用於協調器函式的 function.json 檔案內容。 大部分協調器 function.json 檔案看起來幾乎完全像這樣。
{
"bindings": [
{
"name": "context",
"type": "orchestrationTrigger",
"direction": "in"
}
],
"disabled": false
}
重要的是 orchestrationTrigger
繫結類型。 所有協調器函式必須都使用此觸發程序類型。
警告
為了遵守協調器函式的「沒有 I/O」規則,當您使用 orchestrationTrigger
觸發程序繫結時,請勿使用任何輸入或輸出繫結。 如果需要其他輸入或輸出繫結,請改為在協調器所呼叫之 activityTrigger
函式的內容中使用。 如需詳細資訊,請參閱協調器函數程式碼條件約束 一文。
index.js
協調器函式如下:
const df = require("durable-functions");
module.exports = df.orchestrator(function* (context) {
context.log("Starting chain sample");
const output = [];
output.push(yield context.df.callActivity("E1_SayHello", "Tokyo"));
output.push(yield context.df.callActivity("E1_SayHello", "Seattle"));
output.push(yield context.df.callActivity("E1_SayHello", "London"));
return output;
});
所有 JavaScript 協調流程函式都必須包含 durable-functions
模組 。 這是可讓您以 JavaScript 撰寫 Durable Functions 的程式庫。 協調器函式與其他 JavaScript 函式之間有三項重大差異:
協調器函式是一種產生器函式 。
此函式會包裝在對durable-functions
模組的orchestrator
方法進行的呼叫中 (在此是 df
)。
此函式必須是同步的。 「Orchestrator」方法會處理對於「context.done」的最終呼叫,因為函式應該只是「return」。
context
物件包含一個 df
長期協調流程內容物件,可讓您使用其 callActivity
方法來呼叫其他「活動」 函式並傳遞輸入參數。 程式碼會使用不同的參數值依序呼叫 E1_SayHello
三次,使用 yield
表示執行應等候要傳回的非同步活動函式呼叫。 每次呼叫的傳回值會新增至函式最後傳回的 outputs
陣列。
const df = require("durable-functions");
const helloActivityName = "sayHello";
df.app.orchestration("helloSequence", function* (context) {
context.log("Starting chain sample");
const output = [];
output.push(yield context.df.callActivity(helloActivityName, "Tokyo"));
output.push(yield context.df.callActivity(helloActivityName, "Seattle"));
output.push(yield context.df.callActivity(helloActivityName, "Cairo"));
return output;
});
所有 JavaScript 協調流程函式都必須包含 durable-functions
模組 。 本課程模組可讓您使用 JavaScript 撰寫 Durable Functions。 若要使用 V4 節點程式設計模型,您必須安裝 durable-functions
的預覽 v3.x
版本。
協調器函式與其他 JavaScript 函式之間有兩大差異:
協調器函式是一種產生器函式 。
此函式必須是同步的。 函式應只會「傳回」。
context
物件包含一個 df
長期協調流程內容物件,可讓您使用其 callActivity
方法來呼叫其他「活動」 函式並傳遞輸入參數。 程式碼會使用不同的參數值依序呼叫 sayHello
三次,使用 yield
表示執行應等候要傳回的非同步活動函式呼叫。 每次呼叫的傳回值會新增至函式最後傳回的 outputs
陣列。
注意
Python Durable Functions 僅可供 Functions 3.0 執行階段使用。
function.json
如果您使用 Visual Studio Code 或 Azure 入口網站進行開發,以下是適用於協調器函式的 function.json 檔案內容。 大部分協調器 function.json 檔案看起來幾乎完全像這樣。
{
"scriptFile": "__init__.py",
"bindings": [
{
"name": "context",
"type": "orchestrationTrigger",
"direction": "in"
}
]
}
重要的是 orchestrationTrigger
繫結類型。 所有協調器函式必須都使用此觸發程序類型。
警告
為了遵守協調器函式的「沒有 I/O」規則,當您使用 orchestrationTrigger
觸發程序繫結時,請勿使用任何輸入或輸出繫結。 如果需要其他輸入或輸出繫結,請改為在協調器所呼叫之 activityTrigger
函式的內容中使用。 如需詳細資訊,請參閱協調器函數程式碼條件約束 一文。
__init__.py
協調器函式如下:
import azure.functions as func
import azure.durable_functions as df
def orchestrator_function(context: df.DurableOrchestrationContext):
result1 = yield context.call_activity('E1_SayHello', "Tokyo")
result2 = yield context.call_activity('E1_SayHello', "Seattle")
result3 = yield context.call_activity('E1_SayHello', "London")
return [result1, result2, result3]
main = df.Orchestrator.create(orchestrator_function)
所有 Python 協調流程函式都必須包含 durable-functions
套件 。 這是可讓您以 Python 撰寫 Durable Functions 的程式庫。 協調器函式與其他 Python 函式之間有兩項重大差異:
協調器函式是一種產生器函式 。
該「檔案」 應該藉由在檔案結尾指出 main = df.Orchestrator.create(<orchestrator function name>)
,好將協調器函式註冊為協調器。 這有助於區別該函式與檔案中宣告的其他協助程式函式。
此 context
物件可讓您使用其 call_activity
方法來呼叫其他「活動」 函式並傳遞輸入參數。 程式碼會使用不同的參數值依序呼叫 E1_SayHello
三次,使用 yield
表示執行應等候要傳回的非同步活動函式呼叫。 每次呼叫的傳回值會在函式的最後傳回。
E1_SayHello 活動函式
[FunctionName("E1_SayHello")]
public static string SayHello([ActivityTrigger] IDurableActivityContext context)
{
string name = context.GetInput<string>();
return $"Hello {name}!";
}
活動會使用 ActivityTrigger
屬性。 使用提供的 IDurableActivityContext
來執行活動相關動作,例如使用 GetInput<T>
來存取輸入值。
E1_SayHello
的實作是相當簡單的字串格式化作業。
您可以直接繫結至傳遞至活動函式的類型,而不是繫結至 IDurableActivityContext
。 例如:
[FunctionName("E1_SayHello_DirectInput")]
public static string SayHelloDirectInput([ActivityTrigger] string name)
{
return $"Hello {name}!";
}
E1_SayHello/function.json
活動函式 E1_SayHello
和 E1_HelloSequence
的 function.json 檔案很類似,差別在於前者使用 activityTrigger
繫結型別,而不是 orchestrationTrigger
繫結型別。
{
"bindings": [
{
"name": "name",
"type": "activityTrigger",
"direction": "in"
}
],
"disabled": false
}
注意
協調流程函式所呼叫的所有活動函式必須使用 activityTrigger
繫結。
E1_SayHello
的實作是相當簡單的字串格式化作業。
E1_SayHello/index.js
module.exports = function (context) {
context.done(null, `Hello ${context.bindings.name}!`);
};
不同於協調流程函式,活動函式不需要特殊安裝。 協調器函式傳遞給它的輸入位於 context.bindings
物件的 activityTrigger
繫結名稱之下 - 在此例中為 context.bindings.name
。 繫結名稱可以設定為所匯出函式的參數並直接進行存取,這是範例程式碼所執行的作業。
sayHello
的實作是相當簡單的字串格式化作業。
const df = require("durable-functions");
const helloActivityName = "sayHello";
df.app.activity(helloActivityName, {
handler: function (input) {
return `Hello ${input}`;
},
});
不同於協調流程函式,活動函式不需要特殊安裝。 協調器函式所傳遞的輸入是該函式的第一個引數。 第二個引數是叫用內容,但在此範例中不會用到。
E1_SayHello/function.json
活動函式 E1_SayHello
和 E1_HelloSequence
的 function.json 檔案很類似,差別在於前者使用 activityTrigger
繫結型別,而不是 orchestrationTrigger
繫結型別。
{
"scriptFile": "__init__.py",
"bindings": [
{
"name": "name",
"type": "activityTrigger",
"direction": "in"
}
]
}
注意
協調流程函式所呼叫的所有活動函式必須使用 activityTrigger
繫結。
E1_SayHello
的實作是相當簡單的字串格式化作業。
E1_SayHello/__init__.py
def main(name: str) -> str:
return f"Hello {name}!"
不同於協調器函式,活動函式不需要特殊安裝。 可以直接存取協調器函式所傳遞的輸入,並將其當做函式的參數。
HttpStart 用戶端函式
您可以使用用戶端函式來啟動協調器函式的執行個體。 您將使用 HTTP 觸發的 HttpStart
函式來啟動 E1_HelloSequence
的執行個體。
public static class HttpStart
{
[FunctionName("HttpStart")]
public static async Task<HttpResponseMessage> Run(
[HttpTrigger(AuthorizationLevel.Function, methods: "post", Route = "orchestrators/{functionName}")] HttpRequestMessage req,
[DurableClient] IDurableClient starter,
string functionName,
ILogger log)
{
// Function input comes from the request content.
object eventData = await req.Content.ReadAsAsync<object>();
string instanceId = await starter.StartNewAsync(functionName, eventData);
log.LogInformation($"Started orchestration with ID = '{instanceId}'.");
return starter.CreateCheckStatusResponse(req, instanceId);
}
}
若要與協調器互動,函式必須包含 DurableClient
輸入繫結。 您可以使用用戶端來啟動協調流程。 其也可以協助您傳回 HTTP 回應,其中包含 URL,用於檢查新協調流程的狀態。
HttpStart/function.json
{
"bindings": [
{
"authLevel": "anonymous",
"name": "req",
"type": "httpTrigger",
"direction": "in",
"route": "orchestrators/{functionName}",
"methods": ["post"]
},
{
"name": "$return",
"type": "http",
"direction": "out"
},
{
"name": "starter",
"type": "orchestrationClient",
"direction": "in"
}
],
"disabled": false
}
若要與協調器互動,函式必須包含 durableClient
輸入繫結。
HttpStart/index.js
const df = require("durable-functions");
module.exports = async function (context, req) {
const client = df.getClient(context);
const instanceId = await client.startNew(req.params.functionName, undefined, req.body);
context.log(`Started orchestration with ID = '${instanceId}'.`);
return client.createCheckStatusResponse(context.bindingData.req, instanceId);
};
請使用 df.getClient
來取得 DurableOrchestrationClient
物件。 您可以使用用戶端來啟動協調流程。 其也可以協助您傳回 HTTP 回應,其中包含 URL,用於檢查新協調流程的狀態。
const df = require("durable-functions");
const { app } = require("@azure/functions");
app.http("httpStart", {
route: "orchestrators/{orchestratorName}",
extraInputs: [df.input.durableClient()],
handler: async (request, context) => {
const client = df.getClient(context);
const body = await request.json();
const instanceId = await client.startNew(request.params.orchestratorName, { input: body });
context.log(`Started orchestration with ID = '${instanceId}'.`);
return client.createCheckStatusResponse(request, instanceId);
},
});
若要管理協調器和與其互動,此函式需要 durableClient
輸入繫結。 註冊函式時,必須在 extraInputs
引數中指定此繫結。 您可以呼叫 df.input.durableClient()
來取得 durableClient
輸入。
請使用 df.getClient
來取得 DurableClient
物件。 您可以使用用戶端來啟動協調流程。 其也可以協助您傳回 HTTP 回應,其中包含 URL,用於檢查新協調流程的狀態。
HttpStart/function.json
{
"scriptFile": "__init__.py",
"bindings": [
{
"authLevel": "anonymous",
"name": "req",
"type": "httpTrigger",
"direction": "in",
"route": "orchestrators/{functionName}",
"methods": [
"post",
"get"
]
},
{
"name": "$return",
"type": "http",
"direction": "out"
},
{
"name": "starter",
"type": "durableClient",
"direction": "in"
}
]
}
若要與協調器互動,函式必須包含 durableClient
輸入繫結。
HttpStart/__init__.py
import logging
import azure.functions as func
import azure.durable_functions as df
async def main(req: func.HttpRequest, starter: str) -> func.HttpResponse:
client = df.DurableOrchestrationClient(starter)
instance_id = await client.start_new(req.route_params["functionName"], None, None)
logging.info(f"Started orchestration with ID = '{instance_id}'.")
return client.create_check_status_response(req, instance_id)
使用 DurableOrchestrationClient
建構函式來取得 Durable Functions 用戶端。 您可以使用用戶端來啟動協調流程。 其也可以協助您傳回 HTTP 回應,其中包含 URL,用於檢查新協調流程的狀態。
執行範例
若要執行 E1_HelloSequence
協調流程,請將下列 HTTP POST 要求傳送至 HttpStart
函式。
POST http://{host}/orchestrators/E1_HelloSequence
注意
先前的 HTTP 程式碼片段假設 host.json
檔案中有一個項目會從所有的 HTTP 觸發程序函式 URL 中移除預設 api/
前置詞。 您可以在範例的 host.json
檔案中找到此組態的標記。
例如,如果您在名為 "myfunctionapp" 的函式應用程式中執行範例,請將 "{host}" 取代為 "myfunctionapp.azurewebsites.net"。
結果會是 HTTP 202 回應,就像這樣 (為了簡潔起見已修剪):
HTTP/1.1 202 Accepted
Content-Length: 719
Content-Type: application/json; charset=utf-8
Location: http://{host}/runtime/webhooks/durabletask/instances/96924899c16d43b08a536de376ac786b?taskHub=DurableFunctionsHub&connection=Storage&code={systemKey}
(...trimmed...)
現在,協調流程已排入佇列,並立即開始執行。 Location
標頭中的 URL 可以用來檢查執行的狀態。
GET http://{host}/runtime/webhooks/durabletask/instances/96924899c16d43b08a536de376ac786b?taskHub=DurableFunctionsHub&connection=Storage&code={systemKey}
結果會是協調流程的狀態。 執行和完成都很快速,您會看到 Completed 狀態,而且回應看起來像這樣 (為了簡潔起見已修剪):
HTTP/1.1 200 OK
Content-Length: 179
Content-Type: application/json; charset=utf-8
{"runtimeStatus":"Completed","input":null,"output":["Hello Tokyo!","Hello Seattle!","Hello London!"],"createdTime":"2017-06-29T05:24:57Z","lastUpdatedTime":"2017-06-29T05:24:59Z"}
如您所見,執行個體的 runtimeStatus
是 Completed ,而 output
包含協調器函式執行的 JSON 序列化結果。
注意
您可以對其他觸發程序類型實作類似的起始邏輯,例如 queueTrigger
、eventHubTrigger
或 timerTrigger
。
查看函式執行記錄。 因為協調流程可靠性 主題中所述的重新執行行為,所以函式已啟動並完成多次。E1_HelloSequence
相反地,E1_SayHello
只執行三次,因為這幾次函式執行不會再來一次。
下一步
此範例已示範簡單的函式鏈結協調流程。 下一個範例會說明如何實作展開傳送/收合傳送模式。