Skip to content

07 - Extending Triggers (Premium)

Add queue, timer, and blob triggers with the Node.js v4 APIs and verify they execute on the Premium plan.

Prerequisites

  • You completed 06 - CI/CD.
  • Your function app is deployed and has storage resources (queue, blob containers).
Tool Version Purpose
Node.js 20+ Local runtime and package execution
Azure Functions Core Tools v4 Local host and publishing
Azure CLI 2.61+ Azure resource provisioning and management

Plan basics

Premium provides always-warm instances, VNet integration, deployment slots, and unlimited timeout support.

What You'll Build

You will extend your app with a timer trigger (scheduledCleanup), a queue trigger (queueProcessor), and a blob trigger (blobProcessor). You will deploy, send test messages, and verify trigger execution via Application Insights.

Infrastructure Context

Plan: Premium (EP1) | Triggers: HTTP + Timer + Queue + Blob

Premium supports all Azure Functions triggers with no timeout limits. Queue and blob triggers use the AzureWebJobsStorage or a dedicated connection string.

flowchart TD
    FA[Function App\nPremium EP1]

    TIMER[Timer Trigger\nscheduledCleanup\nevery 5 min] --> FA
    QUEUE[Queue Trigger\nqueueProcessor\nwork-items] --> FA
    BLOB[Blob Trigger\nblobProcessor\nuploads/] --> FA
    HTTP[HTTP Triggers\nhelloHttp, health, info] --> FA

    FA --> ST[Storage Account]
    FA --> AI[Application Insights]

    style FA fill:#ff8c00,color:#fff
    style TIMER fill:#E3F2FD
    style QUEUE fill:#E8F5E9
    style BLOB fill:#FFF3E0

Steps

Step 1 — Add timer trigger

The reference app includes scheduledCleanup in src/functions/scheduled.js:

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

app.timer('scheduledCleanup', {
    schedule: '0 */5 * * * *',
    handler: async (_timer, context) => {
        context.log(`Scheduled cleanup ran at ${new Date().toISOString()}`);
    }
});

Step 2 — Add queue trigger

The reference app includes queueProcessor in src/functions/queueProcessor.js:

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

app.storageQueue('queueProcessor', {
    queueName: 'work-items',
    connection: 'QueueStorage',
    handler: async (queueItem, context) => {
        context.log(`Queue item received: ${JSON.stringify(queueItem)}`);
    }
});

Step 3 — Add blob trigger

The reference app includes blobProcessor in src/functions/blobProcessor.js:

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

const blobOutput = output.storageBlob({
    path: 'processed/{name}',
    connection: 'AzureWebJobsStorage',
});

app.storageBlob('blobProcessor', {
    path: 'uploads/{name}',
    connection: 'AzureWebJobsStorage',
    source: 'EventGrid',
    return: blobOutput,
    handler: async (blob, context) => {
        context.log(`Blob processed: ${context.triggerMetadata.name}, Size: ${blob.length} bytes`);
        return blob;
    }
});

Step 4 — Create storage resources

az storage queue create \
  --name "work-items" \
  --account-name "$STORAGE_NAME" \
  --auth-mode key

az storage container create \
  --name "uploads" \
  --account-name "$STORAGE_NAME" \
  --auth-mode key

az storage container create \
  --name "processed" \
  --account-name "$STORAGE_NAME" \
  --auth-mode key

Step 5 — Configure queue connection

Set the QueueStorage connection string for the queue trigger:

CONN_STR=$(az storage account show-connection-string \
  --name "$STORAGE_NAME" \
  --resource-group "$RG" \
  --query connectionString \
  --output tsv)

az functionapp config appsettings set \
  --name "$APP_NAME" \
  --resource-group "$RG" \
  --settings "QueueStorage=$CONN_STR"

Step 6 — Deploy and verify trigger indexing

func azure functionapp publish "$APP_NAME"

After publishing, verify all triggers are indexed:

az functionapp function list \
  --name "$APP_NAME" \
  --resource-group "$RG" \
  --query "[].{Name:name, Language:language}" \
  --output table

Expected output (key rows):

Name                                          Language
--------------------------------------------  ----------
func-ndprem-04100022/helloHttp                node
func-ndprem-04100022/health                   node
func-ndprem-04100022/scheduledCleanup         node
func-ndprem-04100022/queueProcessor           node
func-ndprem-04100022/blobProcessor            node
func-ndprem-04100022/timerLab                 node

Function indexing may require restart

If queueProcessor shows as disabled or fails to index, restart the function app after setting the QueueStorage connection:

az functionapp restart --name "$APP_NAME" --resource-group "$RG"

Step 7 — Test queue trigger

Send a test message to the queue:

az storage message put \
  --queue-name "work-items" \
  --content '{"task":"validate-premium","priority":"high"}' \
  --account-name "$STORAGE_NAME" \
  --auth-mode key

Expected output:

{
  "content": "{\"task\":\"validate-premium\",\"priority\":\"high\"}",
  "id": "32d6a0d5-d2c0-426a-8516-96f1d63f5337",
  "insertionTime": "2026-04-09T15:45:05+00:00"
}

Step 8 — Test blob trigger

Upload a test file to the uploads container:

echo "Premium blob trigger test" > /tmp/test-blob.txt
az storage blob upload \
  --container-name "uploads" \
  --file "/tmp/test-blob.txt" \
  --name "test-premium.txt" \
  --account-name "$STORAGE_NAME" \
  --auth-mode key \
  --overwrite

Step 9 — Verify trigger execution via Application Insights

Wait 2–3 minutes for telemetry ingestion, then query:

az monitor app-insights query \
  --app "$APP_NAME" \
  --resource-group "$RG" \
  --analytics-query "requests | where timestamp > ago(30m) | summarize count() by name | order by count_ desc" \
  --output json

Expected output (abridged):

{
  "tables": [
    {
      "rows": [
        ["health", 3],
        ["helloHttp", 2],
        ["queueProcessor", 2],
        ["scheduledCleanup", 1],
        ["logLevels", 1]
      ]
    }
  ]
}

You can also search for specific trigger executions:

az monitor app-insights query \
  --app "$APP_NAME" \
  --resource-group "$RG" \
  --analytics-query "traces | where timestamp > ago(30m) and message contains 'queueProcessor' | project timestamp, message | take 5" \
  --output json

Expected output:

{
  "tables": [
    {
      "rows": [
        ["2026-04-09T15:47:07Z", "Executed 'Functions.queueProcessor' (Succeeded, Id=..., Duration=31ms)"],
        ["2026-04-09T15:47:07Z", "Executing 'Functions.queueProcessor' (Reason='New queue message detected on 'work-items'.')"]
      ]
    }
  ]
}

Plan-specific notes

  • Premium plans support all trigger types with no timeout limits.
  • Queue and blob triggers on Premium benefit from always-warm instances — no cold-start delay for the first trigger after idle.
  • Blob triggers use EventGrid-based source by default in v4 — initial blob trigger processing may take up to 10 minutes for the first event.
  • Use connection: 'AzureWebJobsStorage' for blob triggers if the storage is the same account used for the function app.

Verification

Functions:
    helloHttp: [GET] http://localhost:7071/api/hello/{name?}
    scheduledCleanup: timerTrigger
    queueProcessor: queueTrigger
    blobProcessor: blobTrigger

Confirm:

  1. All triggers are indexed (visible in az functionapp function list or local func start).
  2. Queue message is processed — visible in App Insights requests table.
  3. Timer trigger fires every 5 minutes — visible in App Insights.
  4. Blob trigger fires when a file is uploaded to uploads/ container.

See Also

Sources