このクイック スタートでは、Azure Developer コマンド ライン ツールを使用して、並列で実行される複数のタスクを調整するサーバーレス ワークフローを構築します。 Azureでリソースを作成し、コードをローカルで検証し、その後、Azure FunctionsのFlex Consumption planで動く新しいサーバーレス関数アプリにデプロイします。
このプロジェクトでは、Azure Developer CLI (azd) を使用して、Azure へのコードのデプロイを簡略化します。 このデプロイは、セキュリティで保護されたスケーラブルなAzure Functions展開に関する現在のベスト プラクティスに従います。 このクイック スタートでは、Durable Functions のファンアウト/ファンイン パターンについて説明します。これは、永続的な実行でステートフル ワークフローを調整する拡張機能です。 サンプルはDurable Task Schedulerを使用しており、これはAzure Storageのバックエンドを置き換えるDurable Functionsの完全管理バックエンドです。 このサンプルは、複数の記事のタイトルを取得して並列に配置します。オーケストレーション機能は、同時に動作している複数のアクティビティに対してこれらのタイトルを分岐させ、その後、元に戻して集約し、結果を集計します。
既定では、Flex 従量課金プランは 従量課金 制の課金モデルに従います。つまり、このクイック スタートを完了すると、Azure アカウントで数 USD セント以下の小さなコストが発生します。
前提条件
アクティブなサブスクリプションを持つ Azure アカウント。 無料でアカウントを作成できます。
プロジェクトを初期化する
azd init コマンドを使用して、テンプレートからローカルの Durable Functions コード プロジェクトを作成します。
ローカル ターミナルまたはコマンド プロンプトで、空のフォルダーで次の
azd initコマンドを実行します。azd init --template durable-functions-quickstart-dotnet-azd -e dfquickstart-dotnetこのコマンドは、template リポジトリからプロジェクト ファイルをプルし、新しいフォルダー内のプロジェクトを初期化します。
-eフラグでは、現在の環境の名前が設定されます。azdでは、環境はアプリの一意のデプロイ コンテキストを維持し、複数を定義できます。 環境名は、Azure で作成するリソース グループの名前にも使用されます。プロジェクトディレクトリに変更し、
fanoutfaninアプリフォルダに移動します。cd durable-functions-quickstart-dotnet-azd/fanoutfanin
ローカル ターミナルまたはコマンド プロンプトで、空のフォルダーで次の
azd initコマンドを実行します。azd init --template durable-functions-quickstart-python-azd -e dfquickstart-pythonこのコマンドは、template リポジトリからプロジェクト ファイルをプルし、新しいフォルダー内のプロジェクトを初期化します。
-eフラグでは、現在の環境の名前が設定されます。azdでは、環境はアプリの一意のデプロイ コンテキストを維持し、複数を定義できます。 環境名は、Azure で作成するリソース グループの名前にも使用されます。プロジェクトディレクトリに変更し、
srcアプリフォルダに移動します。cd durable-functions-quickstart-python-azd/src
ローカル ターミナルまたはコマンド プロンプトで、空のフォルダーで次の
azd initコマンドを実行します。azd init --template durable-functions-quickstart-typescript-azd -e dfquickstart-typescriptこのコマンドは、template リポジトリからプロジェクト ファイルをプルし、新しいフォルダー内のプロジェクトを初期化します。
-eフラグでは、現在の環境の名前が設定されます。azdでは、環境はアプリの一意のデプロイ コンテキストを維持し、複数を定義できます。 環境名は、Azure で作成するリソース グループの名前にも使用されます。プロジェクトディレクトリに変更し、
srcアプリフォルダに移動します。cd durable-functions-quickstart-typescript-azd/src
ローカル ターミナルまたはコマンド プロンプトで、空のフォルダーで次の
azd initコマンドを実行します。azd init --template durable-functions-quickstart-java-azd -e dfquickstart-javaこのコマンドは、template リポジトリからプロジェクト ファイルをプルし、新しいフォルダー内のプロジェクトを初期化します。
-eフラグでは、現在の環境の名前が設定されます。azdでは、環境はアプリの一意のデプロイ コンテキストを維持し、複数を定義できます。 環境名は、Azure で作成するリソース グループの名前にも使用されます。プロジェクト ディレクトリに移動します。
cd durable-functions-quickstart-java-azd
ローカル ターミナルまたはコマンド プロンプトで、空のフォルダーで次の
azd initコマンドを実行します。azd init --template durable-functions-quickstart-javascript-azd -e dfquickstart-javascriptこのコマンドは、template リポジトリからプロジェクト ファイルをプルし、新しいフォルダー内のプロジェクトを初期化します。
-eフラグでは、現在の環境の名前が設定されます。azdでは、環境はアプリの一意のデプロイ コンテキストを維持し、複数を定義できます。 環境名は、Azure で作成するリソース グループの名前にも使用されます。プロジェクトディレクトリに変更し、
srcアプリフォルダに移動します。cd durable-functions-quickstart-javascript-azd/src
ローカル ターミナルまたはコマンド プロンプトで、空のフォルダーで次の
azd initコマンドを実行します。azd init --template durable-functions-quickstart-powershell-azd -e dfquickstart-powershellこのコマンドは、template リポジトリからプロジェクト ファイルをプルし、新しいフォルダー内のプロジェクトを初期化します。
-eフラグでは、現在の環境の名前が設定されます。azdでは、環境はアプリの一意のデプロイ コンテキストを維持し、複数を定義できます。 環境名は、Azure で作成するリソース グループの名前にも使用されます。プロジェクトディレクトリに変更し、
srcアプリフォルダに移動します。cd durable-functions-quickstart-powershell-azd/src
Azure リソースをプロビジョニングする
このプロジェクトでは、azd provisionコマンドを使って必要なAzureリソースを作成し、フレックス消費プラン内の新しい機能アプリ、持続タスクスケジューラ、タスクハブなどを導入します。
ヒント
このプロジェクトには、ベスト プラクティスに従って Flex 従量課金プランへの安全なデプロイを作成するために使用する Bicep ファイルのセット (infra フォルダー内) が含まれています。
ルートプロジェクトフォルダ(
azure.yamlファイルを含むフォルダ)に戻ってください:cd ..
- ルートプロジェクトフォルダ(
azure.yamlファイルを含むフォルダ)にまだいることを確認してください。
このコマンドを実行してAzureアカウントで認証してください:
azd auth loginルートプロジェクトフォルダから次のコマンドを実行し、必要なAzureリソースを作成
azdさせます:azd provisionルート フォルダーには、
azure.yamlに必要なazd定義ファイルが含まれています。プロンプトが表示されたら、次の必須のデプロイ パラメーターを指定します。
パラメーター Description Azure サブスクリプション リソースが作成されるサブスクリプション。 アカウントに複数のテナントがある場合は、まずテナントを選ばなければなりません。 Azure リージョン 新しい Azure リソースを含むリソース グループを作成する Azure リージョン。 Flex 従量課金プランを現在サポートしているリージョンのみが表示されます。 vnetEnabled 仮想ネットワークに展開するかどうか。 このクイックスタートでは、 falseを選択してください。 azd provisionコマンドは、これらのプロンプトに対する応答とBicep設定ファイルを使って、必要なAzureリソースを作成・設定します。- Flex 従量課金プランと関数アプリ
- Azure Storage (必須) と Application Insights (推奨)
- 耐久タスクスケジューラとタスクハブ
- アカウントのアクセス ポリシーと役割
- マネージド ID を使用したサービス間接続 (格納されている接続文字列の代わりに)
コマンドが正常に完了した後、作成したリソースへのリンクが表示されます。
プロビジョニングはまた、プロビジョニング後スクリプトを実行し、アプリフォルダ内に local.settings.json ファイルを生成します。 このファイルには、プロジェクトをローカルで実行するために必要な、デプロイ済みのDurable Task Schedulerエンドポイントの接続設定が含まれています。
Azurite を起動する
プロジェクトをローカルで実行するには、Functionsランタイムにローカルストレージエミュレーターが必要です。 local.settings.json ファイルの "AzureWebJobsStorage": "UseDevelopmentStorage=true" 設定は、この目的のためにランタイムにAzuriteを使用するよう指示しています。
新しいターミナルウィンドウで、Azuriteを起動するために次のコマンドを実行します:
azurite --skipApiVersionCheck --location ~/azurite-data
ローカルテスト中はこのターミナルウィンドウでAzuriteを稼働させ続けてください。
ローカル環境で実行する
元の端末で
fanoutfaninアプリフォルダに行き、Functionsホストを起動します:cd fanoutfanin func startFunctions ホストは、ローカル プロジェクト フォルダーで起動すると、HTTP によってトリガーされる関数のローカル URL エンドポイントをターミナル出力に書き込みます。
Note
ローカルで実行する場合、アクセス キーの承認は適用されないため、関数を呼び出すためにアクセス キーは必要ありません。
ブラウザーで、オーケストレーションを開始するエンドポイントに対して GET 要求を行います。
http://localhost:7071/api/FetchOrchestration_HttpStart
この要求は、新しいオーケストレーション インスタンスを開始します。 オーケストレーション機能は、複数のアクティビティに分岐させ、Microsoft Learn 記事のタイトルを取得して並列に配置します。 アクティビティが完了すると、オーケストレーション機能は元に戻して集約します。また、複数のタイトルを、書式設定された文字列として返します。
元の端末で
srcアプリフォルダにアクセスし、仮想環境を作成・有効化し、依存関係をインストールしてFunctionsホストを起動します:cd src仮想環境(
.venvと名付けられた)を作成・起動する方法は、端末によって異なります:python3 -m venv .venv source .venv/bin/activate pip install -r requirements.txt func startFunctions ホストは、ローカル プロジェクト フォルダーで起動すると、HTTP によってトリガーされる関数のローカル URL エンドポイントをターミナル出力に書き込みます。
Note
ローカルで実行する場合、アクセス キーの承認は適用されないため、関数を呼び出すためにアクセス キーは必要ありません。
ブラウザーで、HTTP 開始エンドポイントに対して GET 要求を行います。
http://localhost:7071/api/orchestrators/fetch_orchestration
この要求は、新しいオーケストレーション インスタンスを開始します。 オーケストレーション機能は、複数のアクティビティに分岐させ、Microsoft Learn 記事のタイトルを取得して並列に配置します。 アクティビティが完了すると、オーケストレーション機能は元に戻して集約します。また、複数のタイトルを、書式設定された文字列として返します。
元の端末で
srcアプリフォルダにアクセスし、依存関係をインストールし、プロジェクトを構築し、Functionsホストを起動します:cd src npm install npm run build func startFunctions ホストは、ローカル プロジェクト フォルダーで起動すると、HTTP によってトリガーされる関数のローカル URL エンドポイントをターミナル出力に書き込みます。
Note
ローカルで実行する場合、アクセス キーの承認は適用されないため、関数を呼び出すためにアクセス キーは必要ありません。
ブラウザーで、HTTP 開始エンドポイントに対して GET 要求を行います。
http://localhost:7071/api/orchestrators/fetchOrchestration
この要求は、新しいオーケストレーション インスタンスを開始します。 オーケストレーション機能は、複数のアクティビティに分岐させ、Microsoft Learn 記事のタイトルを取得して並列に配置します。 アクティビティが完了すると、オーケストレーション機能は元に戻して集約します。また、複数のタイトルを、書式設定された文字列として返します。
元のターミナルでプロジェクトを構築し、ビルド出力フォルダからFunctionsホストを起動します:
mvn clean package cd target/azure-functions/durable-functions-quickstart func startFunctions ホストは、ローカル プロジェクト フォルダーで起動すると、HTTP によってトリガーされる関数のローカル URL エンドポイントをターミナル出力に書き込みます。
Note
ローカルで実行する場合、アクセス キーの承認は適用されないため、関数を呼び出すためにアクセス キーは必要ありません。
ブラウザーで、オーケストレーションを開始するエンドポイントに対して GET 要求を行います。
http://localhost:7071/api/FetchOrchestration_HttpStart
この要求は、新しいオーケストレーション インスタンスを開始します。 オーケストレーション機能は、複数のアクティビティに分岐させ、Microsoft Learn 記事のタイトルを取得して並列に配置します。 アクティビティが完了すると、オーケストレーション機能は元に戻して集約します。また、複数のタイトルを、書式設定された文字列として返します。
元の端末で
srcアプリフォルダに行き、依存関係をインストールし、Functionsホストを起動します:cd src npm install func startFunctions ホストは、ローカル プロジェクト フォルダーで起動すると、HTTP によってトリガーされる関数のローカル URL エンドポイントをターミナル出力に書き込みます。
Note
ローカルで実行する場合、アクセス キーの承認は適用されないため、関数を呼び出すためにアクセス キーは必要ありません。
ブラウザーで、オーケストレーションを開始するエンドポイントに対して GET 要求を行います。
http://localhost:7071/api/FetchOrchestration_HttpStart
この要求は、新しいオーケストレーション インスタンスを開始します。 オーケストレーション機能は、複数のアクティビティに分岐させ、Microsoft Learn 記事のタイトルを取得して並列に配置します。 アクティビティが完了すると、オーケストレーション機能は元に戻して集約します。また、複数のタイトルを、書式設定された文字列として返します。
元の端末で
srcアプリフォルダに行き、Functionsホストを起動します:cd src func startFunctions ホストは、ローカル プロジェクト フォルダーで起動すると、HTTP によってトリガーされる関数のローカル URL エンドポイントをターミナル出力に書き込みます。
Note
ローカルで実行する場合、アクセス キーの承認は適用されないため、関数を呼び出すためにアクセス キーは必要ありません。
ブラウザーで、オーケストレーションを開始するエンドポイントに対して GET 要求を行います。
http://localhost:7071/api/FetchOrchestration_HttpStart
この要求は、新しいオーケストレーション インスタンスを開始します。 オーケストレーション機能は、複数のアクティビティに分岐させ、Microsoft Learn 記事のタイトルを取得して並列に配置します。 アクティビティが完了すると、オーケストレーション機能は元に戻して集約します。また、複数のタイトルを、書式設定された文字列として返します。
HTTP エンドポイントは、複数の URL を含む JSON 応答を返します。
statusQueryGetUriエンドポイントは、オーケストレーションの状態を提供します。statusQueryGetUri値をコピーし、ブラウザーまたは HTTP テスト ツールに貼り付けてオーケストレーションの状態を確認します。 オーケストレーションが完了すると、取得された記事のタイトルが応答に表示されます。完了したら、ターミナル ウィンドウで Ctrl + C キーを押して、
funcホスト プロセスを停止します。
-
deactivateを実行して仮想環境をシャットダウンします。
コードの確認 (省略可能)
ファンアウト/ファンイン パターンを実装するコードを確認できます。
タイトル フェッチ アクティビティは、動的タスク リストを使用して追跡されます。 行 await Task.WhenAll(parallelTasks); は、同時に実行されるすべての呼び出されたアクティビティが完了するまで待機します。 完了すると、すべての出力が書式設定された文字列として集計されます。
[Function(nameof(FetchOrchestration))]
public static async Task<string> RunOrchestrator(
[OrchestrationTrigger] TaskOrchestrationContext context)
{
ILogger logger = context.CreateReplaySafeLogger(nameof(FetchOrchestration));
logger.LogInformation("Fetching data.");
var parallelTasks = new List<Task<string>>();
// List of URLs to fetch titles from
var urls = new List<string>
{
"https://learn.microsoft.com/azure/azure-functions/durable/durable-functions-overview",
"https://learn.microsoft.com/azure/azure-functions/durable/durable-task-scheduler/durable-task-scheduler",
"https://learn.microsoft.com/azure/azure-functions/functions-scenarios",
"https://learn.microsoft.com/azure/azure-functions/functions-create-ai-enabled-apps",
};
// Run fetching tasks in parallel
foreach (var url in urls)
{
Task<string> task = context.CallActivityAsync<string>(nameof(FetchTitleAsync), url);
parallelTasks.Add(task);
}
// Wait for all the parallel tasks to complete before continuing
await Task.WhenAll(parallelTasks);
// Return fetched titles as a formatted string
return string.Join("; ", parallelTasks.Select(t => t.Result));
}
完全なテンプレート プロジェクト は、ここで確認できます。
タイトル フェッチ アクティビティは、動的タスク リストを使用して追跡されます。 行 yield context.task_all(tasks) は、同時に実行されるすべての呼び出されたアクティビティが完了するまで待機します。 完了すると、すべての出力が書式設定された文字列として集計されます。
# List of URLs to fetch titles from
urls = [
"https://learn.microsoft.com/azure/azure-functions/durable/durable-functions-overview",
"https://learn.microsoft.com/azure/azure-functions/durable/durable-task-scheduler/durable-task-scheduler",
"https://learn.microsoft.com/azure/azure-functions/functions-scenarios",
"https://learn.microsoft.com/azure/azure-functions/functions-create-ai-enabled-apps",
]
# Run fetching tasks in parallel
tasks = []
for url in urls:
task = context.call_activity("fetch_title", url)
tasks.append(task)
# Wait for all the parallel tasks to complete before continuing
results = yield context.task_all(tasks)
# Return fetched titles as a formatted string
return "; ".join(results)
@myApp.activity_trigger(input_name="url")
async def fetch_title(url: str):
"""Activity function that fetches the title from a URL."""
logger = logging.getLogger("FetchTitle")
logger.info(f"Fetching from url {url}.")
try:
async with ClientSession() as session:
完全なテンプレート プロジェクト は、ここで確認できます。
タイトル フェッチ アクティビティは、動的タスク リストを使用して追跡されます。 行 yield context.df.Task.all(parallelTasks) は、同時に実行されるすべての呼び出されたアクティビティが完了するまで待機します。 完了すると、すべての出力が書式設定された文字列として集計されます。
const urls = [
"https://learn.microsoft.com/azure/azure-functions/durable/durable-functions-overview",
"https://learn.microsoft.com/azure/azure-functions/durable/durable-task-scheduler/durable-task-scheduler",
"https://learn.microsoft.com/azure/azure-functions/functions-scenarios",
"https://learn.microsoft.com/azure/azure-functions/functions-create-ai-enabled-apps",
];
// Run fetching tasks in parallel
const parallelTasks = [];
for (const url of urls) {
const task = context.df.callActivity(fetchTitleActivityName, url);
parallelTasks.push(task);
}
// Wait for all the parallel tasks to complete before continuing
const results: string[] = yield context.df.Task.all(parallelTasks);
// Return fetched titles as a formatted string
return results.join("; ");
};
df.app.orchestration("fetchOrchestration", fetchOrchestration);
const fetchTitleAsync: ActivityHandler = async function (
url: string,
context: InvocationContext
完全なテンプレート プロジェクト は、ここで確認できます。
タイトル フェッチ アクティビティは、動的タスク リストを使用して追跡されます。 行 ctx.allOf(parallelTasks).await() は、同時に実行されるすべての呼び出されたアクティビティが完了するまで待機します。 完了すると、すべての出力が書式設定された文字列として集計されます。
@FunctionName("FetchOrchestration")
public String runOrchestrator(
@DurableOrchestrationTrigger(name = "taskOrchestrationContext") TaskOrchestrationContext ctx) {
List<String> urls = List.of(
"https://learn.microsoft.com/azure/azure-functions/durable/durable-functions-overview",
"https://learn.microsoft.com/azure/azure-functions/durable/durable-task-scheduler/durable-task-scheduler",
"https://learn.microsoft.com/azure/azure-functions/functions-scenarios",
"https://learn.microsoft.com/azure/azure-functions/functions-create-ai-enabled-apps"
);
// Fan out: run fetching tasks in parallel
List<Task<String>> parallelTasks = urls.stream()
.map(url -> ctx.callActivity("FetchTitle", url, String.class))
.collect(Collectors.toList());
// Fan in: wait for all parallel tasks to complete
List<String> results = ctx.allOf(parallelTasks).await();
// Return fetched titles as a formatted string
return String.join("; ", results);
}
完全なテンプレート プロジェクト は、ここで確認できます。
タイトル フェッチ アクティビティは、動的タスク リストを使用して追跡されます。 行 yield context.df.Task.all(parallelTasks) は、同時に実行されるすべての呼び出されたアクティビティが完了するまで待機します。 完了すると、すべての出力が書式設定された文字列として集計されます。
df.app.orchestration('fetchOrchestration', function* (context) {
context.log("Fetching data.");
const urls = [
"https://learn.microsoft.com/azure/azure-functions/durable/durable-functions-overview",
"https://learn.microsoft.com/azure/azure-functions/durable/durable-task-scheduler/durable-task-scheduler",
"https://learn.microsoft.com/azure/azure-functions/functions-scenarios",
"https://learn.microsoft.com/azure/azure-functions/functions-create-ai-enabled-apps",
];
// Fan out: run fetching tasks in parallel
const parallelTasks = urls.map(url => context.df.callActivity(activityName, url));
// Fan in: wait for all parallel tasks to complete
const results = yield context.df.Task.all(parallelTasks);
// Return fetched titles as a formatted string
return results.join("; ");
});
完全なテンプレート プロジェクト は、ここで確認できます。
タイトル フェッチ アクティビティは、動的タスク リストを使用して追跡されます。 行 Wait-ActivityFunction -Task $parallelTasks は、同時に実行されるすべての呼び出されたアクティビティが完了するまで待機します。 完了すると、すべての出力が書式設定された文字列として集計されます。
param($Context)
$urls = @(
"https://learn.microsoft.com/azure/azure-functions/durable/durable-functions-overview",
"https://learn.microsoft.com/azure/azure-functions/durable/durable-task-scheduler/durable-task-scheduler",
"https://learn.microsoft.com/azure/azure-functions/functions-scenarios",
"https://learn.microsoft.com/azure/azure-functions/functions-create-ai-enabled-apps"
)
# Fan out: run fetching tasks in parallel
$parallelTasks = @()
foreach ($url in $urls) {
$parallelTasks += Invoke-DurableActivity -FunctionName 'FetchTitle' -Input $url -NoWait
}
# Fan in: wait for all parallel tasks to complete
$results = Wait-ActivityFunction -Task $parallelTasks
# Return fetched titles as a formatted string
$output = $results -join "; "
$output
完全なテンプレート プロジェクト は、ここで確認できます。
ローカルで機能の検証が終わったら、次はAzureにデプロイする時です。
Azure にデプロイ
rootプロジェクトフォルダからこのコマンドを実行して、Azureの関数アプリにコードプロジェクトをデプロイしてください:
azd deploy
azd deployコマンドは、プロビジョニング中に作成された関数アプリにコードをパッケージ化し、デプロイします。 コマンドが完了すると、アプリは起動し、デプロイされたパッケージ内で実行されます。
Azureで関数を呼び出す
URL への HTTP 要求を行うことで、Azure でオーケストレーション エンドポイントを呼び出すようになりました。 関数が Azure で実行されると、アクセス キーの承認が適用され、要求に関数アクセス キーを指定する必要があります。
Core Tools を使用して、Azure でオーケストレーションを開始する HTTP トリガーの URL エンドポイントを取得できます。
ローカル ターミナルまたはコマンド プロンプトで、次のコマンドを実行して URL エンドポイント値を取得します。
APP_NAME=$(azd env get-value AZURE_FUNCTION_NAME) func azure functionapp list-functions $APP_NAME --show-keysazd env get-valueコマンドでは、ローカル環境から関数アプリ名が取得されます。--show-keysでfunc azure functionapp list-functionsオプションを使用すると、返される呼び出し URL: 各エンドポイントの値には、必要な関数レベルのアクセス キーが含まれます。ブラウザやHTTPテストツールを使って、Azureで動作する関数アプリのオーケストレーションを開始するために、HTTP STARTエンドポイントにGETリクエストを送りましょう。
コードを再デプロイする
関数アプリにコードアップデートをデプロイするために必要なだけ azd deploy 実行してください。 Azureリソースを更新する必要がある場合は、再度azd provisionを実行してください。
Note
最新のデプロイ パッケージは、常にデプロイされたコード ファイルを上書きします。
azd プロンプトに対する最初の応答と、azd によって生成された環境変数は、名前付き環境にローカルに格納されます。
azd env get-values コマンドを使用して、Azure リソースの作成時に使用した環境内のすべての変数を確認します。
リソースをクリーンアップする
関数アプリと関連リソースの操作が完了したら、次のコマンドを使用して関数アプリとその関連リソースを Azure から削除し、それ以上のコストが発生しないようにします。
azd down --no-prompt
Note
--no-prompt オプションは、確認なしでリソース グループを削除するように azd に指示します。
このコマンドは、ローカル コード プロジェクトには影響しません。