イベント ドリブンのバックグラウンド処理に Azure WebJobs SDK を使用する方法
この記事は、Azure WebJobs SDK を使用する方法のガイダンスを提供します。 WebJobs をすぐに使い始めたい場合は、「Azure WebJobs SDK の概要」をご覧ください。
WebJobs SDK のバージョン
WebJobs SDK のバージョン 3.x とバージョン 2.x には、重要な違いがあります。
- バージョン 3.x では、.NET Core のサポートが追加されています。
- バージョン 3.x では、WebJobs SDK で必要となるストレージ バインディング拡張機能をインストールします。 バージョン 2.x では、ストレージのバインドは SDK に含まれています。
- .NET Core (3.x) プロジェクト用の Visual Studio 2019 のツールは、.NET Framework (2.x) プロジェクト用のツールと異なります。 詳しくは、「Visual Studio を使用して Web ジョブを開発してデプロイする - Azure App Service」をご覧ください。
この記事では、WebJobs バージョン 3.x および WebJobs バージョン 2.x の両方のバージョンの例について説明します。
Azure Functions は WebJobs SDK 上に構築されています。
- Azure Functions バージョン 2.x は、WebJobs SDK バージョン 3.x 上に構築されています。
- Azure Functions バージョン 1.x は、WebJobs SDK バージョン 2.x 上に構築されています。
Azure Functions と WebJobs SDK の両方のソース コード リポジトリでは、WebJobs SDK の番号付けが使用されます。 このハウツー記事のいくつかのセクションは、Azure Functions ドキュメントにリンクしています。
詳しくは、WebJobs SDK と Azure Functions の比較に関するページをご覧ください。
WebJobs ホスト
このホストは、関数のランタイム コンテナーです。 このホストは、トリガーをリッスンして関数を呼び出します。 バージョン 3.x では、ホストは IHost
の実装です。 バージョン 2.x では、JobHost
オブジェクトを使用します。 コードでホスト インスタンスを作成し、その動作をカスタマイズするコードを書きます。
これが、直接 WebJobs SDK を使用することと、Azure Functions によって間接的に使用することの主な違いです。 Azure Functions では、サービスがホストを制御するので、コードを書いてホストをカスタマイズすることはできません。 Azure Functions では、host.json ファイルの設定を使用してホスト動作をカスタマイズできます。 これらの設定はコードではなく文字列なので、これらの文字列の使用によって、実行できるカスタマイズの種類が制限されます。
ホスト接続
WebJobs SDK では、Azure Storage と Azure Service Bus の接続は、ローカルで実行するときは local.settings.json ファイルで検索され、Azure で実行するときは WebJob の環境で検索されます。 既定では、WebJobs SDK には AzureWebJobsStorage
という名前のストレージ接続が必要です。
接続名が 1 つの正確な値に解決されると、ランタイムでは、値を接続文字列として識別します。これには通常、シークレットが含まれます。 接続文字列の詳細は、接続先のサービスによって異なります。 ただし、接続名は、複数の構成アイテムのコレクションを参照することもできます。これは、ID ベースの接続を構成する場合に役立ちます。 2 つのアンダースコア __
で終わる共有プレフィックスを使用して、環境変数をコレクションとして扱うことができます。 このプレフィックスに接続名を設定することによって、グループを参照できます。
たとえば、Azure Blob トリガー定義の connection
プロパティが Storage1
であるとします。 Storage1
という名前の環境変数で構成された単一の文字列値がない限り、Storage1__blobServiceUri
という名前の環境変数を使用して、接続の blobServiceUri
プロパティを通知できます。 接続のプロパティはサービスによって異なります。 接続を使用するコンポーネントのドキュメントを参照してください。
ID ベースの接続
WebJobs SDK で ID ベースの接続を使用するには、プロジェクトで最新バージョンの WebJobs パッケージを使用していることを確認します。 また、Microsoft.Azure.WebJobs.Host.Storage への参照があることを確認する必要があります。 以下は、これらの更新を行った後にプロジェクト ファイルがどのようになるかの例です。
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net48</TargetFramework>
<IsWebJobProject>true</IsWebJobProject>
<WebJobName>$(AssemblyName)</WebJobName>
<WebJobType>Continuous</WebJobType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Azure.WebJobs" Version="3.0.41" />
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.Storage.Queues" Version="5.3.1" />
<PackageReference Include="Microsoft.Azure.WebJobs.Host.Storage" Version="5.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="2.1.1" />
</ItemGroup>
<ItemGroup>
<None Update="appsettings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
HostBuilder 内で WebJobs を設定するときは、AddAzureStorageCoreServices
への呼び出しを必ず含めるようにしてください。これは、AzureWebJobsStorage
およびその他のストレージ トリガーとバインドで ID を使用できるようにするためです:
builder.ConfigureWebJobs(b =>
{
b.AddAzureStorageCoreServices();
// other configurations...
});
次に、環境変数 (または App Service でホストされている場合はアプリケーション設定) を設定して、AzureWebJobsStorage
接続を構成できます:
環境変数 | 説明 | 値の例 |
---|---|---|
AzureWebJobsStorage__blobServiceUri |
HTTPS スキームを使用する、ストレージ アカウントの BLOB サービスのデータ プレーン URI。 | https://<storage_account_name>.blob.core.windows.net |
AzureWebJobsStorage__queueServiceUri |
HTTPS スキームを使用する、ストレージ アカウントのキュー サービスのデータ プレーン URI。 | https://<storage_account_name>.queue.core.windows.net |
appsettings.json
など、環境変数以外の方法で構成を指定する場合は、代わりに接続とそのプロパティの構造化構成を指定する必要があります:
{
"AzureWebJobsStorage": {
"blobServiceUri": "https://<storage_account_name>.blob.core.windows.net",
"queueServiceUri": "https://<storage_account_name>.queue.core.windows.net"
}
}
BLOB トリガーを使用する予定がない場合は、queueServiceUri
プロパティを省略できます。
コードをローカルで実行すると、DefaultAzureCredential で記述されている動作に従って開発者 ID が既定で使用されます。
コードが Azure App Service でホストされている場合、上記の構成は既定でリソースの システム割り当てマネージド ID になります。 代わりに、アプリに割り当てられている ユーザー割り当て ID を使用するには、使用する ID を指定する接続のプロパティを追加する必要があります。 credential
プロパティ (環境変数として AzureWebJobsStorage__credential
) は、文字列 "managedidentity" に設定する必要があります。 clientId
プロパティ (環境変数として AzureWebJobsStorage__clientId
) は、使用するユーザー割り当てマネージド ID のクライアント ID に設定する必要があります。 構造化された構成として、完全なオブジェクトは次のようになります:
{
"AzureWebJobsStorage": {
"blobServiceUri": "https://<storage_account_name>.blob.core.windows.net",
"queueServiceUri": "https://<storage_account_name>.queue.core.windows.net",
"credential": "managedidentity",
"clientId": "<user-assigned-identity-client-id>"
}
}
AzureWebJobsStorage
に使用される ID には、ストレージ BLOB データ所有者、ストレージ キュー データ共同作成者、およびストレージ アカウント共同作成者 ロールを付与するロールの割り当てが必要です。 BLOB トリガーを使用する予定がない場合は、ストレージ キュー データ共同作成者 と ストレージ アカウント共同作成者 の両方を省略できます。
次の表は、通常の操作でバインドでトリガーを使用する場合に推奨される組み込みロールを示しています。 アプリケーションでは、記述したコードに基づいて追加のアクセス許可が必要になる場合があります。
バインド | 組み込みロールの例 |
---|---|
BLOB トリガー | ストレージ BLOB データ所有者およびストレージ キュー データ共同作成者AzureWebJobsStorage の要件についても、上記を参照してください。 |
BLOB (入力) | ストレージ BLOB データ閲覧者 |
BLOB (出力) | ストレージ BLOB データ所有者 |
キュー トリガー | ストレージ キュー データ閲覧者、ストレージ キュー データのメッセージ プロセッサ |
キュー (出力) | ストレージ キュー データ共同作成者、ストレージ キュー データのメッセージ送信者 |
Service Bus トリガー1 | Azure Service Bus データ受信者、Azure Service Bus データ所有者 |
Service Bus (出力) | Azure Service Bus データ送信者 |
1 Service Bus トピックからのトリガーの場合、ロール割り当てには、Service Bus サブスクリプション リソースに対する有効なスコープが必要です。 トピックだけが含まれている場合は、エラーが発生します。 Azure portal などの一部のクライアントは、ロール割り当てのスコープとして、Service Bus サブスクリプション リソースを公開しません。 このような場合、代わりに Azure CLI を使用できます。 詳しくは、「Azure Service Bus 用の Azure 組み込みロール」を参照してください。
バージョン 2.x の接続文字列
SDK のバージョン 2.x は、特定の名前を必要としません。 バージョン 2.x を使用すると、これらの接続文字列に独自の名前を使用でき、それらを他の場所に格納できます。 次に示すように、JobHostConfiguration
を使用してコードで名前を設定できます。
static void Main(string[] args)
{
var _storageConn = ConfigurationManager
.ConnectionStrings["MyStorageConnection"].ConnectionString;
//// Dashboard logging is deprecated; use Application Insights.
//var _dashboardConn = ConfigurationManager
// .ConnectionStrings["MyDashboardConnection"].ConnectionString;
JobHostConfiguration config = new JobHostConfiguration();
config.StorageConnectionString = _storageConn;
//config.DashboardConnectionString = _dashboardConn;
JobHost host = new JobHost(config);
host.RunAndBlock();
}
Note
バージョン 3.x では、既定の .NET Core 構成 API が使用されるため、接続文字列の名前を変更する API はありません。 Visual Studio を使用した Web ジョブの開発とデプロイに関する記事を参照してください
ホスト開発設定
ローカル開発をより効率的にするために、開発モードでホストを実行できます。 開発モードで実行しているときに自動的に変更されるいくつかの設定を以下に示します。
プロパティ | 開発設定 |
---|---|
Tracing.ConsoleLevel |
TraceLevel.Verbose でログ出力を最大化します。 |
Queues.MaxPollingInterval |
キューのメソッドがすぐにトリガーされるように、値は低くしてあります。 |
Singleton.ListenerLockPeriod |
素早い反復開発の支援は 15 秒です。 |
開発モードを有効にするプロセスは、SDK のバージョンによって異なります。
バージョン 3.x
バージョン 3.x では、標準の ASP.NET Core API が使用されます。 HostBuilder
インスタンスで UseEnvironment
メソッドを呼び出します。 次の例のように、development
という名前の文字列を渡します。
static async Task Main()
{
var builder = new HostBuilder();
builder.UseEnvironment("development");
builder.ConfigureWebJobs(b =>
{
b.AddAzureStorageCoreServices();
});
var host = builder.Build();
using (host)
{
await host.RunAsync();
}
}
バージョン 2.x
JobHostConfiguration
クラスには、開発モードを有効にする UseDevelopmentSettings
メソッドがあります。 次の例では、開発設定を使用する方法を示します。 ローカル環境で実行したときは config.IsDevelopment
が true
を返すようにするには、AzureWebJobsEnv
という名前で値が Development
のローカル環境変数を設定します。
static void Main()
{
config = new JobHostConfiguration();
if (config.IsDevelopment)
{
config.UseDevelopmentSettings();
}
var host = new JobHost(config);
host.RunAndBlock();
}
コンカレント接続の管理 (バージョン 2.x)
バージョン 3.x では、接続制限は既定で無限接続に設定されます。 何らかの理由でこの制限を変更する必要がある場合は、WinHttpHandler
クラス の MaxConnectionsPerServer
プロパティを使用できます。
バージョン 2.x では、ServicePointManager.DefaultConnectionLimit API を使用して、ホストへのコンカレント接続の数を制御します。 バージョン 2.x では、WebJobs ホストを開始する前に、この値を既定値の 2 から増加してください。
HttpClient
を使用することで関数から送信するすべての HTTP 要求は、ServicePointManager
を通過します。 DefaultConnectionLimit
で設定されている値に達した後は、ServicePointManager
では送信する前に要求をキューに格納するようになります。 たとえば、DefaultConnectionLimit
が 2 に設定されていて、コードが 1,000 個の HTTP 要求を行ったとします。 最初、OS への送信が許可されるのは 2 個の要求のみです。 その他の 998 個は、余裕ができるまでキューされたままになります。 つまり、要求を行ったように見えても、OS によって宛先サーバーに要求が送信されなかったため、HttpClient
がタイムアウトする可能性があります。 従って、ローカルの HttpClient
は、要求を完了するのに 10 秒間かかっているのに、サービスはどの要求も 200 ミリ秒で返しているというような、あまり意味をなさないように見える動作が目撃されることがあります。
ASP.NET アプリケーションの既定値は Int32.MaxValue
であり、これは Basic またはそれ以降の App Service プランで実行されている WebJobs で適切に動作します。 WebJobs は通常、Always On の設定を必要としており、これは Basic またはそれ以降の App Service プランでのみサポートされています。
Web ジョブが Free または Shared App Service プランで実行されている場合、アプリケーションは、現在 300 の接続制限を持つ App Service サンドボックスにより制限されています。 ServicePointManager
の設定がバインドなしの接続制限の場合、サンドボックスの接続がしきい値に達し、サイトがシャット ダウンする可能性が高くなります。 その場合は、DefaultConnectionLimit
の設定を 50 または 100 のようにより低いものにすることで、これを防ぎつつ十分なスループットを可能にします。
あらゆる HTTP 要求が行われる前に、この設定を構成する必要があります。 このため、WebJobs ホストでは設定を自動的に調整しないでください。 ホストが開始する前に HTTP 要求が発生する可能性があり、予期しない動作を招くことがあります。 最善の方法は、次に示すように、JobHost
を初期化する前に Main
メソッドですぐに値を設定することです。
static void Main(string[] args)
{
// Set this immediately so that it's used by all requests.
ServicePointManager.DefaultConnectionLimit = Int32.MaxValue;
var host = new JobHost();
host.RunAndBlock();
}
トリガー
WebJobs SDK では、Azure Functions で使用されるのと同じトリガーとバインドのセットがサポートされます。 WebJobs SDK では、トリガーは関数固有であり、WebJob デプロイの種類には関係しないことに注意してください。 SDK を使用して作成されたイベントトリガー関数を持つ WebJobs は、常に "Always On" が有効になっている継続的な WebJobs として発行する必要があります。
関数は、パブリック メソッドである必要があり、1 つのトリガー属性または NoAutomaticTrigger
属性を必要とします。
自動トリガー
自動トリガーは、イベントに応答して関数を呼び出します。 Azure Queue Storage に追加されるメッセージによってトリガーされる次の例のような関数について考えます。 関数は、Azure Blob Storage から BLOB を読み取ることで応答します。
public static void Run(
[QueueTrigger("myqueue-items")] string myQueueItem,
[Blob("samples-workitems/{queueTrigger}", FileAccess.Read)] Stream myBlob,
ILogger log)
{
log.LogInformation($"BlobInput processed blob\n Name:{myQueueItem} \n Size: {myBlob.Length} bytes");
}
QueueTrigger
属性は、キュー メッセージが myqueue-items
に出現するたびに関数を呼び出すようランタイムに通知します。 Blob
属性は、キュー メッセージを使用して sample-workitems コンテナー内の BLOB を読み取るようランタイムに通知します。 samples-workitems
コンテナー内の BLOB 項目の名前は、キュー トリガーからバインド式 ({queueTrigger}
) として直接取得されます。
Note
Web アプリは非アクティブな状態が 20 分続くとタイムアウトになり、実際の Web アプリに対する要求だけがタイマーをリセットできます。 Azure portal でアプリの構成を表示したり、高度なツールのサイト (https://<app_name>.scm.azurewebsites.net
) に対して要求を行ったりしても、タイマーはリセットされません。 ジョブをホストしている Web アプリを継続的に実行させるか、またはスケジュールに従って実行させるか、あるいはイベント ドリブン トリガーを使用するように設定する場合は、Web アプリの Azure 構成ページで [常にオン] 設定を有効にします。 [常にオン] の設定は、これらの種類の WebJobs が確実に実行されるようにするのに役立ちます。 この機能は、Basic、Standard、および Premium の価格レベルでのみ利用できます。
手動トリガー
関数を手動でトリガーするには、次に示すように、NoAutomaticTrigger
属性を使用します。
[NoAutomaticTrigger]
public static void CreateQueueMessage(
ILogger logger,
string value,
[Queue("outputqueue")] out string message)
{
message = value;
logger.LogInformation("Creating queue message: ", message);
}
関数を手動でトリガーするプロセスは、SDK のバージョンによって異なります。
バージョン 3.x
static async Task Main(string[] args)
{
var builder = new HostBuilder();
builder.ConfigureWebJobs(b =>
{
b.AddAzureStorageCoreServices();
b.AddAzureStorage();
});
var host = builder.Build();
using (host)
{
var jobHost = host.Services.GetService(typeof(IJobHost)) as JobHost;
var inputs = new Dictionary<string, object>
{
{ "value", "Hello world!" }
};
await host.StartAsync();
await jobHost.CallAsync("CreateQueueMessage", inputs);
await host.StopAsync();
}
}
バージョン 2.x
static void Main(string[] args)
{
JobHost host = new JobHost();
host.Call(typeof(Program).GetMethod("CreateQueueMessage"), new { value = "Hello world!" });
}
入出力バインド
入力バインドは、Azure やサード パーティ サービスからのデータをコードに使用できるようにする宣言方法を提供します。 出力バインドは、データを更新する方法を提供します。 WebJobs SDK の使用開始に関するページでは、それぞれの例が示されています。
出力バインドに対してメソッドの戻り値を使用するには、属性をメソッドの戻り値に適用します。 「Azure 関数の戻り値の使用」の例をご覧ください。
バインドの種類
バインドの種類をインストールして管理するプロセスは、バージョン 3.x またはバージョン 2.x のどちらの SDK を使用しているかによって異なります。 特定のバインドの種類用にインストールするパッケージは、Azure Functions のそのバインドの種類の参照資料の「パッケージ」セクションで見つけることができます。 例外は (ローカル ファイル システム用の) Files トリガーとバインドで、これは Azure Functions ではサポートされていません。
バージョン 3.x
バージョン 3.xMicrosoft.Azure.WebJobs.Extensions.Storage
では、ストレージのバインドは パッケージに含まれています。 次に示すように、ConfigureWebJobs
メソッドで AddAzureStorage
拡張メソッドを呼び出します。
static async Task Main()
{
var builder = new HostBuilder();
builder.ConfigureWebJobs(b =>
{
b.AddAzureStorageCoreServices();
b.AddAzureStorage();
});
var host = builder.Build();
using (host)
{
await host.RunAsync();
}
}
他のトリガーやバインドの種類を使用するには、それらを含む NuGet パッケージをインストールして、拡張で実装されている Add<binding>
拡張メソッドを呼び出します。 たとえば、Azure Cosmos DB バインドを使用する場合は、次のように、Microsoft.Azure.WebJobs.Extensions.CosmosDB
をインストールして AddCosmosDB
を呼び出します。
static async Task Main()
{
var builder = new HostBuilder();
builder.ConfigureWebJobs(b =>
{
b.AddAzureStorageCoreServices();
b.AddCosmosDB();
});
var host = builder.Build();
using (host)
{
await host.RunAsync();
}
}
コア サービスの一部である Timer トリガーまたは Files バインドを使用するには、AddTimers
拡張メソッドまたは AddFiles
拡張メソッドを呼び出します。
バージョン 2.x
次のトリガーおよびバインドの種類は、Microsoft.Azure.WebJobs
パッケージのバージョン 2.x に含まれています。
- BLOB ストレージ
- ストレージ
- テーブル ストレージ
その他の種類のトリガーやバインドを使用するには、それらを含む NuGet パッケージをインストールして、JobHostConfiguration
オブジェクトの Use<binding>
メソッドを呼び出します。 たとえば、Timer トリガーを使用する場合は、次のように、Microsoft.Azure.WebJobs.Extensions
をインストールして、Main
メソッドで UseTimers
を呼び出します。
static void Main()
{
config = new JobHostConfiguration();
config.UseTimers();
var host = new JobHost(config);
host.RunAndBlock();
}
Files バインドを使用するには、Microsoft.Azure.WebJobs.Extensions
をインストールして UseFiles
を呼び出します。
ExecutionContext
WebJobs を使用すると、ExecutionContext
にバインドできます。 このバインディングを使用すると、関数シグネチャのパラメーターとして ExecutionContext
にアクセスできます。 たとえば、次のコードはコンテキスト オブジェクトを使用して呼び出し ID にアクセスします。その呼び出し ID を使用すると、特定の関数呼び出しによって生成されたすべてのログを関連付けることができます。
public class Functions
{
public static void ProcessQueueMessage([QueueTrigger("queue")] string message,
ExecutionContext executionContext,
ILogger logger)
{
logger.LogInformation($"{message}\n{executionContext.InvocationId}");
}
}
ExecutionContext
にバインドするプロセスは、SDK のバージョンによって異なります。
バージョン 3.x
次に示すように、ConfigureWebJobs
メソッドで AddExecutionContextBinding
拡張メソッドを呼び出します。
static async Task Main()
{
var builder = new HostBuilder();
builder.ConfigureWebJobs(b =>
{
b.AddAzureStorageCoreServices();
b.AddExecutionContextBinding();
});
var host = builder.Build();
using (host)
{
await host.RunAsync();
}
}
バージョン 2.x
先述した Microsoft.Azure.WebJobs.Extensions
パッケージは、UseCore
メソッドを呼び出すことによって登録できる特別なバインドの種類も提供しています。 このバインドを使用すると、関数シグネチャで ExecutionContext
パラメーターを定義でき、それは次のように有効化されます。
class Program
{
static void Main()
{
config = new JobHostConfiguration();
config.UseCore();
var host = new JobHost(config);
host.RunAndBlock();
}
}
バインド構成
一部のトリガーとバインドの動作を構成することができます。 それらを構成するプロセスは、SDK のバージョンによって異なります。
- バージョン 3.x:
ConfigureWebJobs
でAdd<Binding>
メソッドを 呼び出すときに、構成を設定します。 - バージョン 2.x:
JobHost
に渡す構成オブジェクトでプロパティを設定することにより、構成を設定します。
これらのバインド固有の設定は、Azure Functions の host.json プロジェクト ファイルでの設定と同等です。
次のバインドを構成できます。
Azure Cosmos DB トリガーの構成 (バージョン 3.x)
次の例では、Azure Cosmos DB トリガーを構成する方法を示します。
static async Task Main()
{
var builder = new HostBuilder();
builder.ConfigureWebJobs(b =>
{
b.AddAzureStorageCoreServices();
b.AddCosmosDB(a =>
{
a.ConnectionMode = ConnectionMode.Gateway;
a.Protocol = Protocol.Https;
a.LeaseOptions.LeasePrefix = "prefix1";
});
});
var host = builder.Build();
using (host)
{
await host.RunAsync();
}
}
詳しくは、Azure Cosmos DB のバインドに関する記事をご覧ください。
Event Hubs トリガーの構成 (バージョン 3.x)
次の例では、Event Hubs トリガーを構成する方法を示します。
static async Task Main()
{
var builder = new HostBuilder();
builder.ConfigureWebJobs(b =>
{
b.AddAzureStorageCoreServices();
b.AddEventHubs(a =>
{
a.BatchCheckpointFrequency = 5;
a.EventProcessorOptions.MaxBatchSize = 256;
a.EventProcessorOptions.PrefetchCount = 512;
});
});
var host = builder.Build();
using (host)
{
await host.RunAsync();
}
}
詳細については、Event Hubs バインディングに関する記事を参照してください。
Queue Storage トリガーの構成
次の例では、Queue Storage トリガーを構成する方法を示します。
バージョン 3.x
static async Task Main()
{
var builder = new HostBuilder();
builder.ConfigureWebJobs(b =>
{
b.AddAzureStorageCoreServices();
b.AddAzureStorage(a => {
a.BatchSize = 8;
a.NewBatchThreshold = 4;
a.MaxDequeueCount = 4;
a.MaxPollingInterval = TimeSpan.FromSeconds(15);
});
});
var host = builder.Build();
using (host)
{
await host.RunAsync();
}
}
詳しくは、Queue Storage のバインドに関する記事をご覧ください。
バージョン 2.x
static void Main(string[] args)
{
JobHostConfiguration config = new JobHostConfiguration();
config.Queues.BatchSize = 8;
config.Queues.NewBatchThreshold = 4;
config.Queues.MaxDequeueCount = 4;
config.Queues.MaxPollingInterval = TimeSpan.FromSeconds(15);
JobHost host = new JobHost(config);
host.RunAndBlock();
}
詳細については、host.json v1.x のリファレンスを参照してください。
SendGrid バインドの構成 (バージョン 3.x)
次の例では、SendGrid 出力バインドを構成する方法を示します。
static async Task Main()
{
var builder = new HostBuilder();
builder.ConfigureWebJobs(b =>
{
b.AddAzureStorageCoreServices();
b.AddSendGrid(a =>
{
a.FromAddress.Email = "samples@functions.com";
a.FromAddress.Name = "Azure Functions";
});
});
var host = builder.Build();
using (host)
{
await host.RunAsync();
}
}
詳細については、SendGrid バインディングに関する記事を参照してください。
Service Bus トリガーの構成 (バージョン 3.x)
次の例では、Service Bus トリガーを構成する方法を示します。
static async Task Main()
{
var builder = new HostBuilder();
builder.ConfigureWebJobs(b =>
{
b.AddAzureStorageCoreServices();
b.AddServiceBus(sbOptions =>
{
sbOptions.MessageHandlerOptions.AutoComplete = true;
sbOptions.MessageHandlerOptions.MaxConcurrentCalls = 16;
});
});
var host = builder.Build();
using (host)
{
await host.RunAsync();
}
}
詳しくは、Service Bus のバインドに関する記事をご覧ください。
その他のバインドの構成
一部のトリガーとバインドの種類では、独自のカスタム構成の種類が定義されています。 たとえば、次の例に示すように、File トリガーを使用して、監視するルート パスを指定することができます。
バージョン 3.x
static async Task Main()
{
var builder = new HostBuilder();
builder.ConfigureWebJobs(b =>
{
b.AddAzureStorageCoreServices();
b.AddFiles(a => a.RootPath = @"c:\data\import");
});
var host = builder.Build();
using (host)
{
await host.RunAsync();
}
}
バージョン 2.x
static void Main()
{
config = new JobHostConfiguration();
var filesConfig = new FilesConfiguration
{
RootPath = @"c:\data\import"
};
config.UseFiles(filesConfig);
var host = new JobHost(config);
host.RunAndBlock();
}
バインド式
属性コンス トラクターのパラメーターでは、さまざまなソースからの値に解決する式を使用することができます。 たとえば、次のコードで BlobTrigger
属性のパスは、filename
という名前の式を作成します。 これが出力バインドに使用されると、filename
はトリガーする BLOB の名前に解決します。
public static void CreateThumbnail(
[BlobTrigger("sample-images/{filename}")] Stream image,
[Blob("sample-images-sm/{filename}", FileAccess.Write)] Stream imageSmall,
string filename,
ILogger logger)
{
logger.Info($"Blob trigger processing: {filename}");
// ...
}
バインド式の詳細については、Azure Functions ドキュメント内のバインド式とパターンを参照してください。
カスタム バインド式
キュー名、BLOB 名、コンテナー、テーブル名をハードコーディングではなく、コードに指定する場合もあります。 たとえば、構成ファイルや環境変数で QueueTrigger
属性のキュー名を指定するとします。
構成の間にカスタム名前リゾルバーを渡すことによって、それを行うことができます。 トリガーやバインド属性コンストラクターのパラメーターにプレースホルダーを組み込み、それらのプレースホルダーの代わりに使われる実際の値をリゾルバーのコードで提供します。 次に示すように、プレースホルダーはパーセント (%) 記号で囲んで示します。
public static void WriteLog([QueueTrigger("%logqueue%")] string logMessage)
{
Console.WriteLine(logMessage);
}
このコードを使用すると、logqueuetest
という名前のキューをテスト環境で使用でき、logqueueprod
という名前のキューを実稼働環境で使用できます。 キュー名をハードコードする代わりに、appSettings
コレクションのエントリの名前を指定します。
カスタム リゾルバーを提供しない場合、既定のリゾルバーが使われます。 既定値は、アプリの設定や環境変数から値を取得します。
.NET Core 3.1 以降では、使用する ConfigurationManager
に System.Configuration.ConfigurationManager NuGet パッケージが必要です。 サンプルでは、次の using
ステートメントが必要です。
using System.Configuration;
次のように、NameResolver
クラスによってアプリの設定からキューの名前が取得されます。
public class CustomNameResolver : INameResolver
{
public string Resolve(string name)
{
return ConfigurationManager.AppSettings[name].ToString();
}
}
バージョン 3.x
リゾルバーは、依存関係インジェクションを使用して構成します。 これらのサンプルには、次の using
ステートメントが必要です。
using Microsoft.Extensions.DependencyInjection;
次の例のように、HostBuilder
で ConfigureServices
拡張メソッドを呼び出してリゾルバーを追加します。
static async Task Main(string[] args)
{
var builder = new HostBuilder();
var resolver = new CustomNameResolver();
builder.ConfigureWebJobs(b =>
{
b.AddAzureStorageCoreServices();
});
builder.ConfigureServices(s => s.AddSingleton<INameResolver>(resolver));
var host = builder.Build();
using (host)
{
await host.RunAsync();
}
}
バージョン 2.x
次に示すように、NameResolver
クラスを JobHost
オブジェクトに渡します。
static void Main(string[] args)
{
JobHostConfiguration config = new JobHostConfiguration();
config.NameResolver = new CustomNameResolver();
JobHost host = new JobHost(config);
host.RunAndBlock();
}
Azure Functions では、次の例に示すように、アプリの設定から値を取得するために INameResolver
が実装されます。 WebJobs SDK を直接使用する場合は、お好みのソースからプレースホルダーの置換値を取得するカスタム実装を記述できます。
実行時のバインド
Queue
、Blob
、Table
などのバインド属性を使用する前に関数で何らかの処理を行う必要がある場合は、IBinder
インターフェイスを使用できます。
次の例では、入力キュー メッセージを取得して同じ内容の新しい出力キュー メッセージを作成します。 出力キュー名は、関数本体のコードによって設定されます。
public static void CreateQueueMessage(
[QueueTrigger("inputqueue")] string queueMessage,
IBinder binder)
{
string outputQueueName = "outputqueue" + DateTime.Now.Month.ToString();
QueueAttribute queueAttribute = new QueueAttribute(outputQueueName);
CloudQueue outputQueue = binder.Bind<CloudQueue>(queueAttribute);
outputQueue.AddMessageAsync(new CloudQueueMessage(queueMessage));
}
詳細については、Azure Functions ドキュメント内の実行時のバインドを参照してください。
バインド参照情報
Azure Functions のドキュメントでは、各バインドの種類に関する参照情報が提供されています。 各バインド参照記事には、以下の情報が記載されています。 (この例は、Storage キューに基づいています。)
- パッケージ。 WebJobs SDK プロジェクトにバインドのサポートを含めるためにインストールする必要のあるパッケージです。
- 例。 コード サンプルです。 C# クラス ライブラリの例は、WebJobs SDK に適用されます。
FunctionName
属性は単に省略します。 - 属性。 バインドの種類に使用する属性です。
- 構成。 属性のプロパティとコンストラクターのパラメーターの説明です。
- 使用方法。 どの種類にバインドできるかとバインドの動作方法に関する情報です。 例: ポーリング アルゴリズム、有害キュー処理。
Note
HTTP、Webhook、Event Grid のバインドは、Azure Functions でのみサポートされており、WebJobs SDK ではサポートされていません。
Azure Functions ランタイムでサポートされるバインディングの完全な一覧については、「サポートされるバインディング」を参照してください。
Disable、Timeout、Singleton の属性
これらの属性を使用すると、関数のトリガーを制御し、関数を取り消し、関数のインスタンスが 1 つのみ実行されるようにできます。
Disable 属性
Disable
属性は、関数がトリガーされるかどうかを制御します。
次の例では、アプリ設定 Disable_TestJob
の値が 1
または True
(大文字小文字の区別なし) の場合、関数は実行されません。 その場合、ランタイムが関数 'Functions.TestJob' が無効ですというログ メッセージを作成します。
[Disable("Disable_TestJob")]
public static void TestJob([QueueTrigger("testqueue2")] string message)
{
Console.WriteLine("Function with Disable attribute executed!");
}
Azure portal でアプリ設定の値を変更すると、WebJobs が再起動され、新しい設定が取得されます。
属性は、パラメーター、メソッド、またはクラス レベルで宣言できます。 設定名には、バインド式を含めることもできます。
Timeout 属性
Timeout
属性は、関数が指定した時間内に完了しない場合にキャンセルします。 次の例では、関数は Timeout 属性なしで 1 日間実行されます。 Timeout があると、関数は 15 秒後に取り消されます。 Timeout 属性の "throwOnError" パラメーターが "true" に設定されている場合、タイムアウトの期間を超えたときに Webjobs SDK によって例外がスローされ、関数の呼び出しが終了します。 "throwOnError" の既定値は "false" です。 Timeout 属性を使用する場合、既定の動作では、キャンセル トークンを設定して関数の呼び出しを取り消し、関数コードが例外を返すかスローするまで呼び出しを無期限に実行できるようにします。
[Timeout("00:00:15")]
public static async Task TimeoutJob(
[QueueTrigger("testqueue2")] string message,
CancellationToken token,
TextWriter log)
{
await log.WriteLineAsync("Job starting");
await Task.Delay(TimeSpan.FromDays(1), token);
await log.WriteLineAsync("Job completed");
}
クラスまたはメソッド レベルで Timeout 属性を適用し、JobHostConfiguration.FunctionTimeout
を使用してグローバル タイムアウトを指定することができます。 クラス レベルまたはメソッド レベルのタイムアウトは、グローバル タイムアウトをオーバーライドします。
Singleton 属性
Singleton
属性を使用すると、ホスト Web アプリの複数のインスタンスがある場合でも、関数の 1 つのインスタンスのみが実行されます。 Singleton 属性は分散ロックを使用して、1 つのインスタンスが実行されることを保証できます。
次の例では、常に ProcessImage
関数の単一のインスタンスのみが実行されます。
[Singleton]
public static async Task ProcessImage([BlobTrigger("images")] Stream image)
{
// Process the image.
}
SingletonMode.Listener
一部のトリガーには、コンカレンシー管理の組み込みサポートがあります。
- QueueTrigger。
JobHostConfiguration.Queues.BatchSize
を1
に設定します。 - ServiceBusTrigger。
ServiceBusConfiguration.MessageOptions.MaxConcurrentCalls
を1
に設定します。 - FileTrigger。
FileProcessor.MaxDegreeOfParallelism
を1
に設定します。
これらの設定を使用すると、単一のインスタンスで、関数がシングルトンとして実行されるようになります。 Web アプリが複数のインスタンスにスケールアウトするとき、関数の単一のインスタンスのみが実行されるようにするには、関数にリスナー レベルのシングルトン ロック ([Singleton(Mode = SingletonMode.Listener)]
) を適用します。 リスナー ロックは、JobHost の起動時に取得されます。 3 つのスケール アウト インスタンスのすべてが同時に開始すると、1 つのインスタンスのみがロックを取得して、1 つのみがリスナーを開始します。
Note
SingletonMode.Function の機能の詳細については、この GitHub リポジトリを参照してください。
スコープ値
シングルトンで "スコープ式/値" を指定することができます。 式/値により、特定スコープでの関数のすべての実行がシリアル化されることが保証されます。 この方法で詳細なロックを実装すると、要件によって指示されたように他の呼び出しをシリアル化すると同時に、関数のある程度の並列処理が可能になります。 たとえば、次のコードでは、スコープ式は、受信メッセージの Region
値 にバインドしています。 キューに East、East、および West のリージョンの 3 つのメッセージが含まれている場合、リージョン East を持つメッセージは連続して実行されます。 リージョン West のメッセージは、リージョン East のメッセージと並行して実行されます。
[Singleton("{Region}")]
public static async Task ProcessWorkItem([QueueTrigger("workitems")] WorkItem workItem)
{
// Process the work item.
}
public class WorkItem
{
public int ID { get; set; }
public string Region { get; set; }
public int Category { get; set; }
public string Description { get; set; }
}
SingletonScope.Host
ロックの既定スコープは SingletonScope.Function
です。つまり、ロック スコープ (BLOB のリース パス) は、関数の完全修飾名に関連付けられています。 複数の関数にわたってロックするには、SingletonScope.Host
を指定して、同時に実行したくない関数すべてと同じスコープ ID 名を使用します。 次の例では、 AddItem
または RemoveItem
の1 つのみのインスタンス が一度に実行されます。
[Singleton("ItemsLock", SingletonScope.Host)]
public static void AddItem([QueueTrigger("add-item")] string message)
{
// Perform the add operation.
}
[Singleton("ItemsLock", SingletonScope.Host)]
public static void RemoveItem([QueueTrigger("remove-item")] string message)
{
// Perform the remove operation.
}
リース BLOB のビュー
WebJobs SDK は、バックグラウンドで Azure BLOB リースを使用して、分散ロックを実装します。 Singleton により使用されるリース BLOB は、パス "locks" にある AzureWebJobsStorage
ストレージ アカウント内の azure-webjobs-host
コンテナーにあります。 たとえば、先に示した最初の ProcessImage
の例のリース BLOB パスは、locks/061851c758f04938a4426aa9ab3869c0/WebJobs.Functions.ProcessImage
です。 どのパスにも JobHost ID が含まれています。この場合は、061851c758f04938a4426aa9ab3869c0 になります。
Async 関数
Async 関数のコードを書く方法については、Azure Functions のドキュメントをご覧ください。
キャンセル トークン
キャンセル トークンを処理する方法については、Azure Functions ドキュメントのキャンセル トークンと正常なシャットダウンを参照してください。
複数インスタンス
Web アプリが複数のインスタンス上で稼働している場合、継続的な Web ジョブは各インスタンスで実行され、トリガーをリッスンして関数の呼び出しを行います。 各種のトリガー バインドは、インスタンス間で協調して作業を効率的に共有するよう設計されているので、より多くのインスタンスにスケール アウトすると、より多くの負荷を処理することができます。
一部のトリガーで二重の処理が発生する可能性がありますが、キューと BLOB ストレージ トリガーでは、関数がキュー メッセージや BLOB を 2 回以上処理することが自動的に防止されます。 詳細については、Azure Functions ドキュメントの同一入力のための設計に関する記事を参照してください。
タイマー トリガーは、指定された時刻に常に 1 つを超える関数のインスタンスが実行しないように、自動的に タイマーの1 つのインスタンスのみが実行するようにします。
ホスト Web アプリの複数のインスタンスがある場合でも、関数の 1 つのインスタンスのみを実行するには Singleton
属性を使用できます。
フィルター
関数のフィルター (プレビュー) は、独自のロジックで WebJobs 実行パイプラインをカスタマイズする方法を提供します。 フィルターは ASP.NET Core フィルターに似ています。 関数またはクラスに適用される宣言型の属性として実装することができます。 詳細については、関数フィルターを参照してください。
ログ記録と監視
ASP.NET 用に開発されたログ記録フレームワークをお勧めします。 使用方法については、使用の開始に関する記事をご覧ください。
ログのフィルタリング
ILogger
インスタンスによって作成されたすべてのログには、関連付けられた Category
と Level
があります。 LogLevel
は列挙型で、整数コードは次のような相対的な重要度を示します。
LogLevel | コード |
---|---|
Trace | 0 |
デバッグ | 1 |
Information | 2 |
警告 | 3 |
エラー | 4 |
Critical | 5 |
なし | 6 |
各カテゴリを特定の LogLevel
に個別にフィルター処理できます。 たとえば、BLOB トリガー処理のすべてのログを表示するが、それ以外に関しては Error
以降のみを表示するなどが可能です。
バージョン 3.x
SDK のバージョン 3.x は、.NET Core に組み込まれているフィルタリングに依存しています。 LogCategories
クラスを使用すると、特定の関数、トリガー、またはユーザーのカテゴリを定義することができます。 また、特定のホストの状態 (Startup
や Results
など) のフィルターも定義されています。 これにより、ログ記録の出力を微調整できます。 定義されたカテゴリ内で一致するものが見つからない場合、メッセージをフィルターするかどうかを決めるときに、フィルターは Default
値に戻ります。
LogCategories
には、次の using ステートメントが必要です。
using Microsoft.Azure.WebJobs.Logging;
次の例では、既定で Warning
レベルのすべてのログをフィルター処理するフィルターを構築します。 Function
および results
カテゴリ (バージョン 2.x の Host.Results
と同等) は、Error
レベルでフィルタリングされます。 フィルターは、現在のカテゴリを、LogCategories
インスタンス内のすべての登録済みレベルと比較して、最も長い一致を選択します。 つまり、Host.Triggers
に登録されている Debug
レベルは、Host.Triggers.Queue
や Host.Triggers.Blob
に一致します。 これにより、カテゴリを 1 つずつ追加しなくても、より幅広いカテゴリを制御できます。
static async Task Main(string[] args)
{
var builder = new HostBuilder();
builder.ConfigureWebJobs(b =>
{
b.AddAzureStorageCoreServices();
});
builder.ConfigureLogging(logging =>
{
logging.SetMinimumLevel(LogLevel.Warning);
logging.AddFilter("Function", LogLevel.Error);
logging.AddFilter(LogCategories.CreateFunctionCategory("MySpecificFunctionName"),
LogLevel.Debug);
logging.AddFilter(LogCategories.Results, LogLevel.Error);
logging.AddFilter("Host.Triggers", LogLevel.Debug);
});
var host = builder.Build();
using (host)
{
await host.RunAsync();
}
}
バージョン 2.x
SDK のバージョン 2.x では、LogCategoryFilter
クラスを使用してフィルター処理を制御します。 LogCategoryFilter
には Default
プロパティがあり、初期値は Information
です。つまり、Information
、Warning
、Error
、Critical
レベルのメッセージはすべてログに記録されますが、Debug
または Trace
レベルのメッセージは除外されます。
バージョン 3.x の LogCategories
と同様に、CategoryLevels
プロパティを使用すると特定のカテゴリのログ レベルを指定できるため、ロギング出力を微調整することができます。 CategoryLevels
ディクショナリ内で一致するものが見つからない場合、メッセージをフィルターするかどうかを決定する際に、フィルターが Default
値にフォールバックします。
次の例は、既定値で Warning
レベルのすべてのログをフィルタリングするフィルターを構築します。 Function
および Host.Results
カテゴリは、Error
レベルでフィルター処理されます。 LogCategoryFilter
は現在のカテゴリを、登録されているすべての CategoryLevels
と比較して、最長一致を選択します。 したがって、Host.Triggers
に登録されている Debug
レベルは、Host.Triggers.Queue
または Host.Triggers.Blob
と一致します。 これにより、カテゴリを 1 つずつ追加しなくても、より幅広いカテゴリを制御できます。
var filter = new LogCategoryFilter();
filter.DefaultLevel = LogLevel.Warning;
filter.CategoryLevels[LogCategories.Function] = LogLevel.Error;
filter.CategoryLevels[LogCategories.Results] = LogLevel.Error;
filter.CategoryLevels["Host.Triggers"] = LogLevel.Debug;
config.LoggerFactory = new LoggerFactory()
.AddApplicationInsights(instrumentationKey, filter.Filter)
.AddConsole(filter.Filter);
Application Insights のカスタム テレメトリ
Application Insights 用のカスタム テレメトリを実装するプロセスは、SDK のバージョンによって異なります。 Application Insights の構成方法については、「Application Insights ログの追加」を参照してください。
バージョン 3.x
WebJobs SDK のバージョン 3.x は、.NET Core 汎用ホストに依存しているため、カスタム テレメトリ ファクトリは提供されなくなりました。 ただし、依存関係インジェクションを使用してカスタム テレメトリをパイプラインに追加できます。 このセクションの例には、次の using
ステートメントが必要です。
using Microsoft.ApplicationInsights.Extensibility;
using Microsoft.ApplicationInsights.Channel;
次の ITelemetryInitializer
のカスタム実装を使用すると、独自の ITelemetry
を既定の TelemetryConfiguration
に追加することができます。
internal class CustomTelemetryInitializer : ITelemetryInitializer
{
public void Initialize(ITelemetry telemetry)
{
// Do something with telemetry.
}
}
ビルダーで ConfigureServices
を呼び出して、カスタム ITelemetryInitializer
をパイプラインに追加します。
static async Task Main()
{
var builder = new HostBuilder();
builder.ConfigureWebJobs(b =>
{
b.AddAzureStorageCoreServices();
});
builder.ConfigureLogging((context, b) =>
{
// Add logging providers.
b.AddConsole();
// If this key exists in any config, use it to enable Application Insights.
string appInsightsKey = context.Configuration["APPINSIGHTS_INSTRUMENTATIONKEY"];
if (!string.IsNullOrEmpty(appInsightsKey))
{
// This uses the options callback to explicitly set the instrumentation key.
b.AddApplicationInsights(o => o.InstrumentationKey = appInsightsKey);
}
});
builder.ConfigureServices(services =>
{
services.AddSingleton<ITelemetryInitializer, CustomTelemetryInitializer>();
});
var host = builder.Build();
using (host)
{
await host.RunAsync();
}
}
TelemetryConfiguration
が構築されるとき、ITelemetryInitializer
のすべての登録されている種類が組み込まれます。 詳しくは、「カスタムのイベントとメトリックのための Application Insights API」をご覧ください。
バージョン 3.x では、ホストが停止するときに TelemetryClient
をフラッシュする必要がなくなりました。 .NET Core 依存関係インジェクション システムが、登録されている ApplicationInsightsLoggerProvider
を自動的に破棄し、それにより TelemetryClient
がフラッシュされます。
バージョン 2.x
バージョン 2.x では、WebJobs SDK 用に Application Insights プロバイダーによって内部で作成された TelemetryClient
では、ServerTelemetryChannel
が使用されます。 Application Insights のエンドポイントが使用できない、または着信要求のスロットリングが行われている場合、このチャンネルが Web アプリのファイル システムで要求を保存して、後でこれらを再送信します。
TelemetryClient
は、ITelemetryClientFactory
を実装するクラスにより作成されます。 既定で、これは DefaultTelemetryClientFactory
です。
Application Insights パイプラインの一部を変更する場合、独自の ITelemetryClientFactory
を使用することができます。すると、ホストはクラスを使用して TelemetryClient
を構築します。 たとえば、次のコードでは DefaultTelemetryClientFactory
がオーバーライドされて、ServerTelemetryChannel
のプロパティが変更されます。
private class CustomTelemetryClientFactory : DefaultTelemetryClientFactory
{
public CustomTelemetryClientFactory(string instrumentationKey, Func<string, LogLevel, bool> filter)
: base(instrumentationKey, new SamplingPercentageEstimatorSettings(), filter)
{
}
protected override ITelemetryChannel CreateTelemetryChannel()
{
ServerTelemetryChannel channel = new ServerTelemetryChannel();
// Change the default from 30 seconds to 15 seconds.
channel.MaxTelemetryBufferDelay = TimeSpan.FromSeconds(15);
return channel;
}
}
SamplingPercentageEstimatorSettings
オブジェクトでは、アダプティブ サンプリングが構成されます。 つまり、特定の大規模なシナリオでは、Application Insights はテレメトリ データの選択されたサブセットをサーバーに送信します。
テレメトリ ファクトリを作成した後、Application Insights のログ プロバイダーにそれを渡します。
var clientFactory = new CustomTelemetryClientFactory(instrumentationKey, filter.Filter);
config.LoggerFactory = new LoggerFactory()
.AddApplicationInsights(clientFactory);
次のステップ
この記事では、WebJobs SDK を操作するための一般的なシナリオの処理方法を示すコード スニペットを提供しました。 完全なサンプルは、azure-webjobs-sdk-samples を参照してください。