Code Must Run on Demand or Schedule? Create HTTP and Timer Functions

Published on:

CloudTrips needs a small API endpoint and a recurring background job. Azure Functions runs code when a trigger fires and scales the underlying compute without requiring a permanently managed server.

Function App: Shared host, configuration, deployment, and scaling boundary
HTTP function: Runs when an HTTP request arrives
Timer function: Runs according to a CRON schedule

Both functions can share one Function App because they belong to the same small application and use the same lifecycle. The later Durable Functions trip uses a separate app because it introduces stateful workflow orchestration.

Create the Function App

Search for Function App, select Create, choose Flex Consumption, and select Select. Enter:

Subscription: CloudTrips TEST
Resource group: rg-cloudtrips-functions-test-weu
Function App name: func-cloudtrips-events-dmytro-test-weu
Region: West Europe
Runtime stack: Node.js
Version: 22 LTS
Instance size: 2048 MB

The Function App name must be globally unique. Use the newest Node.js LTS version offered by the portal if 22 LTS is no longer listed.

On Storage, create the default host storage account. A Function App uses storage for host coordination, trigger state, and deployment packages; it is not optional even when the function code stores no business data.

On Monitoring, keep Enable Application Insights enabled. On Authentication, select Managed identity for all resources. Accept the remaining defaults, then select Review + create > Create.

Flex Consumption is the recommended serverless plan, scales to zero when idle, and charges mainly for executions and consumed resources. Application Insights and Storage can incur small additional charges.

Create Function App page showing Node.js on the Flex Consumption plan

Create the Local Project

Create this structure on your Mac:

cloudtrips-functions/
├── host.json
├── package.json
└── src/
    └── functions/
        ├── http.js
        └── timer.js
mkdir -p cloudtrips-functions/src/functions
cd cloudtrips-functions

Create host.json:

{
  "version": "2.0",
  "logging": {
    "applicationInsights": {
      "samplingSettings": {
        "isEnabled": false
      }
    }
  }
}

Disabling sampling makes this small lab’s timer invocations easier to find. In a busy production app, sampling normally controls telemetry volume and cost.

Create package.json:

{
  "name": "cloudtrips-functions",
  "version": "1.0.0",
  "main": "src/functions/*.js",
  "scripts": {
    "start": "func start"
  },
  "dependencies": {
    "@azure/functions": "^4.7.2"
  }
}

The main pattern tells the Node.js v4 programming model where to load the function registrations.

Add the HTTP Function

Create src/functions/http.js:

const { app } = require('@azure/functions');

app.http('cloudTripsHttp', {
  methods: ['GET'],
  authLevel: 'anonymous',
  route: 'cloudtrips',
  handler: async (request, context) => {
    const name = request.query.get('name') || 'traveler';
    context.log(`HTTP request received for ${name}`);

    return {
      headers: { 'Content-Type': 'application/json' },
      jsonBody: {
        message: `Hello, ${name}!`,
        trigger: 'HTTP'
      }
    };
  }
});

anonymous keeps the lab endpoint easy to call. Production APIs normally use Function keys, App Service Authentication, API Management, or another authentication layer.

Add the Timer Function

Create src/functions/timer.js:

const { app } = require('@azure/functions');

app.timer('cloudTripsTimer', {
  schedule: '0 */5 * * * *',
  handler: async (timer, context) => {
    context.log(`CloudTrips scheduled job ran at ${new Date().toISOString()}`);

    if (timer.isPastDue) {
      context.warn('The timer invocation was later than scheduled.');
    }
  }
});

Azure Functions timer expressions have six fields:

second minute hour day month day-of-week
0      */5    *    *   *     *            → every five minutes

The schedule is evaluated in UTC by default. The Functions host uses its storage account to coordinate the timer so scaled-out instances do not all run the same scheduled occurrence.

Deploy Both Functions

From cloudtrips-functions, create a deployment package containing the project contents—not the parent folder:

zip -r cloudtrips-functions.zip host.json package.json src

Deploy it and let Azure install the Node dependency remotely:

az functionapp deployment source config-zip \
  --resource-group rg-cloudtrips-functions-test-weu \
  --name func-cloudtrips-events-dmytro-test-weu \
  --src cloudtrips-functions.zip \
  --build-remote true

Flex Consumption uses One Deploy behind this command: Azure stores and mounts the deployment package instead of editing files directly in the portal. Wait for the command to finish, then open Functions in the Function App. Both cloudTripsHttp and cloudTripsTimer should appear.

Function App Functions page showing cloudTripsHttp and cloudTripsTimer

Test the HTTP Trigger

Open cloudTripsHttp, select Get Function URL, and copy the URL. Call it from your Mac, adding the query parameter:

curl --fail --show-error \
  '<FUNCTION_URL>?name=Dmytro'

The ? starts the URL’s query string and name=Dmytro supplies the name parameter read by the function. Because this lab uses authLevel: 'anonymous', the copied Function URL normally has no existing ?code=... query string. Expected JSON:

{"message":"Hello, Dmytro!","trigger":"HTTP"}

The request is the event that triggers this function.

Terminal showing the successful JSON response from cloudTripsHttp

Verify the Timer Trigger

Wait at least five minutes. Open cloudTripsTimer, select Monitor, and open Invocations. Application Insights ingestion can take several minutes, so refresh until a successful invocation appears. Open it and confirm its logs include:

CloudTrips scheduled job ran at

The timer has no public URL. The Functions host invokes it from the CRON schedule and records the execution in Application Insights.

Timer function Monitor page showing a successful scheduled invocation

Clean Up

Delete the standalone resource group to remove the Function App, storage, monitoring resources, and any continuing charges:

az group delete \
  --name rg-cloudtrips-functions-test-weu \
  --yes

Confirm that it is gone:

az group exists --name rg-cloudtrips-functions-test-weu

Expected result: false.