Deploying an Azure WebJob with GitHub Actions

enter image description here

WebJobs are a hidden gem within Azure App Service. While it's coupled to the web application, one of the neat tricks is to turn it into a worker service for continuous background processing. Arguably, this could be also accomplished by Azure Functions, but in certain scenarios, it's simpler to have an equivalent of what used to be a Windows Service. I will skip the building a WebJob part. It's sufficiently enough documented by Microsoft. Yves Goeleven has done some really nice work with WebJobs he'd be happy to share with those that are looking for ideas. And while what he's done is great, I will mention that I'd love to see a WebJob as a Service kind of offer coming soon. Or some Worker as a role. Something that would fill in the gap that is there. Not everything is containers/Kubernetes or Functions. And using WebJobs under the App Service umbrella feels like hunting a mosquito with a canon. Without further ado, how to deploy a WebJob using GitHub actions?

Assumptions

Operation system

When using GitHub actions, the operating system used matters. Windows images are twice more expensive than Linux. This directly translates into having half the free minutes when running with Windows. While it's not the biggest factor, there's really no reason to demand a Windows image when building, testing, and deploying to Azure a .NET based WebJob. Therefore, I'll be using a Linux image for this post.

Conditional execution

If you're like me and push almost every commit, it can become quite expensive very fast. I also like to work in PRs, leveraging draft PRs as an indication the work is still in progress. With that in mind, I'd like to avoid unnecessary deployments on PR builds while PRs are marked as draft PRs. In addition to that, I'll skip the packaging of the WebJob if a deployment is not taking place. While it's such a small optimization, it leads to faster build execution.

Managing secrets

GitHub Actions has support for creating and managing secrets. I'll use that and frankly, recommend you always store your secrets that way. In my example, I'll be storing .publishsettings files retrieved from the portal as GitHub secrets.

Project structure

WebJobSolution/
├── .github/workflows/
│   └── dotnet-core.yml
└── src/
    ├── worker
    │   ├── worker.csproj
    │   ├── run.cmd
    │   ├── settings.job
    │   └── ...
    └── worker.sln

Action script

name: .NET Core

env:
  BINARIES: './output/app_data/jobs/continuous/mywebjob' # the last folder name will become the webjob name in the portal
  ZIP_FILE: 'webjob.zip'
  ZIP_PATH: './output'
  ZIP_FILEPATH: './output/webjob.zip'

on:
  push:
    branches: [ master, develop ]
  pull_request:
    branches: [ master, develop ]
    types: [review_requested, ready_for_review]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v2

    - name: Setup .NET Core
      uses: actions/setup-dotnet@v1
      with:
        dotnet-version: 3.1.101

    - name: Install dependencies
      run: dotnet restore ./src/worker.sln

    - name: Build
      run: dotnet build ./src/worker.sln --configuration Release --no-restore --output ${{env.BINARIES}}
    
    - name: Test
      run: dotnet test ./src/worker.sln --no-restore --verbosity normal --output ${{env.BINARIES}}

    - name: Zip
      if: github.event_name != 'pull_request' # skip on PRs
      uses: nguyenquyhy/zip-release@v0.3.0
      with:
        filename: '${{env.ZIP_FILE}}'
        workingDirectory:  ${{env.ZIP_PATH}}
        exclusions: 'worker.exe app_data/**/unix/*' # skip .exe and Unix runtime as deployment will be to a Windows App Service

    - name: Deploy to Test (develop branch) # skip on PRs
      if: github.ref == 'refs/heads/develop' && github.event_name != 'pull_request' # skip on PRs, deploy develop branch to the test environment
      uses: srijken/azure-zip-deploy@v1.0.1
      with:
        zip-file: ${{env.ZIP_FILEPATH}}
        publish-profile: ${{ secrets.WEBJOB_PUBLISH_PROFILE_TEST }}

    - name: Deploy to Production (master branch)
      if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request' # skip on PRs, deploy master branch to the production environment
      uses: srijken/azure-zip-deploy@v1.0.1
      with:
        zip-file: ${{env.ZIP_FILEPATH}}
        publish-profile: ${{ secrets.WEBJOB_PUBLISH_PROFILE_PROD }}

With this fairly small script, an automated CI/CD will be executed and deploy the WebJob whenever a change is done on develop or master branches, deploying the bits into the testing or production environment. Happy deploying!

No Comments

Add a Comment

As it will appear on the website

Not displayed

Your website