We will learn how to be notified via email when errors occur in an Azure WebJob.

When an Azure WebJob is executed wouldn't it be good to be notified when something goes wrong?

Thanks to the following extensions this is something we can easily do:

WebJobs ErrorTrigger extension

WebJobs SendGrid extension

 

In this article, we will discover how to send emails from an Azure WebJob with the SenGrid extension when errors are detected using the ErrorTrigger extension. As a base, we will create a project with the Azure WebJob template in Visual Studio.

 

Creation

The first thing you will need is to add the following NuGet package to your project: Microsoft.Azure.WebJobs.Extensions.SendGrid

 

To enable the ErrorTrigger and SendGrid extensions in your WebJob you will need to configure the JobHostConfiguration like the following:

using Microsoft.Azure.WebJobs;

namespace AzureWebJobs.ErrorsEmails
{
    // To learn more about Microsoft Azure WebJobs SDK, please see https://go.microsoft.com/fwlink/?LinkID=320976
    class Program
    {
        // Please set the following connection strings in app.config for this WebJob to run:
        // AzureWebJobsDashboard and AzureWebJobsStorage
        static void Main()
        {
            var config = new JobHostConfiguration();

            if (config.IsDevelopment)
            {
                config.UseDevelopmentSettings();
            }

            config.UseCore();
            config.UseSendGrid();

            var host = new JobHost(config);
            // The following code ensures that the WebJob will be running continuously
            host.RunAndBlock();
        }
    }
}

The important part here is to call the extensions named UseCore and UseSendGrid. This will enable the ErrorTrigger and SendGrid extensions.

 

We will now add a new application settings to be able to connect to SendGrid:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <connectionStrings>
    <!-- The format of the connection string is "DefaultEndpointsProtocol=https;AccountName=NAME;AccountKey=KEY" -->
    <!-- For local execution, the value can be set either in this config file or through environment variables -->
    <add name="AzureWebJobsDashboard" connectionString="" />
    <add name="AzureWebJobsStorage" connectionString="" />
  </connectionStrings>
  <appSettings>
    <add key="AzureWebJobsSendGridApiKey" value="" />
  </appSettings>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
  </startup>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.Azure.KeyVault.Core" publicKeyToken="31bf3856ad364e35" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.WindowsAzure.Storage" publicKeyToken="31bf3856ad364e35" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-8.1.4.0" newVersion="8.1.4.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-10.0.0.0" newVersion="10.0.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

 

Now using the default ProcessQueueMessage function that uses a QueueTrigger, we will call the ProcessMessage method. This method checks if the message is empty. If it is, an exception will be thrown.

Then we create a function named GlobalErrorMonitor. This function will catch errors and send emails using SendGrid:

using System;
using System.IO;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions;
using SendGrid.Helpers.Mail;

namespace AzureWebJobs.ErrorsEmails
{
    public class Functions
    {
        // This function will get triggered/executed when a new message is written 
        // on an Azure Queue called queue.
        public static void ProcessQueueMessage([QueueTrigger("queue")] string message, TextWriter log)
        {
            log.WriteLine(message);

            ProcessMessage(message);
        }

        /// <summary>
        /// Triggered when an error is reported in other functions.
        /// Called whenever 2 errors occur within a 3 minutes sliding window (throttled at a maximum of 2 notifications per 10 minutes).
        /// </summary>
        public static void GlobalErrorMonitor([ErrorTrigger("0:03:00", 2, Throttle = "0:10:00")] TraceFilter filter, TextWriter log, [SendGrid(From = "no-reply@anydomainxyz.com", To = "anybody@anydomainxyz.com")] out Mail mail)
        {
            mail = new Mail();

            mail.Subject = "WebJob - Warning - An error has been detected in a job";
            mail.AddContent(new Content("text/plain", filter.GetDetailedMessage(1)));

            Console.Error.WriteLine("An error has been detected in a function.");

            log.WriteLine(filter.GetDetailedMessage(1));
        }

        private static void ProcessMessage(string message)
        {
            if (string.IsNullOrEmpty(message))
            {
                throw new ArgumentNullException(nameof(message));
            }

            //Do some work here...
        }
    }
}

You can notice two things here:

 

Example of use

Once the WebJob ready and properly configured, we will launch it:

Found the following functions:
AzureWebJobs.ErrorsEmails.Functions.ProcessQueueMessage
Job host started

Now add an empty message to the queue. The ProcessQueueMessage function will be called 5 times and the message will be moved to the queue-poison.

After the second exception, you can notice that GlobalErrorMonitor is triggered:

Executing 'Functions.ProcessQueueMessage' (Reason='New queue message detected on 'queue'.', Id=8ee22555-15df-458e-8a0e-cdd1b9b2a97a)
Executing 'Functions.GlobalErrorMonitor' (Reason='Error trigger fired', Id=8b368696-7dab-4908-af53-18018abd8f3e)
An error has been detected in a function.
2 events at level 'Error' or lower have occurred within time window 00:03:00.

05/16/2017 02:41:20 Error Exception while executing function: Functions.ProcessQueueMessage WebJobs.Execution
Microsoft.Azure.WebJobs.Host.FunctionInvocationException: Exception while executing function: Functions.ProcessQueueMessage ---> System.ArgumentNullException:
Value cannot be null. Parameter name: message

Executed 'Functions.GlobalErrorMonitor' (Succeeded, Id=8b368696-7dab-4908-af53-18018abd8f3e)
Executed 'Functions.ProcessQueueMessage' (Succeeded, Id=8ee22555-15df-458e-8a0e-cdd1b9b2a97a)

 You should receive an email to the address you've specified in the To property of the SendGrid attribute. The title will be as WebJob - Warning - An error has been detected in a job, and the body will contain the exception with the stack trace.

 

To go further

The error trigger is configured to be called whenever 2 errors occur within a 3 minutes sliding window throttled at a maximum of 2 notifications per 10 minutes.

You can easily configure it differently to receive less notifications:

public static void GlobalErrorMonitor([ErrorTrigger("0:10:00", 5, Throttle = "1:00:00")] TraceFilter filter, TextWriter log, [SendGrid(From = "no-reply@anydomainxyz.com", To = "anybody@anydomainxyz.com")] out Mail mail)

 

 

Summary

We have seen how to send emails from an Azure WebJob with the SenGrid extension when errors are detected using the ErrorTrigger extension.

 

You can download the example solution here:

Download full sources

Or

Browse the GitHub repository

(Note that the project uses Microsoft.Azure.WebJobs version 2.0.0)

 

Please feel free to comment or contact me if you have any question about this article.

Add a comment

(Will not be published)

Back to articles