Blog.Amit Apple

Blog by Amit Apple

Scheduling Azure WebJobs with cron expressions

Scheduled WebJobs have existed from the beginning of Azure WebJobs, they are a result of combining 2 different Azure resources: a triggered WebJob containing the script to run and an Azure Scheduler job containing the schedule to use.

The Azure Scheduler job would point to the triggered WebJob invoke url and would make a request to it on schedule.

There have been some difficulties with this approach mainly around the deployment part of the schedule which convinced us to build another scheduler implementation that is built into kudu (the WebJobs host) which enables a scheduled WebJob to be deployed by simply adding a file with the WebJob binaries.

How to add a schedule to a triggered WebJob

The way to add a schedule to a triggered WebJob is by adding a file called settings.job with the following json content: {"schedule": "the schedule as a cron expression"}, this file should be at the root of the WebJob directory (next to the WebJob executable).

If you already have this file with other settings simply add the schedule property.

The schedule is configured using a cron expression which is a common way to write schedules.

CRON Expressions

There are many pages that can teach you how to write a cron expression, I will describe the main format used for the scheduled WebJob.

  • The cron parsing is implemented by NCrontab nuget package.
  • The cron expression is composed of 6 fields: {second} {minute} {hour} {day} {month} {day of the week}.
  • The supported operators are: , - * /
  • Each field can have a specific value (1), a range (1-10), a set of values (1,2,3), all values (), an interval value (/2 == 0,2,4,6,...) or a mix of these (1,5-10).
  • Each value represents a point in time, for example: "5 * * * * *" - means on the 5th second of every minutes --> 00:00:05, 00:01:05, 00:02:05, ... (and not every 5 seconds).


  • 0 0 13 * * * - 1pm every day.
  • 0 15 9 * * * - 9:15am every day.
  • 0 0/5 16 * * * - Every 5 minutes starting at 4pm and ending at 4:55pm, every day.
  • 0 11 11 11 11 * - Every November 11th at 11:11am.

You can find some more cron expression samples here but note that they have 5 fields, to use them you should add a 0 as the first field (for the seconds).

Important - To use this way of scheduling WebJobs you'll have to configure the website as Always On (just as you would with continuous WebJobs) otherwise the scm website will go down and the scheduling will stop until it is brought up again.

Debugging a schedule

To see the scheduler logs for a scheduled WebJob you need to use the get triggered WebJob api, go to the url: https://{sitename}{jobname} (remove the job name to see all triggered WebJobs).

You will receive the following json result:

    name: "jobName",
    runCommand: "...\run.cmd",
    type: "triggered",
    url: "http://.../triggeredwebjobs/jobName",
    history_url: "http://.../triggeredwebjobs/jobName/history",
    extra_info_url: "http://.../",
    scheduler_logs_url: "https://.../vfs/data/jobs/triggered/jobName/job_scheduler.log",
    settings: { },
    using_sdk: false,
        id: "20131103120400",
        status: "Success",
        start_time: "2013-11-08T02:56:00.000000Z",
        end_time: "2013-11-08T02:57:00.000000Z",
        duration: "00:01:00",
        output_url: "http://.../vfs/data/jobs/triggered/jobName/20131103120400/output_20131103120400.log",
        error_url: "http://.../vfs/data/jobs/triggered/jobName/20131103120400/error_20131103120400.log",
        url: "http://.../triggeredwebjobs/jobName/history/20131103120400",
        trigger: "Schedule - 0 0 0 * * *"

The scheduler_logs_url property has a url that will get you the scheduler log, that log will tell you some verbose information on the scheduling and invocation of the triggered WebJob.

There is also a trigger property for a triggered WebJob run that tells you which schedule (or external user agent) invoked the specific run.

More information about WebJobs API.

Adding a schedule for an on demand WebJob in Visual Studio

If you have a Visual Studio Azure WebJob project, the way to add a schedule is by authoring the settings.job file described above and adding it to the project. In the solution explorer you'll need to change the properties of that settings.job file and set the Copy to output directory to Copy always.

This will make sure the file is in the root directory of the WebJob.

Changing (or setting/removing) a schedule of a triggered WebJob is all about updating the schedule property of the settings.job file in the WebJob's directory (d:\home\site\wwwroot\App_Data\jobs\triggered\{jobname}), whenever the file is updated the change is picked up and the schedule will change according.

This means you can deploy the schedule in any way you wish including by updating the file on your git repository.

Differences between the two scheduled WebJobs

There are pros and cons to each way of scheduling a WebJob, review them and choose which way to go.

Azure Scheduler


  • Doesn't require the website to be configured as Always On.
  • Supported by Visual Studio tooling and the current Azure portal.


  • Doesn't support continuous integration - to schedule a job or reschedule a job you'll need access to your Azure account.
  • Loosely tied to the triggered WebJob, you cannot always tell that a WebJob has an Azure Scheduler job behind it.

Internal WebJob Scheduler


  • Supports continuous integration and any deployment mechanism available for Azure Web Apps as it is file based.
  • Supports the common cron expressions.
  • Can tell a WebJob is scheduled with a simple api call.


  • Requires Always On.
  • Not yet supported by tooling and portal (hopefully that will change).


To summarize, we've introduced a new way to schedule WebJobs that is continuous deployment friendly, in some cases it won't be the right one to choose but if the cons doesn't bother you it is a simpler and way for you to schedule triggered WebJobs.

Please let us know how it works for you in the comments or better yet on kudu project issues.


Azure Websites --> Web Apps Rename

Recently Azure Websites were renamed to Azure Web Apps, I've applied (or at least tried to apply) this rename to my blog posts.

