DEV Community

Victorio Berra
Victorio Berra

Posted on • Edited on

Gotchas when deploying a WebJob to Azure.

Azure App Services - Deploying a .NET Core 3.1 worker as a schedule triggered WebJob via DevOps

This article will cover some issues I ran into creating a new .NET Core 3.1 worker as a scheduled triggered WebJob on Azure App Services (AAS)

You might need to be a little familiar with: .NET Core, Azure DevOps, AAS, Kudu.

Goals

Lean into conventions as much as possible. Avoid complicated customization to the pipelines YAML, or deployment pipeline or unnecessary extra scripts and files in the repo.

Getting Started

Environment

  • Create the AAS as Windows only because WebJobs are not yet available on Linux.
  • Enable Always-On (so the scheduler works). You may see Core 3.1 Runtime is not on the Windows AAS according to the Azure Portal GUI but it actually is.

Pipeline

Creating the app from scratch is easy: dotnet new worker --name MyFirst.Worker

Create a very basic .NET Core azure-pipeline.yaml, all it needs to do is run the core publish task and then publish the artifact. The core template for DevOps does this out of the box.

Use this guide: https://docs.microsoft.com/en-us/azure/devops/pipelines/ecosystems/dotnet-core?view=azure-devops

steps:

# ...

- task: DotNetCoreCLI@2
  inputs:
    command: publish
    publishWebProjects: True
    arguments: '--configuration $(BuildConfiguration) --output $(Build.ArtifactStagingDirectory)'
    zipAfterPublish: True

# this code takes all the files in $(Build.ArtifactStagingDirectory) and uploads them as an artifact of your build.
- task: PublishBuildArtifacts@1
  inputs:
    pathtoPublish: '$(Build.ArtifactStagingDirectory)' 
    artifactName: 'MyFirstWorker'
Enter fullscreen mode Exit fullscreen mode

Run the build and verify your worker was published.

First gotcha:

Always generate an Exe. Kudu looks for specific files to run. If you use the DevOps Ubuntu agent, you wont get an Exe. So how can we ALWAYS get one?

You need to edit the publish arguments in your pipeline YAML and add -r win-x86 --self-contained false. this will force Core to spit out an Exe for windows, even when publishing on Ubuntu. WITHOUT creating a self contained deployment. Although, there is nothing wrong with creating an SCD if you want. might even be a good idea, but for this tutorial I want to go from dotnet new to a working deployment without lighting up every feature in Core and without adding more scripts and files to my repo.

NOTE: To see how Kudu picks something to run, check the Wiki for WebJobsKudu wiki.

Second gotcha:

The path you deploy to in AAS for web jobs is highly specific. It MUST be in one of the following:

For a triggered (or scheduled) job, the folder is wwwroot\app_data\jobs\triggered\{job name}, and for a continuous job, it's wwwroot\app_data\jobs\continuous\{job name}. This is easily achieved by setting the --output flag on your dotnet publish to publish into a directory like that.

Mark Heath has a great blog post on a very similar topic:

Why the app_data folder? Well that's a special ASP.NET folder that is intended for storing your application data. The web server will not serve up the contents of this folder, so everything in there is safe. It's also considered a special case for deployments - since it might contain application generated data files, its contents won't get deleted or reset when you deploy a new version of your app.

To expand on Marks last line, in Azure DevOps Pipelines -> Deployments -> Deploy AAS Task there is actually a checkbox to blow away the app_data folder if you want. I thought that was interesting.

The Kudu WebJob wiki also says:

As an alternative, d:\home\site\jobs\... can be used instead of d:\home\site\wwwroot\app_data\jobs\.... This is useful when using Run-From-Zip, which makes d:\home\site\wwwroot become read-only.

But I haven't tested this.

Third gotcha:

Make sure to copy always the settings.job file. AND it uses https://github.com/atifaziz/NCrontab which requires a seconds field. I first tried 5 0 * * * and then had to go back and do 0 5 0 * * * this means run 5 minutes after midnight every day.

This is trivial to verify, go to your AAS in the portal, and click the WebJob blade, you should see your schedule.

Full YAML

trigger:
- master

pool:
  vmImage: 'ubuntu-latest'

variables:
  buildConfiguration: 'Release'

steps:

- task: DotNetCoreCLI@2
  inputs:
    command: publish
    publishWebProjects: False
    arguments: '--configuration $(BuildConfiguration) --output $(Build.ArtifactStagingDirectory)'
    zipAfterPublish: True

- task: PublishBuildArtifacts@1
  inputs:
    pathtoPublish: '$(Build.ArtifactStagingDirectory)' 
    artifactName: 'myWebsiteName'
Enter fullscreen mode Exit fullscreen mode

Things id like to know more about:

  • How to use Run-From-Zip WebJobs
  • How to add a WebApp to my repo, and deploy that with my WebJob at the same time.

SEO Tags: Azure,App,Services,Deploying,.NET,Core,3.1,worker,schedule,triggered,WebJob,DevOps

Top comments (3)

Collapse
 
dielawn profile image
Dylan Farrell

Great article!

Collapse
 
ttjackott profile image
Jack S

Great article! Would be helpful if you'd included the finished modified yaml at the very end of the article though :)

Collapse
 
victorioberra profile image
Victorio Berra

There was only a couple missing lines, I added the full build YAML at the end though.