Vlastní obslužné rutiny Azure Functions
Každá aplikace Functions se spouští obslužnou rutinou specifickou pro jazyk. Azure Functions sice ve výchozím nastavení nabízí mnoho obslužných rutin jazyka, ale existují případy, kdy můžete chtít použít jiné jazyky nebo moduly runtime.
Vlastní obslužné rutiny jsou odlehčené webové servery, které přijímají události z hostitele služby Functions. Jakýkoli jazyk, který podporuje primitivy HTTP, může implementovat vlastní obslužnou rutinu.
Vlastní obslužné rutiny jsou nejvhodnější pro situace, kdy chcete:
- Implementujte aplikaci funkcí v jazyce, který momentálně není k dispozici, například Go nebo Rust.
- Implementujte aplikaci funkcí v modulu runtime, který aktuálně není ve výchozím nastavení doporučený, například Deno.
Pomocí vlastních obslužných rutin můžete pomocí sad rozšíření použít triggery a vstupní a výstupní vazby.
Začínáme s vlastními obslužnými rutinami Azure Functions pomocí rychlých startů v Go a Rustu
Přehled
Následující diagram znázorňuje vztah mezi hostitelem služby Functions a webovým serverem implementovaným jako vlastní obslužná rutina.
- Každá událost aktivuje požadavek odeslaný hostiteli Functions. Událost je jakákoli aktivační událost podporovaná službou Azure Functions.
- Hostitel služby Functions pak vydá datovou část požadavku na webový server. Datová část obsahuje data triggeru a vstupní vazby a další metadata funkce.
- Webový server spustí jednotlivé funkce a vrátí datovou část odpovědi hostiteli Functions.
- Hostitel Functions předává data z odpovědi na výstupní vazby funkce ke zpracování.
Aplikace Azure Functions implementovaná jako vlastní obslužná rutina musí nakonfigurovat host.json, local.settings.json a function.json soubory podle několika konvencí.
Struktura aplikace
K implementaci vlastní obslužné rutiny potřebujete pro aplikaci následující aspekty:
- Soubor host.json v kořenovém adresáři aplikace
- Soubor local.settings.json v kořenovém adresáři aplikace
- Soubor function.json pro každou funkci (uvnitř složky, která odpovídá názvu funkce)
- Příkaz, skript nebo spustitelný soubor, který spouští webový server
Následující diagram ukazuje, jak tyto soubory vypadají v systému souborů pro funkci s názvem "MyQueueFunction" a vlastní spustitelný soubor obslužné rutiny s názvem handler.exe.
| /MyQueueFunction
| function.json
|
| host.json
| local.settings.json
| handler.exe
Konfigurace
Aplikace se konfiguruje prostřednictvím host.json a local.settings.json souborů.
host.json
host.json hostiteli Functions řekne, kde odesílat požadavky odkazováním na webový server, který dokáže zpracovat události HTTP.
Vlastní obslužná rutina je definována konfigurací souboru host.json s podrobnostmi o tom, jak webový server spustit prostřednictvím oddílu customHandler
.
{
"version": "2.0",
"customHandler": {
"description": {
"defaultExecutablePath": "handler.exe"
}
}
}
Oddíl customHandler
odkazuje na cíl definovaný objektem defaultExecutablePath
. Cílem spuštění může být příkaz, spustitelný soubor nebo soubor, ve kterém je webový server implementovaný.
arguments
Pomocí pole předejte spustitelnému souboru všechny argumenty. Argumenty podporují rozšíření proměnných prostředí (nastavení aplikace) pomocí %%
zápisu.
Můžete také změnit pracovní adresář používaný spustitelným souborem s workingDirectory
.
{
"version": "2.0",
"customHandler": {
"description": {
"defaultExecutablePath": "app/handler.exe",
"arguments": [
"--database-connection-string",
"%DATABASE_CONNECTION_STRING%"
],
"workingDirectory": "app"
}
}
}
Podpora vazeb
Standardní triggery spolu se vstupními a výstupními vazbami jsou k dispozici odkazováním na sady rozšíření v souboru host.json .
local.settings.json
local.settings.json definuje nastavení aplikace používané při místním spuštění aplikace funkcí. Protože může obsahovat tajné kódy, local.settings.json by měly být vyloučeny ze správy zdrojového kódu. V Azure místo toho použijte nastavení aplikace.
U vlastních obslužných rutin nastavte FUNCTIONS_WORKER_RUNTIME
hodnotu Custom
v local.settings.json.
{
"IsEncrypted": false,
"Values": {
"FUNCTIONS_WORKER_RUNTIME": "Custom"
}
}
Metadata funkcí
Při použití s vlastní obslužnou rutinou se obsah function.json neliší od toho, jak byste definovali funkci v jiném kontextu. Jediným požadavkem je, aby function.json soubory byly ve složce s názvem, aby odpovídaly názvu funkce.
Následující function.json konfiguruje funkci, která má aktivační událost fronty a výstupní vazbu fronty. Protože je ve složce s názvem MyQueueFunction, definuje funkci s názvem 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"
}
]
}
Datová část žádosti
Když se přijme zpráva fronty, hostitel Functions odešle požadavek HTTP post vlastní obslužné rutině s datovou částí v těle.
Následující kód představuje ukázkovou datovou část požadavku. Datová část obsahuje strukturu JSON se dvěma členy: Data
a Metadata
.
Člen Data
obsahuje klíče, které odpovídají názvům vstupních a aktivačních událostí definovaným v poli vazeb v souboru function.json .
Člen Metadata
obsahuje metadata generovaná ze zdroje událostí.
{
"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"
}
}
}
Datová část odpovědi
Podle konvence jsou odpovědi funkcí formátované jako páry klíč/hodnota. Mezi podporované klíče patří:
Datový typ | Poznámky | |
---|---|---|
Outputs |
objekt | Obsahuje hodnoty odpovědí definované polem bindings v function.json.Pokud je například funkce nakonfigurovaná s výstupní vazbou fronty s názvem myQueueOutput, obsahuje Outputs klíč s názvem myQueueOutput , který je nastaven vlastní obslužnou rutinou pro zprávy odeslané do fronty. |
Logs |
pole | Zprávy se zobrazí v protokolech volání funkcí. Při spuštění v Azure se zprávy zobrazí v Application Insights. |
ReturnValue |
string | Slouží k poskytnutí odpovědi, když je výstup nakonfigurovaný jako $return v souboru function.json . |
Toto je příklad datové části odpovědi.
{
"Outputs": {
"res": {
"body": "Message enqueued"
},
"myQueueOutput": [
"queue message 1",
"queue message 2"
]
},
"Logs": [
"Log message 1",
"Log message 2"
],
"ReturnValue": "{\"hello\":\"world\"}"
}
Příklady
Vlastní obslužné rutiny je možné implementovat v libovolném jazyce, který podporuje příjem událostí HTTP. Následující příklady ukazují, jak implementovat vlastní obslužnou rutinu pomocí programovacího jazyka Go.
Funkce s vazbami
Scénář implementovaný v tomto příkladu obsahuje funkci s názvem order
, která přijímá POST
datovou část představující objednávku produktu. Při publikování objednávky do funkce se vytvoří zpráva Queue Storage a vrátí se odpověď HTTP.
Implementace
Ve složce s názvem pořadí nakonfiguruje soubor function.json funkci aktivovanou protokolem 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"
}
]
}
Tato funkce je definována jako funkce aktivovaná protokolem HTTP, která vrací odpověď HTTP a vypíše zprávu queue storage.
V kořenovém adresáři aplikace je soubor host.json nakonfigurovaný tak, aby spustil spustitelný soubor s názvem handler.exe
(handler
v Linuxu nebo macOS).
{
"version": "2.0",
"customHandler": {
"description": {
"defaultExecutablePath": "handler.exe"
}
},
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[1.*, 2.0.0)"
}
}
Toto je požadavek HTTP odeslaný do modulu runtime služby Functions.
POST http://127.0.0.1:7071/api/order HTTP/1.1
Content-Type: application/json
{
"id": 1005,
"quantity": 2,
"color": "black"
}
Modul runtime služby Functions pak odešle vlastní obslužné rutině následující požadavek HTTP:
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": {
}
}
Poznámka:
Některé části datové části byly odebrány kvůli stručnosti.
handler.exe je zkompilovaný program vlastní obslužné rutiny Go, který spouští webový server a reaguje na žádosti o vyvolání funkcí z hostitele služby 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))
}
V tomto příkladu vlastní obslužná rutina spouští webový server pro zpracování událostí HTTP a je nastavena tak, aby naslouchala žádostem prostřednictvím FUNCTIONS_CUSTOMHANDLER_PORT
.
I když hostitel Functions obdržel původní požadavek HTTP, /api/order
vyvolá vlastní obslužnou rutinu pomocí názvu funkce (její název složky). V tomto příkladu je funkce definována na cestě /order
. Hostitel odešle vlastní obslužnou rutinu požadavek HTTP na cestu /order
.
Při POST
odesílání požadavků do této funkce jsou data triggeru a metadata funkcí k dispozici prostřednictvím textu požadavku HTTP. Původní text požadavku HTTP je přístupný v datové části Data.req.Body
.
Odpověď funkce je naformátovaná do párů klíč/hodnota, kde Outputs
člen obsahuje hodnotu JSON, ve které klíče odpovídají výstupům definovaným v souboru function.json .
Toto je příklad datové části, kterou tato obslužná rutina vrátí hostiteli Functions.
{
"Outputs": {
"message": "{\"id\":1005,\"quantity\":2,\"color\":\"black\"}",
"res": {
"body": "Order enqueued"
}
},
"Logs": null,
"ReturnValue": null
}
Nastavením výstupu message
se rovná datům pořadí, která přišla z požadavku, funkce vypíše data objednávky do nakonfigurované fronty. Hostitel Functions také vrátí odpověď HTTP nakonfigurovanou res
volajícímu.
Funkce pouze HTTP
U funkcí aktivovaných protokolem HTTP bez dalších vazeb nebo výstupů můžete chtít, aby obslužná rutina fungovala přímo s požadavkem HTTP a odpovědí místo vlastních požadavků obslužné rutiny a datových částí odpovědí. Toto chování je možné nakonfigurovat v host.json pomocí enableForwardingHttpRequest
tohoto nastavení.
Důležité
Primárním účelem funkce vlastních obslužných rutin je povolit jazyky a moduly runtime, které v současné době nemají prvotřídní podporu ve službě Azure Functions. I když může být možné spouštět webové aplikace pomocí vlastních obslužných rutin, Azure Functions není standardní reverzní proxy server. Některé funkce, jako je streamování odpovědí, HTTP/2 a WebSockets, nejsou k dispozici. Některé součásti požadavku HTTP, například určité hlavičky a trasy, mohou být omezeny. U vaší aplikace může docházet také k nadměrnému studenému startu.
Pokud chcete tyto okolnosti vyřešit, zvažte spuštění webových aplikací ve službě Aplikace Azure Service.
Následující příklad ukazuje, jak nakonfigurovat funkci aktivovanou protokolem HTTP bez dalších vazeb nebo výstupů. Scénář implementovaný v tomto příkladu obsahuje funkci s názvem hello
nebo GET
POST
.
Implementace
Ve složce s názvem hello nakonfiguruje soubor function.json funkci aktivovanou protokolem HTTP.
hello/function.json
{
"bindings": [
{
"type": "httpTrigger",
"authLevel": "anonymous",
"direction": "in",
"name": "req",
"methods": ["get", "post"]
},
{
"type": "http",
"direction": "out",
"name": "res"
}
]
}
Funkce je nakonfigurována tak, aby přijímala požadavky GET
POST
a výsledná hodnota je poskytována prostřednictvím argumentu s názvem res
.
V kořenovém adresáři aplikace je soubor host.json nakonfigurovaný ke spuštění handler.exe
a enableForwardingHttpRequest
je nastavený na true
.
{
"version": "2.0",
"customHandler": {
"description": {
"defaultExecutablePath": "handler.exe"
},
"enableForwardingHttpRequest": true
}
}
Pokud enableForwardingHttpRequest
je true
tomu tak, chování funkcí pouze HTTP se liší od výchozího chování vlastních obslužných rutin těmito způsoby:
- Požadavek HTTP neobsahuje datovou část požadavku vlastních obslužných rutin. Místo toho hostitel Functions vyvolá obslužnou rutinu s kopií původního požadavku HTTP.
- Hostitel Functions vyvolá obslužnou rutinu se stejnou cestou jako původní požadavek, včetně jakýchkoli parametrů řetězce dotazu.
- Hostitel Functions vrátí kopii odpovědi HTTP obslužné rutiny jako odpověď na původní požadavek.
Následuje požadavek POST na hostitele služby Functions. Hostitel služby Functions pak odešle kopii požadavku vlastní obslužné rutině ve stejné cestě.
POST http://127.0.0.1:7071/api/hello HTTP/1.1
Content-Type: application/json
{
"message": "Hello World!"
}
Soubor handler.go implementuje webový server a funkci 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))
}
V tomto příkladu vlastní obslužná rutina vytvoří webový server pro zpracování událostí HTTP a je nastaven tak, aby naslouchal žádostem prostřednictvím FUNCTIONS_CUSTOMHANDLER_PORT
.
GET
požadavky se zpracovávají vrácením řetězce a POST
požadavky mají přístup k textu požadavku.
Trasa pro funkci objednávky je /api/hello
stejná jako původní požadavek.
Poznámka:
Nejedná se FUNCTIONS_CUSTOMHANDLER_PORT
o veřejný port používaný k volání funkce. Tento port používá hostitel služby Functions k volání vlastní obslužné rutiny.
Nasazování
Vlastní obslužnou rutinu je možné nasadit na každou možnost hostování Azure Functions. Pokud obslužná rutina vyžaduje závislosti operačního systému nebo platformy (například jazykový modul runtime), možná budete muset použít vlastní kontejner.
Při vytváření aplikace funkcí v Azure pro vlastní obslužné rutiny doporučujeme jako zásobník vybrat .NET Core.
Pokud chcete nasadit vlastní aplikaci obslužné rutiny pomocí nástrojů Azure Functions Core Tools, spusťte následující příkaz.
func azure functionapp publish $functionAppName
Poznámka:
Ujistěte se, že všechny soubory potřebné ke spuštění vlastní obslužné rutiny jsou ve složce a jsou součástí nasazení. Pokud je vaše vlastní obslužná rutina binární spustitelný soubor nebo má závislosti specifické pro platformu, ujistěte se, že tyto soubory odpovídají cílové platformě nasazení.
Omezení
- Webový server vlastní obslužné rutiny se musí spustit do 60 sekund.
Ukázky
Řešení potíží a podpora
Protokolování trasování
Pokud se váš vlastní proces obslužné rutiny nespustí nebo pokud má problémy s komunikací s hostitelem Functions, můžete zvýšit úroveň protokolu aplikace funkcí, aby Trace
se zobrazily další diagnostické zprávy z hostitele.
Pokud chcete změnit výchozí úroveň protokolu aplikace funkcí, nakonfigurujte logLevel
nastavení v logging
části host.json.
{
"version": "2.0",
"customHandler": {
"description": {
"defaultExecutablePath": "handler.exe"
}
},
"logging": {
"logLevel": {
"default": "Trace"
}
}
}
Hostitel služby Functions vypíše další zprávy protokolu, včetně informací souvisejících s vlastním procesem obslužné rutiny. Pomocí protokolů můžete prozkoumat problémy se spuštěním vlastního procesu obslužné rutiny nebo vyvoláním funkcí ve vlastní obslužné rutině.
Místně se protokoly vytisknou do konzoly.
V Azure se dotazujte na trasování Application Insights, aby se zobrazily zprávy protokolu. Pokud vaše aplikace vytváří velký objem protokolů, do Application Insights se odešle jenom podmnožina zpráv protokolu. Zakažte vzorkování , aby se zajistilo, že jsou protokolované všechny zprávy.
Testování vlastní obslužné rutiny v izolaci
Vlastní aplikace obslužné rutiny jsou procesem webového serveru, takže může být užitečné ji spustit na vlastní a testovací vyvolání funkce odesláním napodobených požadavků HTTP. Pro odesílání požadavků HTTP s datovými částmi nezapomeňte zvolit nástroj, který udržuje vaše data v bezpečí. Další informace najdete v tématu Nástroje pro testování HTTP.
Tuto strategii můžete použít také v kanálech CI/CD ke spouštění automatizovaných testů na vlastní obslužné rutině.
Spouštěcí prostředí
Vlastní obslužné rutiny běží ve stejném prostředí jako typická aplikace Azure Functions. Otestujte obslužnou rutinu a ujistěte se, že prostředí obsahuje všechny závislosti, které potřebuje ke spuštění. U aplikací, které vyžadují další závislosti, je možné, že je budete muset spustit pomocí vlastní image kontejneru hostované v plánu Azure Functions Premium.
Získání podpory
Pokud potřebujete pomoc s aplikací funkcí s vlastními obslužnými rutinami, můžete odeslat žádost prostřednictvím běžných kanálů podpory. Vzhledem k široké škále možných jazyků používaných k vytváření vlastních aplikací obslužných rutin však podpora není neomezená.
Podpora je dostupná, pokud má hostitel služby Functions problémy se spuštěním nebo komunikací s vlastním procesem obslužné rutiny. V případě problémů specifických pro vnitřní fungování vašeho vlastního procesu obslužné rutiny, jako jsou problémy s vybraným jazykem nebo architekturou, nemůže náš tým podpory v tomto kontextu poskytnout pomoc.
Další kroky
Začněte vytvářet aplikaci Azure Functions v Go nebo Rust pomocí rychlého startu vlastních obslužných rutin.