Note
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier les répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de changer de répertoire.
Azure Functions exécute votre code d’application à l’aide de gestionnaires spécifiques au langage. Ces gestionnaires spécifiques au langage permettent à Functions de prendre en charge la plupart des langages clés par défaut. Toutefois, vous devrez peut-être exécuter du code dans une autre langue ou package.
Les gestionnaires personnalisés sont des serveurs web légers qui reçoivent des événements du processus hôte Azure Functions. Vous pouvez utiliser des gestionnaires personnalisés pour déployer sur Azure Functions n’importe quel projet de code qui prend en charge les primitives HTTP.
Les gestionnaires personnalisés sont particulièrement adaptés dans les cas où vous voulez :
- Implémentez une application de fonction dans une langue qui n’est pas actuellement proposée prête à l’emploi, telle que Go ou Rust.
- implémenter une application de fonction dans un runtime qui ne figure pas par défaut comme Deno.
- Déployez un serveur créé avec les kits SDK MCP standard sur Azure Functions.
Avec les gestionnaires personnalisés, vous pouvez utiliser des déclencheurs et des liaisons d’entrée et de sortie via des bundles d’extension.
Démarrez avec les gestionnaires personnalisés Azure Functions avec les démarrages rapides en Go et Rust.
Vue d’ensemble
Le diagramme suivant illustre la relation entre l’hôte Functions et un serveur web implémenté en tant que gestionnaire personnalisé.
- Chaque événement déclenche une demande qui est envoyée à l’hôte Functions. Un événement est tout déclencheur pris en charge par Azure Functions.
- L’hôte Functions émet ensuite une charge utile de demande à destination du serveur web. La charge utile contient des données de déclencheur et de liaison d’entrée ainsi que d’autres métadonnées pour la fonction.
- Le serveur web exécute la fonction individuelle, puis retourne une charge utile de réponse à l’hôte Functions.
- L’hôte Functions transmet les données de la réponse aux liaisons de sortie de la fonction pour traitement.
Une application Azure Functions implémentée en tant que gestionnaire personnalisé doit configurer les fichiers host.json, local.settings.json et function.json en respectant quelques conventions.
Déployer des serveurs MCP auto-hébergés
Les gestionnaires personnalisés vous permettent également d’héberger des serveurs MCP que vous générez à l’aide de kits SDK MCP officiels dans Azure Functions. Les gestionnaires personnalisés offrent une expérience simple et simplifiée pour l’hébergement de vos serveurs MCP dans Azure. Pour plus d’informations, consultez serveur MCP distant auto-hébergé sur Azure Functions.
Remarque
La possibilité d'héberger des serveurs MCP avec Azure Functions que vous créez à l'aide des SDK MCP officiels est actuellement en préversion.
Structure d'application
Pour implémenter un gestionnaire personnalisé, votre application a besoin des aspects suivants :
- Un fichier host.json à la racine de l’application
- Un fichier local.settings.json à la racine de votre application
- Un fichier function.json pour chaque fonction (à l’intérieur d’un dossier dont le nom correspond à celui de la fonction)
- Commande, script ou exécutable qui exécute un serveur web
Le schéma suivant montre comment se présentent ces fichiers dans le système de fichiers pour une fonction nommée « MyQueueFunction » et un exécutable de gestionnaire personnalisé nommé handler. exe.
| /MyQueueFunction
| function.json
|
| host.json
| local.settings.json
| handler.exe
Configuration
Vous configurez l’application via les fichiershost.json et local.settings.json .
host.json
host.json dirige l’hôte Functions où envoyer des requêtes en pointant vers un serveur web capable de traiter les événements HTTP.
Définissez un gestionnaire personnalisé en configurant le fichier host.json avec des détails sur l’exécution du serveur web via la customHandler section.
{
"version": "2.0",
"customHandler": {
"description": {
"defaultExecutablePath": "handler.exe"
}
}
}
La section customHandler pointe vers une cible définie par defaultExecutablePath. La cible d’exécution peut être une commande, un exécutable ou un fichier dans lequel le serveur web est implémenté.
Utilisez le tableau arguments pour transmettre des arguments à l’exécutable. Les arguments prennent en charge l’expansion des variables d’environnement (paramètres d’application) à l’aide %% de la notation.
Vous pouvez aussi remplacer le répertoire de travail utilisé par le fichier exécutable avec workingDirectory.
{
"version": "2.0",
"customHandler": {
"description": {
"defaultExecutablePath": "app/handler.exe",
"arguments": [
"--database-connection-string",
"%DATABASE_CONNECTION_STRING%"
],
"workingDirectory": "app"
}
}
}
Prise en charge des liaisons
Vous pouvez rendre disponibles des déclencheurs standard, de même que des liaisons d’entrée et de sortie, en référençant des bundles d’extension dans le fichier host.json.
local.settings.json
local.settings.json définit les paramètres d’application utilisés pendant l’exécution locale de l’application de fonction. Comme il peut contenir des secrets, excluez local.settings.json du contrôle de code source. Dans Azure, utilisez plutôt les paramètres d’application.
Pour les gestionnaires personnalisés, définissez FUNCTIONS_WORKER_RUNTIME sur Custom dans local.settings.jso.
{
"IsEncrypted": false,
"Values": {
"FUNCTIONS_WORKER_RUNTIME": "Custom"
}
}
Métadonnées de fonction
Lorsque vous utilisez un gestionnaire personnalisé, le contenu function.json est le même que lorsque vous définissez une fonction dans n’importe quel autre contexte. La seule exigence est que vous devez placer function.json fichiers dans un dossier nommé pour correspondre au nom de la fonction.
Le fichier function.json suivant configure une fonction qui possède un déclencheur de file d’attente et une liaison de sortie de file d’attente. Comme il se trouve dans un dossier nommé MyQueueFunction, il définit une fonction nommée MyQueueFunction.
MyQueueFunction/function.json
{
"bindings": [
{
"name": "myQueueItem",
"type": "queueTrigger",
"direction": "in",
"queueName": "messages-incoming",
"connection": "AzureWebJobsStorage"
},
{
"name": "$return",
"type": "queue",
"direction": "out",
"queueName": "messages-outgoing",
"connection": "AzureWebJobsStorage"
}
]
}
Charge utile de demande
Lorsque l’hôte Functions reçoit un message de file d’attente, il envoie une requête HTTP POST au gestionnaire personnalisé avec une charge utile dans le contenu.
Le code suivant montre un exemple de charge utile de requête. La charge utile comprend une structure JSON à deux membres : Data et Metadata.
Le membre Data comprend des clés dont le nom correspond aux noms d’entrée et de déclencheur définis dans le tableau de liaisons du fichier function.json.
Le membre Metadata comprend les métadonnées générées à partir de la source d’événement.
{
"Data": {
"myQueueItem": "{ message: \"Message sent\" }"
},
"Metadata": {
"DequeueCount": 1,
"ExpirationTime": "2019-10-16T17:58:31+00:00",
"Id": "800ae4b3-bdd2-4c08-badd-f08e5a34b865",
"InsertionTime": "2019-10-09T17:58:31+00:00",
"NextVisibleTime": "2019-10-09T18:08:32+00:00",
"PopReceipt": "AgAAAAMAAAAAAAAAAgtnj8x+1QE=",
"sys": {
"MethodName": "QueueTrigger",
"UtcNow": "2019-10-09T17:58:32.2205399Z",
"RandGuid": "24ad4c06-24ad-4e5b-8294-3da9714877e9"
}
}
}
Charge utile de réponse
Par convention, les réponses de fonction se présentent sous la forme de paires clé/valeur. Les clés prises en charge sont les suivantes :
|
|
Type de données | Notes |
|---|---|---|
Outputs |
object | Contient les valeurs de réponse définies par le tableau bindings dans le fichier function.json.Par exemple, si une fonction est configurée avec une liaison de sortie de file d’attente nommée « myQueueOutput », alors Outputs contient une clé nommée myQueueOutput, que le gestionnaire personnalisé utilise pour les messages qu'il envoie à la file d’attente. |
Logs |
tableau | Messages qui apparaissent dans les journaux d’appel Functions. Quand l’exécution se produit dans Azure, les messages s’affichent dans Application Insights. |
ReturnValue |
string | Utilisé pour fournir une réponse quand une sortie est configurée avec la valeur $return dans le fichier function.json. |
Ce tableau montre un exemple de charge utile de réponse.
{
"Outputs": {
"res": {
"body": "Message enqueued"
},
"myQueueOutput": [
"queue message 1",
"queue message 2"
]
},
"Logs": [
"Log message 1",
"Log message 2"
],
"ReturnValue": "{\"hello\":\"world\"}"
}
Exemples
Vous pouvez implémenter des gestionnaires personnalisés dans n’importe quel langage qui prend en charge la réception d’événements HTTP. Les exemples suivants montrent comment implémenter un gestionnaire personnalisé à l’aide du langage de programmation Go.
Fonction avec liaisons
Cet exemple montre une fonction nommée order qui accepte une POST demande avec une charge utile représentant une commande de produit. Lorsque vous publiez une commande dans la fonction, elle crée un message de stockage file d’attente et retourne une réponse HTTP.
Implémentation
Dans un dossier nommé order, le fichier function.json configure la fonction déclenchée par HTTP.
order/function.json
{
"bindings": [
{
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": ["post"]
},
{
"type": "http",
"direction": "out",
"name": "res"
},
{
"type": "queue",
"name": "message",
"direction": "out",
"queueName": "orders",
"connection": "AzureWebJobsStorage"
}
]
}
Cette fonction est définie comme étant une fonction déclenchée par HTTP qui retourne une réponse HTTP et génère un message de Stockage File d’attente.
À la racine de l’application, le fichier host.json est configuré pour exécuter un fichier exécutable nommé handler.exe (handler dans Linux ou macOS).
{
"version": "2.0",
"customHandler": {
"description": {
"defaultExecutablePath": "handler.exe"
}
},
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[4.*, 5.0.0)"
}
}
Il s’agit de la requête HTTP envoyée au runtime Functions.
POST http://127.0.0.1:7071/api/order HTTP/1.1
Content-Type: application/json
{
"id": 1005,
"quantity": 2,
"color": "black"
}
Le runtime Functions envoie la requête HTTP suivante au gestionnaire personnalisé :
POST http://127.0.0.1:<FUNCTIONS_CUSTOMHANDLER_PORT>/order HTTP/1.1
Content-Type: application/json
{
"Data": {
"req": {
"Url": "http://localhost:7071/api/order",
"Method": "POST",
"Query": "{}",
"Headers": {
"Content-Type": [
"application/json"
]
},
"Params": {},
"Body": "{\"id\":1005,\"quantity\":2,\"color\":\"black\"}"
}
},
"Metadata": {
}
}
Remarque
Certaines parties de la charge utile ont été supprimées par souci de concision.
handler. exe est le programme de gestionnaire personnalisé Go compilé qui exécute un serveur web et répond aux demandes d’appel de fonction de l’hôte Functions.
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
"os"
)
type InvokeRequest struct {
Data map[string]json.RawMessage
Metadata map[string]interface{}
}
type InvokeResponse struct {
Outputs map[string]interface{}
Logs []string
ReturnValue interface{}
}
func orderHandler(w http.ResponseWriter, r *http.Request) {
var invokeRequest InvokeRequest
d := json.NewDecoder(r.Body)
d.Decode(&invokeRequest)
var reqData map[string]interface{}
json.Unmarshal(invokeRequest.Data["req"], &reqData)
outputs := make(map[string]interface{})
outputs["message"] = reqData["Body"]
resData := make(map[string]interface{})
resData["body"] = "Order enqueued"
outputs["res"] = resData
invokeResponse := InvokeResponse{outputs, nil, nil}
responseJson, _ := json.Marshal(invokeResponse)
w.Header().Set("Content-Type", "application/json")
w.Write(responseJson)
}
func main() {
customHandlerPort, exists := os.LookupEnv("FUNCTIONS_CUSTOMHANDLER_PORT")
if !exists {
customHandlerPort = "8080"
}
mux := http.NewServeMux()
mux.HandleFunc("/order", orderHandler)
fmt.Println("Go server Listening on: ", customHandlerPort)
log.Fatal(http.ListenAndServe(":"+customHandlerPort, mux))
}
Dans cet exemple, le gestionnaire personnalisé exécute un serveur web pour gérer les événements HTTP et écouter les requêtes via le FUNCTIONS_CUSTOMHANDLER_PORT.
Même si l’hôte Functions reçoit la requête HTTP d’origine à l’adresse /api/order, il appelle le gestionnaire personnalisé à l’aide du nom de la fonction (son nom de dossier). Dans cet exemple, la fonction est définie sur le chemin /order. L’hôte envoie au gestionnaire personnalisé une requête HTTP sur le chemin /order.
Lorsque vous envoyez des POST requêtes à cette fonction, les données de déclencheur et les métadonnées de fonction sont disponibles via le corps de la requête HTTP. Vous pouvez accéder au corps de la requête HTTP d’origine dans le Data.req.Body de la charge utile.
La réponse de la fonction se présente sous la forme de paires clé/valeur où le membre Outputs contient une valeur JSON et où les clés correspondent aux sorties définies dans le fichier function.json.
Voici un exemple de charge utile que ce gestionnaire retourne à l’hôte Functions.
{
"Outputs": {
"message": "{\"id\":1005,\"quantity\":2,\"color\":\"black\"}",
"res": {
"body": "Order enqueued"
}
},
"Logs": null,
"ReturnValue": null
}
En définissant la sortie message comme étant égale aux données de commande résultant de la demande, la fonction sort ces données de commande vers la file d’attente configurée. L’hôte Functions retourne aussi la réponse HTTP configurée dans res pour l’appelant.
Fonction HTTP uniquement
Pour les fonctions déclenchées par HTTP sans liaisons ou sorties supplémentaires, vous souhaiterez peut-être que votre gestionnaire fonctionne directement avec la requête ET la réponse HTTP au lieu des charges utiles de requête et de réponse du gestionnaire personnalisé. Vous pouvez configurer ce comportement dans host.json à l’aide du paramètre de configuration, qui prend en charge le enableProxyingHttpRequest streaming des réponses.
Important
L’objectif principal de la fonctionnalité de gestionnaires personnalisés est d’activer les langages et les runtimes qui n’ont actuellement pas de prise en charge de première classe sur Azure Functions. Bien que vous puissiez exécuter des applications web à l’aide de gestionnaires personnalisés, Azure Functions n’est pas un proxy inverse standard. Certains composants de la requête HTTP, tels que certains en-têtes et itinéraires, peuvent être limités. Votre application peut également rencontrer un démarrage à froid excessif.
Pour faire face à ces situations, envisagez d’exécuter vos applications web dans Azure App Service.
L’exemple suivant montre comment configurer une fonction déclenchée par HTTP sans aucune autre liaison ni sortie. Le scénario implémenté dans cet exemple présente une fonction nommée hello qui accepte un GET ou un POST.
Implémentation
Dans un dossier nommé hello, le fichier function.json configure la fonction déclenchée par HTTP.
hello/function.json
{
"bindings": [
{
"type": "httpTrigger",
"authLevel": "anonymous",
"direction": "in",
"name": "req",
"methods": ["get", "post"]
},
{
"type": "http",
"direction": "out",
"name": "res"
}
]
}
La fonction est configurée pour accepter les demandes GET et POST, et la valeur de résultat est fournie dans un argument nommé res.
À la racine de l’application, le fichier host.json est configuré pour exécuter handler.exe et enableProxyingHttpRequest est défini sur true.
{
"version": "2.0",
"customHandler": {
"description": {
"defaultExecutablePath": "handler.exe"
},
"enableProxyingHttpRequest": true
}
}
Voici une requête POST adressée à l’hôte Functions. L’hôte Functions envoie ensuite la requête au gestionnaire personnalisé.
POST http://127.0.0.1:7071/api/hello HTTP/1.1
Content-Type: application/json
{
"message": "Hello World!"
}
Le fichier handler.go implémente un serveur web et une fonction HTTP.
package main
import (
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
)
func helloHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
if r.Method == "GET" {
w.Write([]byte("hello world"))
} else {
body, _ := ioutil.ReadAll(r.Body)
w.Write(body)
}
}
func main() {
customHandlerPort, exists := os.LookupEnv("FUNCTIONS_CUSTOMHANDLER_PORT")
if !exists {
customHandlerPort = "8080"
}
mux := http.NewServeMux()
mux.HandleFunc("/api/hello", helloHandler)
fmt.Println("Go server Listening on: ", customHandlerPort)
log.Fatal(http.ListenAndServe(":"+customHandlerPort, mux))
}
Dans cet exemple, le gestionnaire personnalisé crée un serveur web pour gérer les événements HTTP et écoute les requêtes via le FUNCTIONS_CUSTOMHANDLER_PORT.
Les demandes GET sont gérées en retournant une chaîne, et les demandes POST ont accès au corps de la demande.
La route pour la fonction order est ici /api/hello, comme pour la demande d’origine.
Remarque
Le FUNCTIONS_CUSTOMHANDLER_PORT n’est pas le port public utilisé pour appeler la fonction. L’hôte Functions utilise ce port pour appeler le gestionnaire personnalisé.
Déploiement en cours
Vous pouvez déployer un gestionnaire personnalisé sur chaque option d’hébergement Azure Functions. Si votre gestionnaire nécessite des dépendances de système d’exploitation ou de plateforme (par exemple, un runtime de langage), vous devrez peut-être utiliser un conteneur personnalisé.
Lorsque vous créez une application de fonction dans Azure pour les gestionnaires personnalisés, sélectionnez .NET Core comme pile.
Pour déployer une application de gestionnaire personnalisée à l’aide d’Azure Functions Core Tools, exécutez la commande suivante.
func azure functionapp publish $functionAppName
Remarque
Vérifiez que tous les fichiers nécessaires à l’exécution de votre gestionnaire personnalisé se trouvent dans le dossier et sont inclus dans le déploiement. Si votre gestionnaire personnalisé est un exécutable binaire ou possède des dépendances spécifiques de plateforme, vérifiez que ces fichiers correspondent à la plateforme de déploiement cible.
Restrictions
- Le serveur web du gestionnaire personnalisé doit démarrer dans un délai de 60 secondes.
Exemples
Pour obtenir des exemples d’implémentation de fonctions dans différents langages, consultez le référentiel GitHub d’exemples de gestionnaires personnalisés.
Résolution des problèmes et support
Journalisation du suivi
Si votre processus de gestionnaire personnalisé ne parvient pas à démarrer ou s’il rencontre des problèmes de communication avec l’hôte des fonctions, augmentez le niveau de journalisation de l’application de fonction à Trace pour afficher davantage de messages de diagnostic à partir de l’hôte.
Pour changer le niveau de journalisation par défaut de l’application de fonction, configurez le paramètre logLevel dans la section logging de host.json.
{
"version": "2.0",
"customHandler": {
"description": {
"defaultExecutablePath": "handler.exe"
}
},
"logging": {
"logLevel": {
"default": "Trace"
}
}
}
L’hôte Functions génère des messages de journal supplémentaires, y compris les informations relatives au processus de gestionnaire personnalisé. Utilisez les journaux pour étudier les problèmes de démarrage du processus de votre gestionnaire personnalisé ou les problèmes d’appel de fonctions dans votre gestionnaire personnalisé.
Localement, les journaux sont imprimés dans la console.
Dans Azure, interrogez les traces Application Insights pour afficher les messages du journal. Si votre application produit un grand nombre de journaux, seul un sous-ensemble des messages de journal est envoyé à Application Insights. Désactivez l’échantillonnage pour faire en sorte que tous les messages soient journalisés.
Tester le gestionnaire personnalisé en isolation
Les applications de gestionnaire personnalisées sont des processus de serveur web, il peut donc être utile de les démarrer par elles-mêmes et d'en tester le fonctionnement en envoyant des requêtes HTTP fictives. Pour envoyer des requêtes HTTP avec des charges utiles, assurez-vous de choisir un outil qui sécurise vos données. Pour découvrir plus d’informations, consultez Outils de test HTTP.
Vous pouvez aussi utiliser cette stratégie dans vos pipelines CI/CD pour exécuter des tests automatisés sur votre gestionnaire personnalisé.
Environnement d’exécution
Les gestionnaires personnalisés s’exécutent dans le même environnement qu’une application Azure Functions classique. Testez votre gestionnaire pour vérifier que l’environnement contient toutes les dépendances dont il a besoin pour s’exécuter. Pour les applications qui nécessitent des dépendances supplémentaires, vous devrez peut-être les exécuter à l’aide d’une image conteneur personnalisée hébergée sur un plan Azure Functions Premium.
Obtenir de l’aide
Si vous avez besoin d’aide sur une application de fonction assortie de gestionnaires personnalisés, vous pouvez envoyer une demande via les canaux de support standard. Toutefois, en raison de la grande variété de langages possibles utilisés pour créer des applications de gestionnaires personnalisés, la prise en charge n’est pas illimitée.
Un support est fourni si l’hôte Functions rencontre des problèmes de démarrage ou de communication avec le processus du gestionnaire personnalisé. Pour les problèmes spécifiques au fonctionnement interne de votre processus de gestionnaire personnalisé, tels que les problèmes liés au langage ou à l’infrastructure choisi, notre équipe de support technique ne peut pas fournir d’assistance dans ce contexte.
Étapes suivantes
Commencez à créer une application Azure Functions en Go ou Rust à l’aide du démarrage rapide des gestionnaires personnalisés.