Concatenamento di funzioni in Funzioni permanenti - Esempio di sequenza di Hello
Articolo
Il concatenamento delle funzioni si riferisce al modello di esecuzione di una sequenza di funzioni in un ordine specifico. Spesso l'output di una funzione deve essere applicato all'input di un'altra funzione. Questo articolo descrive la sequenza di concatenamento creata al termine della guida introduttiva di Durable Functions (C#, JavaScript, TypeScript, Python, PowerShell o Java). Per altre informazioni su Durable Functions, vedere Panoramica di Durable Functions.
La versione 4 del modello di programmazione Node.js per Funzioni di Azure è disponibile a livello generale. Il nuovo modello v4 è progettato per offrire un'esperienza più flessibile e intuitiva agli sviluppatori JavaScript e TypeScript. Altre informazioni sulle differenze tra v3 e v4 sono disponibili nella guida alla migrazione.
Nei frammenti di codice seguenti JavaScript (PM4) indica il modello di programmazione V4, la nuova esperienza.
Funzioni
Questo articolo descrive le funzioni seguenti nell'app di esempio:
E1_HelloSequence: funzione dell’agente di orchestrazione che chiama E1_SayHello più volte in sequenza. Archivia gli output delle chiamate E1_SayHello e registra i risultati.
Tutte le funzioni di orchestrazione C# devono avere un parametro di tipo DurableOrchestrationContext disponibile nell'assembly Microsoft.Azure.WebJobs.Extensions.DurableTask. Questo contesto di ambiente consente di chiamare altre funzioni dell’attività e di passare i parametri di input usando il metodo CallActivityAsync.
Il codice chiama E1_SayHello tre volte in sequenza con valori dei parametri diversi. Il valore restituito di ogni chiamata viene aggiunto all'elenco outputs, che viene restituito al termine della funzione.
function.json
Se si usa Visual Studio Code o il portale di Azure per lo sviluppo, questo è il contenuto del file function.json per la funzione di orchestrazione. La maggior parte dei file function.json dell'agente di orchestrazione sono quasi identici a questo.
Fondamentale è il tipo di associazione orchestrationTrigger. Tutte le funzioni di orchestrazione devono usare questo tipo di trigger.
Avviso
Per rispettare la regola "no I/O" delle funzioni di orchestrazione, non usare associazioni di input o output quando si usa l'associazione di trigger orchestrationTrigger. Quando sono necessarie altre associazioni di input o output, occorre invece usarle nel contesto delle funzioni activityTrigger già chiamate dall'agente di orchestrazione. Per altre informazioni, vedere l'articolo Vincoli di codice delle funzioni dell'agente di orchestrazione.
index.js
La funzione dell'agente di orchestrazione è la seguente:
Tutte le funzioni di orchestrazione JavaScript devono includere il modulo durable-functions. Si tratta di una libreria che consente di usare Durable Functions con JavaScript. Esistono tre differenze significative tra una funzione dell’agente di orchestrazione e altre funzioni JavaScript:
Per la funzione viene eseguito il wrapping in una chiamata al metodo durable-functions del modulo orchestrator (qui df).
La funzione deve essere sincrona. Poiché il metodo 'orchestrator' gestisce la chiamata finale a 'context.done', la funzione deve semplicemente ‘restituire’.
L'oggetto context contiene un contesto di ambiente di orchestrazione durevole df che consente di chiamare altre funzioni dell’attività e di passare parametri di input con il metodo callActivity. Il codice chiama E1_SayHello tre volte in sequenza con valori di parametro diversi, usando yield per indicare che l'esecuzione deve attendere la restituzione delle chiamate di funzioni di attività asincrone. Il valore restituito di ogni chiamata viene aggiunto all'array outputs, che viene restituito al termine della funzione.
Tutte le funzioni di orchestrazione JavaScript devono includere il modulo durable-functions. Questo modulo consente di scrivere funzioni Durable Functions in JavaScript. Per usare il modello di programmazione dei nodi V4, è necessario installare la versione di anteprima v3.x di durable-functions.
Esistono due differenze significative tra una funzione di orchestrazione e altre funzioni JavaScript:
La funzione deve essere sincrona. La funzione deve semplicemente "restituire".
L'oggetto context contiene un contesto di ambiente di orchestrazione durevole df che consente di chiamare altre funzioni dell’attività e di passare parametri di input con il metodo callActivity. Il codice chiama sayHello tre volte in sequenza con valori di parametro diversi, usando yield per indicare che l'esecuzione deve attendere la restituzione delle chiamate di funzioni di attività asincrone. Il valore restituito di ogni chiamata viene aggiunto all'array outputs, che viene restituito al termine della funzione.
Nota
Le funzioni Durable Functions in Python sono disponibili solo per il runtime 3.0.x di Funzioni.
function.json
Se si usa Visual Studio Code o il portale di Azure per lo sviluppo, questo è il contenuto del file function.json per la funzione di orchestrazione. La maggior parte dei file function.json dell'agente di orchestrazione sono quasi identici a questo.
Fondamentale è il tipo di associazione orchestrationTrigger. Tutte le funzioni di orchestrazione devono usare questo tipo di trigger.
Avviso
Per rispettare la regola "no I/O" delle funzioni di orchestrazione, non usare associazioni di input o output quando si usa l'associazione di trigger orchestrationTrigger. Quando sono necessarie altre associazioni di input o output, occorre invece usarle nel contesto delle funzioni activityTrigger già chiamate dall'agente di orchestrazione. Per altre informazioni, vedere l'articolo Vincoli di codice delle funzioni dell'agente di orchestrazione.
__init__.py
La funzione dell'agente di orchestrazione è la seguente:
Tutte le funzioni di orchestrazione di Python devono includere il pacchettodurable-functions. Si tratta di una libreria che consente di scrivere funzioni Durable Functions in Python. Esistono due differenze significative tra una funzione dell'agente di orchestrazione e altre funzioni Python:
Il file deve registrare la funzione dell'agente di orchestrazione come agente di orchestrazione indicando main = df.Orchestrator.create(<orchestrator function name>) alla fine del file. Ciò consente di distinguerlo da altre funzioni, helper, dichiarate nel file.
L'oggetto context consente di chiamare altre funzioni dell’attività e di passare parametri di input tramite il metodo call_activity. Il codice chiama E1_SayHello tre volte in sequenza con valori di parametro diversi, usando yield per indicare che l'esecuzione deve attendere la restituzione delle chiamate di funzioni di attività asincrone. Il valore restituito di ogni chiamata viene restituito alla fine della funzione.
[FunctionName("E1_SayHello")]
public static string SayHello([ActivityTrigger] IDurableActivityContext context)
{
string name = context.GetInput<string>();
return $"Hello {name}!";
}
Le attività usano l'attributo ActivityTrigger. Usare l'oggetto fornito IDurableActivityContext per eseguire azioni correlate alle attività, ad esempio l'accesso al valore di input tramite GetInput<T>.
L'implementazione di E1_SayHello è un'operazione di formattazione delle stringhe relativamente semplice.
Anziché eseguire l'associazione a un oggetto IDurableActivityContext, è possibile eseguire l’associazione direttamente al tipo passato alla funzione dell'attività. Ad esempio:
Il file function.json per la funzione di attività E1_SayHello è simile a quello di E1_HelloSequence ad eccezione del fatto che usa un tipo di associazione activityTrigger anziché un tipo di associazione orchestrationTrigger.
Tutte le funzioni dell’attività chiamate da una funzione di orchestrazione devono usare l'associazione activityTrigger.
L'implementazione di E1_SayHello è un'operazione di formattazione delle stringhe relativamente semplice.
E1_SayHello/index.js
module.exports = function (context) {
context.done(null, `Hello ${context.bindings.name}!`);
};
A differenza di una funzione di orchestrazione, una funzione dell’attività non necessita di alcuna configurazione speciale. L'input passato al metodo tramite la funzione dell'agente di orchestrazione è presente nell'oggetto context.bindings sotto il nome del binding activityTrigger, in questo caso context.bindings.name. Il nome del binding può essere impostato come parametro della funzione esportata e vi si può accedere direttamente, come nel codice di esempio.
L'implementazione di sayHello è un'operazione di formattazione delle stringhe relativamente semplice.
A differenza di una funzione di orchestrazione, una funzione dell’attività non necessita di alcuna configurazione speciale. L'input passato dalla funzione dell'agente di orchestrazione è il primo argomento della funzione. Il secondo argomento è il contesto di chiamata, che non viene usato in questo esempio.
E1_SayHello/function.json
Il file function.json per la funzione di attività E1_SayHello è simile a quello di E1_HelloSequence ad eccezione del fatto che usa un tipo di associazione activityTrigger anziché un tipo di associazione orchestrationTrigger.
A differenza della funzione dell'agente di orchestrazione, una funzione dell’attività non richiede alcuna configurazione speciale. L'input passato dalla funzione dell'agente di orchestrazione è accessibile direttamente come parametro alla funzione.
Funzione client HttpStart
È possibile avviare un'istanza della funzione dell'agente di orchestrazione usando una funzione client. In questo caso verà usata la funzione HttpStart attivata da HTTP per avviare le istanze di E1_HelloSequence.
public static class HttpStart
{
[FunctionName("HttpStart")]
public static async Task<HttpResponseMessage> Run(
[HttpTrigger(AuthorizationLevel.Function, methods: "post", Route = "orchestrators/{functionName}")] HttpRequestMessage req,
[DurableClient] IDurableClient starter,
string functionName,
ILogger log)
{
// Function input comes from the request content.
object eventData = await req.Content.ReadAsAsync<object>();
string instanceId = await starter.StartNewAsync(functionName, eventData);
log.LogInformation($"Started orchestration with ID = '{instanceId}'.");
return starter.CreateCheckStatusResponse(req, instanceId);
}
}
Per interagire con gli agenti di orchestrazione, la funzione deve includere un'associazione DurableClient di input. Usare il client per avviare un'orchestrazione. Può anche essere utile per restituire una risposta HTTP contenente URL per controllare lo stato della nuova orchestrazione.
Usare df.getClient per ottenere un oggetto DurableOrchestrationClient. Usare il client per avviare un'orchestrazione. Può anche essere utile per restituire una risposta HTTP contenente URL per controllare lo stato della nuova orchestrazione.
Per gestire e interagire con gli agenti di orchestrazione, la funzione richiede un'associazione di input durableClient. Questa associazione deve essere specificata nell'argomento extraInputs al momento della registrazione della funzione. È possibile ottenere un input durableClient chiamando df.input.durableClient().
Usare df.getClient per ottenere un oggetto DurableClient. Usare il client per avviare un'orchestrazione. Può anche essere utile per restituire una risposta HTTP contenente URL per controllare lo stato della nuova orchestrazione.
Per interagire con gli agenti di orchestrazione, la funzione deve includere un'associazione durableClient di input.
HttpStart/__init__.py
import logging
import azure.functions as func
import azure.durable_functions as df
async def main(req: func.HttpRequest, starter: str) -> func.HttpResponse:
client = df.DurableOrchestrationClient(starter)
instance_id = await client.start_new(req.route_params["functionName"], None, None)
logging.info(f"Started orchestration with ID = '{instance_id}'.")
return client.create_check_status_response(req, instance_id)
Usare il costruttore DurableOrchestrationClient per ottenere un client Durable Functions. Usare il client per avviare un'orchestrazione. Può anche essere utile per restituire una risposta HTTP contenente URL per controllare lo stato della nuova orchestrazione.
Eseguire l'esempio
Per eseguire l'orchestrazione E1_HelloSequence, inviare la richiesta POST HTTP seguente alla funzione HttpStart.
POST http://{host}/orchestrators/E1_HelloSequence
Nota
Il frammento di codice HTTP precedente presuppone che sia presente una voce nel file host.json che consente di rimuovere il prefisso predefinito api/ da tutti gli URL di funzioni di trigger HTTP. È possibile trovare il markup per la configurazione nel file host.json negli esempi.
Ad esempio, se si esegue l'esempio in un'app per le funzioni denominata "myfunctionapp", sostituire "{host}" con "myfunctionapp.azurewebsites.net".
Il risultato è una risposta HTTP 202, simile alla seguente (tagliata per brevità):
A questo punto, l'orchestrazione viene messa in coda e inizia ad avviarsi immediatamente. L'URL nell'intestazione Location può essere usato per controllare lo stato dell'esecuzione.
GET http://{host}/runtime/webhooks/durabletask/instances/96924899c16d43b08a536de376ac786b?taskHub=DurableFunctionsHub&connection=Storage&code={systemKey}
Il risultato è lo stato dell'orchestrazione. Si esegue e completa rapidamente e appare nello stato Completato con una risposta simile alla seguente (tagliata per brevità):
Come si può notare, il runtimeStatus dell'istanza è Completato e output contiene il risultato JSON serializzato dell'esecuzione della funzione di orchestrazione.
Nota
È possibile implementare una logica di avvio simile per altri tipi di trigger, ad esempio queueTrigger, eventHubTrigger, o timerTrigger.
Esaminare i log di esecuzione della funzione. La funzione E1_HelloSequence si è avviata ed è stata completata più volte a causa del comportamento di riproduzione descritto nell’argomento Affidabilità dell’orchestrazione. In compenso, si sono verificate solo tre esecuzioni di E1_SayHello da quando tali esecuzioni delle funzioni non vengono riprodotte.
Passaggi successivi
In questo esempio è stata illustrata una semplice orchestrazione di concatenamento delle funzioni. Nell'esempio successivo viene illustrato come implementare il criterio di fan-out/fan-in.