• 4 min read

Updates in Azure WebJobs SDK (1.1.0-alpha2)

We recently released a preview of the WebJobs SDK including new features and bug fixes in addition to opening up a new extensibility model allowing you to write your own triggers and binders.

We recently released a preview of the WebJobs SDK. In addition to other new features and bug fixes, the release also opens up a new extensibility model allowing you to write your own triggers and binders. In this latest release we have added more extension triggers and binders in addition to introducing the Singleton feature which allows you to declaratively specify that only a single instance of a particular job function should run at any given time, even across multiple scaled out instances.

You can download the WebJobs SDK from the NuGet gallery and can install these packages from the NuGet gallery using the NuGet Package Manager Console.

Singleton

Singleton allows you to ensure that only one a single instance of the function will be executed when you scale out your workload to multiple instances. The following code shows an example.

 

    public class Program
    {
        static void Main(string[] args)
        {
            var host = new JobHost();
            host.RunAndBlock();
        }

        [Singleton]
        public static async Task SingletonJob()
        {
            // Process only once when scaled out
            await Task.Delay(10 * 1000);
        }

        // Only a single instance of this function will be invoked at a time for the specified scope.
        [Singleton(@"{Region}{Zone}")]
        public static async Task SingletonScopeJob(
            [QueueTrigger("singleton-test")] WorkItem workItem, TraceWriter trace)
        {
            trace.Info("Singleton method started");
            await Task.Delay(10 * 1000);
            trace.Info("Singleton method completed");
        }

        public class WorkItem
        {
            public int ID { get; set; }
            public string Region { get; set; }
            public int Zone { get; set; }
            public int Category { get; set; }
            public string Description { get; set; }
        }
    }

 

You can also specify a scope expression/value on the Singleton attribute which will ensure that all executions of the function at that scope will be serialized. For example, in the above code if the queue contains 3 messages in Regions “East”, “East” and “West” respectively, then the messages that have region “East” will be executed as serially while the message with region “West” will be executed in parallel with those. This is useful if your function needs to access other distributed resources or perform other operations that should not/cannot be performed concurrently. A full sample can be accessed here.

Timer Trigger now uses this singleton feature to ensure that only instance of the Timer Trigger fires when you scale out your workload to multiple instances. I.e., for a scheduled job, you don’t want multiple scaled out instances to be invoked for each schedule occurrence – you only want to be notified once.

Community spotlight: Redis Trigger

We wanted to highlight an example of a trigger authored by one of the community members using the new extensibility model. Jason Haley (@haleyjason) has written a Redis Trigger which you can use to trigger functions based on Redis events. For example, each time an item is inserted in Redis, your function can be triggered. You can find this open source project here and follow the progress.

The following code shows a function which can be triggered for Redis.

public static void ReceivePubSubMessage([RedisTrigger("messages", Mode.PubSub)] string message,
                   TextWriter log)
{
       log.WriteLine(“Message=”+message);
}

 

Other updates in this release

For a detailed list of all improvements in this release, please refer to the release notes and bugs fixed. I am highlighting the key ones here.

Logging/tracing extensibility

  • The logging system is now extensible so you can plug in your TraceWriters and integrate your own logging solution with the SDK.
  • Allow custom TraceWriters to be plugged into the host via JobHostConfiguration.Tracing
  • Allow the Console output TraceLevel to be customized via JobHostConfiguration.Tracing.ConsoleLevel
  • Added a new TraceWriter binding (similar to TextWriter) that allows functions to bind to the TraceWriter
  • Find a sample here.

Service Bus messaging improvements

  • Support message processing concurrency by default (previously there was no concurrency)
  • Allow deep customization of Message processing via ServiceBusConfiguration.MessagingProvider
  • MessagingProvider supports customization of the ServiceBus MessagingFactory and NamespaceManager
  • A new MessageProcessor strategy pattern allows you to specify a processor per queue/topic
  • Easy Easy customization of *OnMessageOptions *via ServiceBusConfiguration.MessageOptions
  • Find a sample here.

New binder (SendGrid) added in the Nightly Builds

As part of going open source, we have been publishing our nightly builds to MyGet. Recently we added SendGrid binder which allows you to send emails using SendGrid.

Imagine a scenario where you have an order processing WebJob where the queue message contains the order information. You can send email on successful order processing and also notify yourself when an error happens.

The following code shows how you can easily integrate this in your WebJob. You need to install Microsoft.Azure.WebJobs.Extensions.SendGrid NuGet package.

public class Program
    {
        static void Main(string[] args)
        {
            var hostConfig = new JobHostConfiguration();
            hostConfig.UseSendGrid();
            var host = new JobHost(hostConfig);
            host.RunAndBlock();
        }
        public static void ProcessOrder(
           [QueueTrigger(@"samples-orders")] Order order,
           [SendGrid] SendGridMessage message)
        {
            message.AddTo(order.CustomerEmail);
            message.Subject = $"Thanks for your order (#{order.OrderId})!";
            message.Text = $"{order.CustomerName}, we've received your order ({order.OrderId}) and have begun processing it!";
        }
        public static void ProcessOrderFailure(
         [QueueTrigger(@"samples-orders-poison")] string queueMessage,
         [SendGrid] SendGridMessage message)
        {
            message.AddTo("AdminEmail");
            message.Subject = "Order processing failed";
            message.Text = queueMessage;
        }
        public class Order
        {
            public int OrderId { get; set; }
            public string CustomerName { get; set; }
            public string CustomerEmail { get; set; }
        }
    }Open Source

 

The source code for the SDK, extensibility system and related repos is available here:

Please provide feedback and send PR’s for any issues you want to fix. We are looking forward to different types of triggers and binders you are interested in adding.

Samples

Documentation

Give feedback and get help

If you have questions, you can ask them on the Azure forum, the ASP.NET forum, or StackOverflow.com. Use #AzureWebJobs on Twitter and the tag Azure-WebJobsSDK on StackOverflow.