One more concept that was renamed is Web Hosting Plan (also known as Server Farm) renamed to App Service Plan.


Azure Web Apps (Websites) Deployment Slots - Explained

One of the premium features you get when using Azure Web Apps in a standard SKU is the deployment slots feature also known as staged deployment but it is actually more than that.

In this post I will go over the deployment slots concept and what you can do with it.

Deployment slots

What are those deployment slots?

From a (standard) website you can create deployment slots which will actually be Azure Web App instances that are tied to that Website.

A deployment slot will carry the name of the Azure Web App + the name of the slot, for example:

If my Azure Web App is called mysite and I create a slot called staging then my slot will be an Azure Web App with the name mysite(staging) and its url will be

Add deployment slot

It's important to emphasize that the slot is in itself a regular Azure Web App, it will have its own app settings, connection string, any other configuration settings and even an scm site (

In fact by default each Azure Web App has a single deployment slot called production which is the Azure Web App itself.

You can add more than one deployment slot.

Why do I need this?

The first feature of deployment slots is the Swap Slots and it's used for Staged Deployment

Add deployment slot

In short, the Swap operation will exchange the website's content between 2 deployment slots.

Later I'll explain what is swapped and what is not but note that swap is not about copying the content of the website but more about swapping DNS pointers.

So in our scenario we have the Production site with index.html that starts with Hello World and our staging slot has the same index.html but it starts with Yello World.

Before swap - will return Hello World...

After swap - will return Yello World...

Now to get this into a real life scenario.

Staged Deployment

Deploying your website in the traditional way, whether deploying via WebDeploy, FTP, git, CI or any other way, has weaknesses that may or may not concern you:

  • After the deployment completes the website might restart and this results in a cold start for the website, the first request will be slower (can be significant depending on the website).
  • Potentially you are deploying a "bad" version of your website and maybe you would want to test it (in production) before releasing it to your customers.

This is where staged deployment comes into play. Instead of deploying directly to our production website we create a deployment slot used for staging and we deploy our new bits there.

Then we "warm" our site (staging slot) by making requests to it and we can start testing our new bits verifying everything works as expected. Once we're ready we hit the Azure Portal's Swap button (or PowerShell/xplat cli command) and the slots will be swapped.

Our customers will not hit the "cold start" delay and we have more confidence in our new bits.


Since we want to test our website before going into production we have this manual step where we hit the Swap button to swap.

But if we only want to address the "cold start" delay we can configure the Auto Swap feature where the website automatically swaps a configured slot (in our case staging) with the Production slot after the deployment completes.

Currently auto-swap only works when deploying using WebDeploy (deploying through VS will usually use WebDeploy) and Continuous Integration (VSO, GitHub, Bitbucket). FTP and git push will not cause an auto swap.

Auto-swap can take a while to swap (1-2 minutes), until the swap completes any other attempts to deploy the website will fail.

To set this up you'll need to use the Azure PowerShell tool (download)

In PowerShell use the following command:

Set-AzureWebsite -Name mysite –Slot staging -AutoSwapSlotName production

This command will set Azure Web Apps to auto swap the staging slot into Production slot whenever staging is deployed.

You can use the operation logs in the (current) Azure portal to see the auto swap operation status.

Deployment Slot App Settings / Connection String / Configuration

One important concept to understand about deployment slots is how the configuration works.

A deployment slot is a full Azure Web App and as one it has all the same configurations as any Azure Web App. When you swap deployment slots there are some settings you actually need to keep with the slot and not swap them.

A setting that is not swapped is referred to as a setting that is sticky to the slot.

Some of the default settings that are sticky to the slot:

  • Most obvious one is the url - will always point to the staging slot.
  • WEBSITE_HOSTNAME environment variable for the staging slot will always be and this is something we can use in our website code to find it's currently running in the Production slot or staging slot.
  • Deployment settings - if you have the deployment profile for the staging slot, after a swap the profile would still point to the staging slot.

    This also includes continuous integration settings - if you hooked your staging slot with a GitHub repository after a swap the hook will still exist between GitHub and the staging slot.

App settings and connection strings are not sticky to the slot and will remain with the website when swapped but we can configure selected app settings and connection strings to become sticky to the slot using a PowerShell command (not yet supported by the Azure portal).

Use this command in Azure PowerShell to set 2 app settings as sticky to the slot

Set-AzureWebsite -Name mysite -SlotStickyAppSettingNames @("myslot", "myslot2")

And this command to set 2 connection strings as sticky to the slot

Set-AzureWebsite -Name mysite -SlotStickyConnectionStringNames @("myconn", "myconn2")

Sticky to the slot configuration is website-wide configuration and affects all slots in that website.

Deployment Slots Traffic Routing

Another great feature for deployment slots is the traffic routing also known as testing in production.

This feature will allow you to route traffic that is coming to your Azure Web App between your deployment slots based on percentage of the traffic.

This feature exists only in the new Azure preview portal.

In the portal under your website there is a tile called Testing in production, click on it to get to the "Testing in production" blade where you can direct traffic coming to your website between all of your deployment slots.

Testing in production

One usage scenario for this feature is A/B testing.

By default 100% of the traffic will go to the Production slot but you can create a new deployment slot with a slightly different version of your website (differs by what you want to A/B test) and add it there with a 50% value so 50% of your visitors will actually be served from the new slot.

Another scenario for this feature is having a dev slot that is a little less stable which gets 1% of the traffic so you can test feature currently being developed with real traffic.

For more information on this feature.

Wrap Up

I hope that if the deployment slots were just a mysterious link/tile/concept before, you now know how to master them as they can bring lots of value to your production website.