SlideShare a Scribd company logo
サーバーレスの常識を覆す
Azure Durable Functionsを使い倒す
2018/08/22 Serverless Meetup Fukuoka #2
@tsubakimoto_s
松村優大 (MLBお兄さん)
• 株式会社オルターブース
• Microsoft MVP
(Developer Technologies)
• C#/PHP/Azure/AWS
• 島根県出身 3031歳
2
本日の内容
• Serverless Services on Microsoft Azure
• Azure Durable Functions
• デモ
3
Serverless Services on
Microsoft Azure
https://azure.microsoft.com/ja-jp/overview/serverless-computing/
https://azure.microsoft.com/ja-jp/campaigns/serverless/
4
5https://www.youtube.com/watch?v=cOFlSvnupQM
6
Azure Functions
Logic Apps
Event Grid
7
Platform as a Service
アプリケーション
コード
ロジック
トリガー
Azure
Functions
8
イベントドリブン型のコードを実行でき
るサービス。従来のホスティングプラン
の他、実行時間・実行回数に対する従量
課金プランが提供されている。
Webhookをはじめ、Microsoft Azure、
Microsoft Graph、サードパーティの
サービスと連携することができる。
Language Runtime v1.x Runtime v2.x
C# GA Preview
Node.js GA Preview
F# GA -
Java - Preview
Python Experimental -
PHP Experimental -
TypeScript Experimental -
.cmd, .bat Experimental -
Bash Experimental -
PowerShell Experimental -
9
Language Runtime v1.x Runtime v2.x
C# GA Preview
Node.js GA Preview
F# GA -
Java - Preview
Python Experimental -
PHP Experimental -
TypeScript Experimental -
.cmd, .bat Experimental -
Bash Experimental -
PowerShell Experimental -
10
仕様変更もある
通常のFunctionsの実装
11
トリガー(入力)
バインド(出力)
単一処理の軽量な
コードが望ましい
Azure Durable Functions
The primary use case for Durable Functions is
simplifying complex, stateful coordination problems
in serverless applications.
12
【de:code 2018】AD02 Serverless の世界を進化させるイノベーション - Durable Functions
https://youtu.be/QuXO5plBiFM
Visual Studio
• Visual Studio 15.3~
• Azure開発のワークロード
• Azure Storage Emulator
• 拡張機能
Microsoft.Azure.WebJobs.Extensions.DurableTask
• C#での開発に適している
13https://docs.microsoft.com/ja-jp/azure/azure-functions/durable-functions-install
Visual Studio Code
• Azure Functions Core Tools 2.x
• Azure Storage Emulator
• 拡張機能
Microsoft.Azure.WebJobs.Extensions.DurableTask
• C#, Node.jsでの開発に適している
14https://docs.microsoft.com/ja-jp/azure/azure-functions/durable-functions-install
Durable Functions Pattern
1. 関数チェーン
2. ファンアウト/ファンイン
3. 非同期のHTTP API
4. 監視
5. 人による操作
15https://docs.microsoft.com/ja-jp/azure/azure-functions/durable-functions-overview
パターン1 : 関数チェーン
16
本来、Queueでつないで連鎖する一連の
関数を、Queueなしで実行できる機能。
ドキュメントのサンプルでは動かない
17
Durable Functionsの仕組み
• クライアント関数(OrchestrationClientAttribute)
• 関数全体の実行トリガーとなる
• オーケストレーター関数(OrchestrationTriggerAttribute)
• アクティビティ関数を呼出し、結果の受取を行う
• アクティビティ関数(ActivityTriggerAttribute)
• 実際の処理を行う作業単位
18
19
[FunctionName("F1")]
public static async Task<HttpResponseMessage> HttpStart(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")]HttpRequestMessage req,
[OrchestrationClient]DurableOrchestrationClient starter,
ILogger log)
{
string instanceId = await starter.StartNewAsync("F2", null);
log.LogInformation($"Started orchestration with ID = '{instanceId}'.");
return starter.CreateCheckStatusResponse(req, instanceId);
}
[FunctionName("F2")]
public static async Task<List<string>> RunOrchestrator(
[OrchestrationTrigger] DurableOrchestrationContext context)
{
var outputs = new List<string>();
outputs.Add(await context.CallActivityAsync<string>("F3", "Tokyo"));
outputs.Add(await context.CallActivityAsync<string>("F3", "Osaka"));
outputs.Add(await context.CallActivityAsync<string>("F3", "Fukuoka"));
return outputs;
}
[FunctionName("F3")]
public static string SayHello([ActivityTrigger] string name, ILogger log)
{
log.LogInformation($"Saying hello to {name}.");
return $"Hello {name}!";
}
クライアント関数
オーケストレーター関数
アクティビティ関数
パターン2 : ファンアウト/ファンイン
20
複数の関数を並列に実行してすべてが
完了するまで待機するパターン。
パターン3 : 非同期のHTTP API
21
長時間実行する関数の“状態”を取得する
ためのAPIを公開する。
Durable FunctionsのAPIレスポンス(JSON)
項目 説明
id
オーケストレーションインスタンス
の ID
statusQueryGetUri
オーケストレーションインスタンス
の状態を取得するURL
sendEventPostUri
オーケストレーションインスタンス
のイベントを発生させるURL
terminatePostUri
オーケストレーションインスタンス
を終了させるURL
22
例
23
{
"id": "2b729f0beb2c44358a9f1c2a75197322",
"statusQueryGetUri":
"http://localhost:7071/runtime/webhooks/DurableTaskExte
nsion/instances/2b729f0beb2c44358a9f1c2a75197322?taskHu
b=DurableFunctionsHub&connection=Storage&code=2bYl3HewP
In8QZMTYiPA0ifHuJ6WSR/t38v1923ru8S8LzbXFNaaCg==", ...
}
statusQueryGetUri (待機中)
24
{
"instanceId": "2b729f0beb2c44358a9f1c2a75197322",
"runtimeStatus": "Pending",
"input": null,
"customStatus": null,
"output": null,
"createdTime": "2018-08-15T20:58:47Z",
"lastUpdatedTime": "2018-08-15T20:58:47Z"
}
statusQueryGetUri (実行中)
25
{
"instanceId": "2b729f0beb2c44358a9f1c2a75197322",
"runtimeStatus": "Running",
"input": null,
"customStatus": null,
"output": null,
"createdTime": "2018-08-15T20:58:47Z",
"lastUpdatedTime": "2018-08-15T20:58:48Z"
}
statusQueryGetUri (完了)
26
{
"instanceId": "2b729f0beb2c44358a9f1c2a75197322",
"runtimeStatus": "Completed",
"input": null,
"customStatus": null,
"output": [
"Hello Tokyo!", "Hello Seattle!", "Hello London!"
],
"createdTime": "2018-08-15T20:58:47Z",
"lastUpdatedTime": "2018-08-15T20:59:01Z"
}
パターン4 : 監視
27
外部の関数を監視し、関数の状態によっ
て後続の処理を変える。
パターン5 : 人による操作
28
イベントが呼び出されるまで関数の実行
を止める。
例)上司の承認が必要なワークフロー
29
[FunctionName("Approval_Run")]
public static async Task RunOrchestrator(
[OrchestrationTrigger] DurableOrchestrationContext context)
{
bool approved = await context.WaitForExternalEvent<bool>("Approval");
if (approved) { /* approval granted */ }
else { /* approval denied */ }
}
[FunctionName("Approval_Request")]
public static async Task RequestApproval(
[QueueTrigger("approval-queue")] string instanceId,
[OrchestrationClient]DurableOrchestrationClient client)
{
await client.RaiseEventAsync(instanceId, "Approval", true);
}
オーケストレーター関数
外部イベント関数
30
[FunctionName("Approval_Run")]
public static async Task RunOrchestrator(
[OrchestrationTrigger] DurableOrchestrationContext context)
{
bool approved = await context.WaitForExternalEvent<bool>("Approval");
if (approved) { /* approval granted */ }
else { /* approval denied */ }
}
[FunctionName("Approval_Request")]
public static async Task RequestApproval(
[QueueTrigger("approval-queue")] string instanceId,
[OrchestrationClient]DurableOrchestrationClient client)
{
await client.RaiseEventAsync(instanceId, "Approval", true);
}
ここで処理が止まり
“Approval”という
イベント呼出しを待つ
31
[FunctionName("Approval_Run")]
public static async Task RunOrchestrator(
[OrchestrationTrigger] DurableOrchestrationContext context)
{
bool approved = await context.WaitForExternalEvent<bool>("Approval");
if (approved) { /* approval granted */ }
else { /* approval denied */ }
}
[FunctionName("Approval_Request")]
public static async Task RequestApproval(
[QueueTrigger("approval-queue")] string instanceId,
[OrchestrationClient]DurableOrchestrationClient client)
{
await client.RaiseEventAsync(instanceId, "Approval", true);
}
キューにインスタンスID
をセットする
32
[FunctionName("Approval_Run")]
public static async Task RunOrchestrator(
[OrchestrationTrigger] DurableOrchestrationContext context)
{
bool approved = await context.WaitForExternalEvent<bool>("Approval");
if (approved) { /* approval granted */ }
else { /* approval denied */ }
}
[FunctionName("Approval_Request")]
public static async Task RequestApproval(
[QueueTrigger("approval-queue")] string instanceId,
[OrchestrationClient]DurableOrchestrationClient client)
{
await client.RaiseEventAsync(instanceId, "Approval", true);
}
指定したインスタンスIDの
“Approval”イベントを呼出す
33
[FunctionName("Approval_Run")]
public static async Task RunOrchestrator(
[OrchestrationTrigger] DurableOrchestrationContext context)
{
bool approved = await context.WaitForExternalEvent<bool>("Approval");
if (approved) { /* approval granted */ }
else { /* approval denied */ }
}
[FunctionName("Approval_Request")]
public static async Task RequestApproval(
[QueueTrigger("approval-queue")] string instanceId,
[OrchestrationClient]DurableOrchestrationClient client)
{
await client.RaiseEventAsync(instanceId, "Approval", true);
}
イベントの結果を受けて
後続の処理を実行
34
[FunctionName("Approval_Run")]
public static async Task RunOrchestrator(
[OrchestrationTrigger] DurableOrchestrationContext context)
{
bool approved = await context.WaitForExternalEvent<bool>("Approval");
if (approved) { /* approval granted */ }
else { /* approval denied */ }
}
[FunctionName("Approval_Request")]
public static async Task RequestApproval(
[QueueTrigger("approval-queue")] string instanceId,
[OrchestrationClient]DurableOrchestrationClient client)
{
await client.RaiseEventAsync(instanceId, "Approval", true);
}
文字列やオブジェクトを
渡すことも可能
価格モデル
• App Serviceプラン
• 使用するリソースに対する課金
• 常時接続可能(AlwaysOn)
• 従量課金プラン
• 関数の実行時間と実行回数に対する課金
• 無料枠あり
• Cold Startやオートスケールの考慮が必要
35
36
[FunctionName("Approval_Run")]
public static async Task RunOrchestrator(
[OrchestrationTrigger] DurableOrchestrationContext context)
{
bool approved = await context.WaitForExternalEvent<bool>("Approval");
if (approved) { /* approval granted */ }
else { /* approval denied */ }
}
ここで処理が止まり
“Approval”という
イベント呼出しを待つ
待機中の時間(=イベントが呼び出されるまで)は課金対象になる?
課金対象にならない
デモ
https://github.com/tsubakimoto/serverless-meetup-fukuoka-v2
37
38
Application
Insights
Azure Functions
Blob
Storage
SlackWeb Browser 上司の承認 結果の通知
私が思う アンチパターン
39
if
条件1 条件2 条件3 条件4 条件5
output1 output2 output3 output4 output5
トリガー
ひとつのFunctionで複数の出力を行うやつ
40
output output output output output
単処理になるように分解する
宣伝
41
42
43
44
https://fukuten.connpass.com/event/95744/
ご清聴ありがとうございました
45

More Related Content

サーバーレスの常識を覆す Azure Durable Functionsを使い倒す