イベント ドリブンのバックグラウンド処理に 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 という名前のストレージ接続文字列設定が必要です。

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.IsDevelopmenttrue を返すようにするには、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:ConfigureWebJobsAdd<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 以降では、使用する ConfigurationManagerSystem.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;

次の例のように、HostBuilderConfigureServices 拡張メソッドを呼び出してリゾルバーを追加します。

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 を直接使用する場合は、お好みのソースからプレースホルダーの置換値を取得するカスタム実装を記述できます。

実行時のバインド

QueueBlobTable などのバインド属性を使用する前に関数で何らかの処理を行う必要がある場合は、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

一部のトリガーには、コンカレンシー管理の組み込みサポートがあります。

  • QueueTriggerJobHostConfiguration.Queues.BatchSize1 に設定します。
  • ServiceBusTriggerServiceBusConfiguration.MessageOptions.MaxConcurrentCalls1 に設定します。
  • FileTriggerFileProcessor.MaxDegreeOfParallelism1 に設定します。

これらの設定を使用すると、単一のインスタンスで、関数がシングルトンとして実行されるようになります。 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 インスタンスによって作成されたすべてのログには、関連付けられた CategoryLevel があります。 LogLevel は列挙型で、整数コードは次のような相対的な重要度を示します。

LogLevel コード
Trace 0
デバッグ 1
Information 2
警告 3
エラー 4
Critical 5
なし 6

各カテゴリを特定の LogLevel に個別にフィルター処理できます。 たとえば、BLOB トリガー処理のすべてのログを表示するが、それ以外に関しては Error 以降のみを表示するなどが可能です。

バージョン 3.x

SDK のバージョン 3.x は、.NET Core に組み込まれているフィルタリングに依存しています。 LogCategories クラスを使用すると、特定の関数、トリガー、またはユーザーのカテゴリを定義することができます。 また、特定のホストの状態 (StartupResults など) のフィルターも定義されています。 これにより、ログ記録の出力を微調整できます。 定義されたカテゴリ内で一致するものが見つからない場合、メッセージをフィルターするかどうかを決めるときに、フィルターは Default 値に戻ります。

LogCategories には、次の using ステートメントが必要です。

using Microsoft.Azure.WebJobs.Logging; 

次の例では、既定で Warning レベルのすべてのログをフィルター処理するフィルターを構築します。 Function および results カテゴリ (バージョン 2.xHost.Results と同等) は、Error レベルでフィルタリングされます。 フィルターは、現在のカテゴリを、LogCategories インスタンス内のすべての登録済みレベルと比較して、最も長い一致を選択します。 つまり、Host.Triggers に登録されている Debug レベルは、Host.Triggers.QueueHost.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 です。つまり、InformationWarningErrorCritical レベルのメッセージはすべてログに記録されますが、Debug または Trace レベルのメッセージは除外されます。

バージョン 3.xLogCategories と同様に、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 を参照してください。