← All guides

Guide · Serverless

Monitor Azure Functions (timer trigger)

A timer-triggered function can silently stop firing (a bad deploy, a disabled app, an exhausted plan) and nothing tells you. Add one HTTPS call at the end of the handler and Mortemain will.

1. Create a check

Create a check in Mortemain and copy its unique ping URL:

 your ping URL
https://ping.mortemain.com/your-check-uuid

2. Ping at the end of the handler (C#)

Call the URL when the function finishes; call /fail from the catch block so an unhandled exception alerts immediately instead of waiting for the next scheduled run:

 NightlyExport.cs
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs;
using Microsoft.Extensions.Logging;

public static class NightlyExport
{
    private static readonly HttpClient client = new HttpClient();
    private const string PingUrl = "https://ping.mortemain.com/your-check-uuid";

    [FunctionName("NightlyExport")]
    public static async Task Run(
        [TimerTrigger("0 0 3 * * *")] TimerInfo myTimer, ILogger log)
    {
        try
        {
            await RunExportAsync();                 // your work
            await client.GetAsync(PingUrl);          // success
        }
        catch (Exception ex)
        {
            await client.PostAsync(PingUrl + "/fail",
                new StringContent(ex.Message));      // failure, alerts immediately
            throw;
        }
    }
}

3. Same idea in Python

The Python v2 programming model wires up the same pattern with requests:

 function_app.py
import azure.functions as func
import requests

app = func.FunctionApp()
PING_URL = "https://ping.mortemain.com/your-check-uuid"

@app.timer_trigger(schedule="0 0 3 * * *", arg_name="myTimer",
                    run_on_startup=False, use_monitor=False)
def nightly_export(myTimer: func.TimerRequest) -> None:
    try:
        run_export()                        # your work
        requests.get(PING_URL, timeout=10)  # success
    except Exception:
        requests.get(f"{PING_URL}/fail", timeout=10)  # failure, alerts immediately
        raise

4. Match the NCRONTAB schedule

Timer triggers use NCRONTAB expressions: six fields ({second} {minute} {hour} {day} {month} {day-of-week}) instead of the usual five, evaluated in UTC unless the app sets WEBSITE_TIME_ZONE. 0 0 3 * * * fires once a day at 03:00 UTC. Give the Mortemain check the same schedule (drop the seconds field) and a grace window that covers your typical run time plus some margin for a cold start on the Consumption plan.

Track duration (optional)

Call /start right as the handler begins and Mortemain records how long each run takes, useful for spotting a job that's quietly getting slower:

 NightlyExport.cs
await client.GetAsync(PingUrl + "/start");   // marks the run as started

Test it

Trigger the function once (wait for the schedule, run it locally with func start, or use the "Test/Run" panel in the portal). The check flips to up within a second or two of the ping; miss its window and you'll get the down alert. Throw a test exception to confirm the /fail path too.