Intercept Azure Function Host Shutdown: Flush Appl

2019-05-07 20:01发布

问题:

I am playing a little bit with Azure Function: Mostly I try to migrate an existing webjob to Azure Functions and now it is time for me to integrate Application Insights in one of my function.

So basically I only need one instance of the TelemetryClient but this assumes that I am able to flush the in-memory buffer when the application stops.

I've used a TimerTrigger but it was just for testing purpose.

I've referenced the Microsoft.ApplicationInsights nuget package (from this SO post) and my run.csx file looks like that:

using System;
using Microsoft.ApplicationInsights;
using Microsoft.Azure.WebJobs;

public static void Run(TimerInfo myTimer, TraceWriter log)
{
    MyTimerJob.TelemetryClient.TrackEvent("AzureFunctionTriggered");
    log.Verbose($"C# Timer trigger function executed at: {DateTime.Now}");
}    

public static class MyTimerJob
{
    public static readonly TelemetryClient TelemetryClient;

    static MyTimerJob(){
        TelemetryClient = new TelemetryClient()
            { InstrumentationKey = "MyInstrumentationKey" };

        // When it shutdowns, we flush the telemty client.
        new WebJobsShutdownWatcher().Token.Register(() =>
        {
            TelemetryClient.TrackEvent("TelemetryClientFlush");
            TelemetryClient.Flush();
        });
    }
}

This implementation is a bit tricky...

  • I have a static TelemetryClient to ensure that I am going to reuse the same instance.
  • I tried using the WebJobsShutdownWatcher to detect when the host is stopping so that I can flush the TelemetryClient.

To simulate the application shutdown, I've created a "test" app setting in the underlying web app and I modify it when I want the host to restart:

Unfortunately this does not work... I did not see any event with name "TelemetryClientFlush" from the app insights dashboard:

So I am now wondering if there is any way to intercept when the azure function host is stopping ?

回答1:

In addition to what Mathew described, you may want to play around with the cancellation token we'll pass if requested.

If you add a CancellationToken type argument to your function, we'll pass in a token that will be signaled when the host shuts down under normal circumstances. Using that may get you close to what you need:

using System;
using System.Threading;
using Microsoft.ApplicationInsights;

public static readonly TelemetryClient TelemetryClient = new  TelemetryClient(){ InstrumentationKey = "MyInstrumentationKey" };
public static bool first = true;
public static void Run(TimerInfo myTimer, TraceWriter log, CancellationToken token)
{
    if(first){
        token.Register(() =>
        {
            TelemetryClient.TrackEvent("TelemetryClientFlush");
            TelemetryClient.Flush();
        });
        first = false;
    }

    TelemetryClient.TrackEvent("AzureFunctionTriggered");
    log.Verbose($"C# Timer trigger function executed at: {DateTime.Now}");
}


回答2:

While Azure Functions does run on top of the WebJobs SDK, it does not run under the traditional Kudu WebJobs infrastructure. The WebJobsShutdownWatcher actually relies on functionality of the Kudu host, specifically the sentinel file indicated by WEBJOBS_SHUTDOWN_FILE. Basically when the Kudu host is shutting down it touches this file which the watcher is monitoring. Since no such file is being touched, your code is not being triggered.

We could make changes to allow the watcher to work as is, or we might instead introduce a new pattern for Functions. I've logged an issue in our repo here tracking this suggestion. I think the scenario is important and we'll give it some thought.