Trigger e binding: due concetti distinti
In Azure Functions ogni funzione nasce da un trigger e da esso soltanto: è l’evento che ne provoca l’esecuzione e ne definisce il payload iniziale. La regola cardine è che una funzione ha esattamente un trigger — non zero, non due. Attorno al trigger puoi invece dichiarare quanti binding di input e output vuoi: sono connessioni verso servizi esterni (Storage, Service Bus, Cosmos DB, SendGrid…) che il runtime risolve automaticamente, iniettando i dati in ingresso e scrivendo quelli in uscita al termine.
La configurazione avviene in due modi equivalenti a seconda del linguaggio:
- Attributi in-process/isolated (C#, Java) — es.
[QueueTrigger],[BlobOutput]applicati ai parametri del metodo. function.json(scripting: JavaScript, Python model v1, PowerShell) — un arraybindingsdove ogni voce hatype,direction(in/out) ename. Nel modello Python v2 e nel worker isolato .NET si usano invece i decoratori/attributi.
Il vantaggio dei binding dichiarativi è togliere codice di plumbing: niente creazione manuale di QueueClient o gestione della connessione. Lo svantaggio è la minor granularità — se ti serve controllo fine (paginazione, transazioni, retry personalizzati, operazioni condizionali) chiami direttamente l’SDK dentro la funzione. Regola pratica da ASSOCIATE: binding per I/O semplice e dichiarativo, SDK quando la logica di accesso al dato è essa stessa parte del problema.
Panoramica dei trigger chiave
- HTTP trigger — invocazione via richiesta HTTP, con
authLevel(anonymous/function/admin). Base per API e webhook. - Timer trigger — esecuzione schedulata tramite espressione NCRONTAB a 6 campi
{secondo} {minuto} {ora} {giorno} {mese} {giorno-settimana}. Attenzione: parte dai secondi, a differenza del cron Linux.0 */5 * * * *= ogni 5 minuti;0 30 9 * * 1-5= 9:30 nei giorni feriali. - Queue Storage trigger — reagisce ai messaggi di una coda; il runtime gestisce il polling, il lease e lo spostamento in poison queue dopo
maxDequeueCounttentativi falliti. - Blob Storage trigger — si attiva su nuovi blob. Sul piano Consumption usa un meccanismo di polling/scan del log, non è in tempo reale né garantito per volumi elevati (vedi trappola sotto).
- Service Bus trigger — code e topic/subscription, con semantica transazionale, sessioni e dead-letter: la scelta enterprise quando servono ordinamento, FIFO o at-least-once affidabile.
- Event Grid trigger — consumo push di eventi discreti (creazione blob, eventi di risorse Azure, eventi custom): bassa latenza, retry con backoff, ideale per architetture event-driven reattive.
- Event Hubs trigger — ingestione ad alto throughput di stream telemetrici/log, processati in batch con checkpoint tramite storage.
Binding di input e output
Un pattern tipico: HTTP trigger + Cosmos DB input binding (leggi un documento by-id) + Queue output binding (accoda un lavoro). Tre servizi orchestrati senza istanziare un solo client. Un output binding può anche restituire collezioni (ICollector<T> / IAsyncCollector<T>) per emettere più messaggi in una singola esecuzione.
Blob trigger vs Event Grid: la scelta architetturale
Il punto più insidioso riguarda il blob trigger. Sul piano Consumption il rilevamento si basa sulla scansione periodica dei log dello storage: la latenza può arrivare a diversi minuti e, oltre le 10.000 blob, alcuni eventi possono sfuggire. Se lo scenario richiede reattività quasi immediata e affidabilità, la risposta corretta è usare Event Grid come sorgente: si sottoscrive l’evento Microsoft.Storage.BlobCreated e si usa il tipo di trigger Blob con source: EventGrid (o direttamente un Event Grid trigger). Event Grid fa push con retry integrati, eliminando il polling.
Trappole tipiche d’esame
- Serve elaborare i blob appena caricati, in tempo reale e affidabile, su piano Consumption → non affidarti al blob trigger basato su polling: sottoscrivi l’evento
BlobCreatedvia Event Grid (blob trigger consource: EventGrid). - Devi eseguire una funzione ogni notte alle 2:00 → Timer trigger con NCRONTAB
0 0 2 * * *; ricorda i 6 campi con i secondi in testa, non i 5 del cron classico. - Vuoi che una funzione legga da una coda e scriva su Cosmos DB senza SDK → un solo queue trigger più un output binding Cosmos DB; non aggiungere un secondo trigger.
- Messaggi che richiedono FIFO, sessioni o dead-letter garantito → Service Bus, non Queue Storage.
- Un messaggio di coda fallisce ripetutamente → dopo
maxDequeueCountfinisce nella poison queue; non resta in loop infinito.