Handler kustom Azure Functions
Setiap aplikasi Functions dijalankan oleh handler khusus bahasa. Meskipun Azure Functions mendukung banyak handler bahasa pemrogram secara default, di beberapa kasus sebaiknya Anda menggunakan bahasa pemrograman atau runtime yang berbeda.
Handler kustom adalah server web ringan yang menerima kejadian dari host Functions. Semua bahasa pemrogram yang mendukung primitif HTTP dapat mengimplementasikan handler kustom.
Handler kustom paling cocok untuk situasi di mana Anda ingin:
- Menerapkan aplikasi fungsi dalam bahasa pemrograman yang saat ini di luar cakupan, seperti Go atau Rust.
- Menerapkan aplikasi fungsi dalam runtime yang saat ini tidak didukung secara default, seperti Deno.
Dengan handler, Anda dapat menggunakan pemicu dan pengikatan input dan output melalui bundel ekstensi.
Mulai menggunakan handler kustom Azure Functions dengan mulai cepat di Go dan Rust.
Gambaran Umum
Diagram berikut menunjukkan hubungan antara host Functions dan server web yang diterapkan sebagai penanganan kustom.
- Setiap kejadian memicu permintaan yang dikirim ke host Functions. Kejadian adalah pemicu apa pun yang didukung oleh Azure Functions.
- Host Functions kemudian mengeluarkan permintaan payload ke server web. Payload memegang data pemicu dan pengikatan input serta metadata lainnya untuk fungsi tersebut.
- Server web menjalankan fungsi individual, dan mengembalikan payload respons ke host Functions.
- Host Functions meneruskan data dari respons ke pengikatan output fungsi untuk diproses.
Aplikasi Azure Functions yang diterapkan sebagai penanganan kustom harus mengonfigurasi file host.json, local.settings.json, dan function.json sesuai dengan beberapa konvensi.
Struktur aplikasi
Untuk mengimplementasikan penanganan kustom, Anda memerlukan beberapa aspek berikut untuk aplikasi Anda:
- File host.jsfon pada akar aplikasi Anda
- File local.settings.json pada akar aplikasi Anda
- File function.json untuk setiap fungsi (di dalam folder yang cocok dengan nama fungsinya)
- Perintah, skrip, atau dapat dieksekusi, yang menjalankan server web
Diagram berikut menunjukkan bagaimana file-file ini terlihat pada sistem file untuk fungsi bernama "MyQueueFunction" dan handler kustom yang dapat dieksekusi bernama handler.exe.
| /MyQueueFunction
| function.json
|
| host.json
| local.settings.json
| handler.exe
Konfigurasi
Aplikasi dikonfigurasi melalui file host.json dan local.settings.json.
host.json
host.json memberi tahu host Functions tempat mengirim permintaan dengan menunjuk ke server web yang mampu memproses kejadian HTTP.
Handler kustom ditentukan dengan mengonfigurasi filehost.json beserta detail tentang cara menjalankan server web melalui bagian customHandler
tersebut.
{
"version": "2.0",
"customHandler": {
"description": {
"defaultExecutablePath": "handler.exe"
}
}
}
Bagian customHandler
ini menunjuk ke target sebagaimana ditentukan oleh defaultExecutablePath
. Target eksekusi dapat berupa perintah, executable, atau file tempat server web diimplementasikan.
Gunakan larik arguments
untuk meneruskan argumen apa pun ke executable. Argumen mendukung perluasan variabel lingkungan (pengaturan aplikasi) menggunakan notasi %%
.
Anda juga dapat mengubah direktori kerja yang digunakan oleh executable dengan workingDirectory
.
{
"version": "2.0",
"customHandler": {
"description": {
"defaultExecutablePath": "app/handler.exe",
"arguments": [
"--database-connection-string",
"%DATABASE_CONNECTION_STRING%"
],
"workingDirectory": "app"
}
}
}
Dukungan pengikatan
Pemicu standar beserta pengikatan input dan output tersedia dengan mereferensikan file bundel ekstensi pada file host.json Anda.
local.settings.json
local.settings.json mendefinisikan pengaturan aplikasi yang digunakan saat menjalankan aplikasi fungsi secara lokal. Karena mungkin berisi rahasia, local.settings.json harus dikecualikan dari kontrol kode sumber. Di Azure, gunakan pengaturan aplikasi sebagai gantinya.
Untuk handler kustom, atur FUNCTIONS_WORKER_RUNTIME
ke Custom
dalam local.settings.json.
{
"IsEncrypted": false,
"Values": {
"FUNCTIONS_WORKER_RUNTIME": "Custom"
}
}
Metadata fungsi
Ketika digunakan dengan handler kustom, konten function.json tidak berbeda dari bagaimana Anda akan mendefinisikan fungsi di bawah konteks lain. Satu-satunya persyaratan adalah file function.json harus berada di dalam folder yang diberi nama sesuai dengan nama fungsinya.
Contoh function.json mengkonfigurasi fungsi yang memiliki pemicu antrean dan pengikatan output antrean. Karena berada dalam folder bernama MyQueueFunction, folder ini mendefinisikan fungsi bernama 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"
}
]
}
Permintaan payload
Ketika pesan antrean diterima, host Functions mengirim permintaan posting HTTP ke handler kustom dengan payload di dalam badan pesan.
Kode berikut menunjukkan contoh permintaan payload. Payload mencakup struktur JSON dengan dua anggota: Data
dan Metadata
.
Anggota Data
menyertakan kunci yang cocok dengan nama input dan pemicu seperti yang didefinisikan dalam larik pengikatan dalam file function.json.
Anggota Metadata
menyertakan metadata yang dihasilkan dari sumber kejadain.
{
"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"
}
}
}
Payload respons
Menurut konvensi, respons fungsi diformat sebagai pasangan kunci/nilai. Kunci yang didukung meliputi:
Jenis Data | Keterangan | |
---|---|---|
Outputs |
object | Mengandung nilai respons sebagaimana didefinisikan pada larikbindings di function.json.Misalnya, jika fungsi dikonfigurasi dengan pengikatan output antrean bernama "myQueueOutput", maka Outputs berisi kunci bernama myQueueOutput , yang diatur oleh handler kustom ke pesan yang dikirim ke antrean. |
Logs |
array | Pesan muncul di log pemanggilan Functions. Saat dijalankan di Azure, pesan muncul di Application Insights. |
ReturnValue |
string | Digunakan untuk memberikan respons ketika output dikonfigurasi seperti $return di dalam file function.json. |
Ini adalah contoh respons payload.
{
"Outputs": {
"res": {
"body": "Message enqueued"
},
"myQueueOutput": [
"queue message 1",
"queue message 2"
]
},
"Logs": [
"Log message 1",
"Log message 2"
],
"ReturnValue": "{\"hello\":\"world\"}"
}
Contoh
Handler kustom dapat diimplementasikan dalam semua bahasa pemrogram yang mendukung penerimaan kejadian HTTP. Contoh berikut menunjukkan cara mengimplementasikan handler kustom menggunakan bahasa pemrogram Go.
Fungsi dengan pengikatan
Skenario yang diterapkan dalam contoh ini menampilkan fungsi bernama order
yang menerima POST
dengan payload yang mewakili pesanan produk. Saat pesanan di-posting pada fungsi, pesan Queue Storage dibuat dan respons HTTP dikembalikan.
implementasi
Dalam folder bernama order, file function.json mengkonfigurasi fungsi yang dipicu 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"
}
]
}
Fungsi ini didefinisikan sebagai fungsi yang dipicu HTTP yang mengembalikan respons HTTP dan output pesan Queue storage.
Di akar aplikasi, file host.json dikonfigurasi untuk menjalankan file executable bernama handler.exe
( handler
di Linux atau macOS).
{
"version": "2.0",
"customHandler": {
"description": {
"defaultExecutablePath": "handler.exe"
}
},
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[1.*, 2.0.0)"
}
}
Ini adalah permintaan HTTP yang dikirim ke runtime Functions.
POST http://127.0.0.1:7071/api/order HTTP/1.1
Content-Type: application/json
{
"id": 1005,
"quantity": 2,
"color": "black"
}
Runtime Functions kemudian akan mengirim permintaan HTTP berikut ke handler kustom:
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": {
}
}
Catatan
Beberapa bagian dari payload dihapus untuk keringkasan.
handler.exe adalah program penanganan kustom Go terkompilasi yang menjalankan server web dan merespons permintaan pemanggilan fungsi dari host 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))
}
Dalam contoh ini, handler kustom menjalankan server web untuk menangani kejadian HTTP dan disetel untuk mendengarkan permintaan melalui FUNCTIONS_CUSTOMHANDLER_PORT
.
Meskipun host Functions menerima permintaan HTTP asli pada /api/order
, host Functions memanggil penanganan kustom menggunakan nama fungsi (nama foldernya). Dalam contoh ini, fungsi didefinisikan pada jalur /order
. Host mengirim penanganan kustom permintaan HTTP di jalur /order
.
Karena POST
permintaan dikirim ke fungsi ini, data pemicu dan metadata fungsi tersedia melalui badan permintaan HTTP. Badan permintaan HTTP asli dapat diakses di dalam Data.req.Body
payload.
Respons fungsi diformat menjadi pasangan kunci/nilai ketikaOutputs
anggota memegang nilai JSON di mana kuncinya cocok dengan output seperti yang didefinisikan dalam file function.json.
Ini adalah contoh payload yang dikembalikan handler kustom ke host Functions.
{
"Outputs": {
"message": "{\"id\":1005,\"quantity\":2,\"color\":\"black\"}",
"res": {
"body": "Order enqueued"
}
},
"Logs": null,
"ReturnValue": null
}
Dengan mengatur output message
yang sama dengan data pesanan yang masuk dari permintaan, fungsi akan meng-output data pesanan ke antrean yang dikonfigurasi. Host Functions juga mengembalikan respons HTTP yang dikonfigurasi pada res
ke penelepon.
Fungsi HTTP-only
Untuk fungsi yang dipicu HTTP tanpa pengikatan atau output tambahan, Anda mungkin ingin handler kustom Anda bekerja langsung dengan permintaan dan respons HTTP daripada permintaan penanganan kustom dan payload respons. Perilaku ini dapat dikonfigurasi pada host.json menggunakan pengaturan enableForwardingHttpRequest
.
Penting
Tujuan utama fitur handler kustom adalah untuk mengaktifkan bahasa pemrogram dan runtime yang saat ini tidak memiliki dukungan kelas satu di Azure Functions. Meskipun aplikasi web dapat dijalankan menggunakan handler kustom, Azure Functions bukan standar proksi terbalik. Beberapa fitur seperti streaming respons, HTTP/2, dan WebSocket tidak tersedia. Beberapa komponen permintaan HTTP seperti header dan rute tertentu mungkin dibatasi. Aplikasi Anda mungkin juga mengalami cold start yang berlebihan.
Untuk mengatasi keadaan ini, pertimbangkan untuk menjalankan aplikasi web Anda di Azure App Service.
Contoh berikut menunjukkan cara mengonfigurasi fungsi yang dipicu HTTP tanpa pengikatan atau output tambahan. Skenario yang diterapkan dalam contoh ini menampilkan fungsi bernama hello
yang menerima GET
atau POST
.
implementasi
Dalam folder bernama hello, file function.json mengkonfigurasi fungsi yang dipicu HTTP.
hello/function.json
{
"bindings": [
{
"type": "httpTrigger",
"authLevel": "anonymous",
"direction": "in",
"name": "req",
"methods": ["get", "post"]
},
{
"type": "http",
"direction": "out",
"name": "res"
}
]
}
Fungsi ini dikonfigurasi untuk menerima kedua permintaan GET
dan POST
serta nilai hasil disediakan melalui argumen bernama res
.
Di akar aplikasi, file host.json dikonfigurasi untuk menjjalankan handler.exe
dan enableForwardingHttpRequest
disetel ke true
.
{
"version": "2.0",
"customHandler": {
"description": {
"defaultExecutablePath": "handler.exe"
},
"enableForwardingHttpRequest": true
}
}
Ketika enableForwardingHttpRequest
adalah true
, perilaku fungsi http-only berbeda dari perilaku default handler kustom dengan beberapa cara ini:
- Permintaan HTTP tidak berisi handler kustom meminta payload. Sebaliknya, host Functions memanggil handler kustom melalui salinan permintaan HTTP asli.
- Host Functions memanggil handler kustom melaui jalur yang sama dengan permintaan asli termasuk semua parameter untai kueri.
- Host Functions mengembalikan salinan respons HTTP handler sebagai respons terhadap permintaan asli.
Berikut ini adalah permintaan POST ke host Functions. Host Functions kemudian mengirim salinan permintaan ke handler kustom pada jalur yang sama.
POST http://127.0.0.1:7071/api/hello HTTP/1.1
Content-Type: application/json
{
"message": "Hello World!"
}
File handler.go file menerapkan server web dan fungsi 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))
}
Dalam contoh ini, handler kustom membuat server web untuk menghandel kejadian HTTP dan disetel untuk mendengarkan permintaan melalui FUNCTIONS_CUSTOMHANDLER_PORT
.
GET
permintaan ditangani dengan mengembalikan string, dan permintaan POST
memiliki akses ke badan permintaan.
Rute untuk fungsi pesanan di sini adalah /api/hello
, sama dengan permintaan asli.
Catatan
FUNCTIONS_CUSTOMHANDLER_PORT
bukan merupakan port dengan akses publik yang digunakan untuk memanggil fungsi. Port ini digunakan oleh host Functions untuk memanggil handler kustom.
Menyebarkan
Handler kustom dapat disebarkan ke setiap opsi hosting Azure Functions. Jika handler kustom Anda memerlukan dependensi sistem operasi atau platform (seperti runtime bahasa pemrogram), Anda mungkin perlu menggunakan kontainer kustom.
Saat membuat aplikasi fungsi di Azure untuk handler kustom, kami sarankan Anda memilih .NET Core sebagai tumpukan.
Untuk menyebarkan aplikasi handler kustom menggunakan Azure Functions Core Tools, jalankan perintah berikut.
func azure functionapp publish $functionAppName
Catatan
Pastikan semua file yang diperlukan untuk menjalankan handler kustom Anda ada di folder dan disertakan dalam penyebaran. Jika hander kustom Anda adalah executable biner atau memiliki dependensi khusus platform, pastikan seluruh file ini cocok dengan platform penyebaran target.
Batasan
- Server web handler kustom harus dimulai dalam 60 detik.
Sampel
Lihat sampel hander kustom dari GitHub repo untuk contoh cara mengimplementasikan fungsi dalam berbagai bahasa pemrogram yang berbeda.
Pemecahan masalah dan dukungan
Pembuatan log jejak
Jika proses handler kustom Anda gagal memulai atau jika mengalami masalah saat berkomunikasi dengan host Functions, Anda dapat meningkatkan tingkat log aplikasi fungsi ke Trace
guna melihat lebih banyak pesan diagnostik dari host.
Untuk mengubah tingkat log default aplikasi fungsi, konfigurasikan pengaturan logLevel
di bagian logging
dari host.json.
{
"version": "2.0",
"customHandler": {
"description": {
"defaultExecutablePath": "handler.exe"
}
},
"logging": {
"logLevel": {
"default": "Trace"
}
}
}
Host Functions memberikan output pesan log tambahan termasuk informasi yang terkait dengan proses handler kustom. Gunakan log untuk menyelidiki masalah saat memulai proses handler kustom Anda atau memanggil fungsi pada handler kustom Anda.
Secara lokal, log dicetak ke konsol.
Di Azure, kueri Application Insights melakukan pelacakan untuk menampilkan pesan log. Jika aplikasi Anda menghasilkan log dalam jumlah besar, hanya sebagian pesan log yang dikirim ke Application Insights. Nonaktifkan pengambilan sampel untuk memastikan semua pesan tercatat.
Menguji handler kustom secara isolasi
Aplikasi handler kustom adalah proses server web, sehingga mungkin berguna untuk memulainya sendiri dan menguji pemanggilan fungsi dengan mengirim permintaan HTTP tiruan. Untuk mengirim permintaan HTTP dengan payload, pastikan untuk memilih alat yang menjaga keamanan data Anda. Untuk informasi selengkapnya, lihat Alat pengujian HTTP.
Anda juga dapat menggunakan strategi ini di alur CI/CD untuk menjalankan pengujian otomatis pada handler kustom Anda.
Lingkungan eksekusi
Handler kustom dijalankan di lingkungan yang sama dengan aplikasi Azure Functions biasa. Uji handler Anda untuk memastikan lingkungan berisi semua dependensi yang diperlukan untuk berjalan. Untuk aplikasi yang memerlukan dependensi tambahan, Anda mungkin perlu menjalankannya menggunakan citra kontainer kustom yang di hosting pada paket Azure Functions Premium.
Dapatkan dukungan
Jika memerlukan bantuan pada aplikasi fungsi dengan handler kustom, Anda dapat mengirimkan permintaan melalui saluran dukungan reguler. Namun, karena berbagai bahasa pemrogram yang mungkin digunakan untuk membangun aplikasi handler kustom, dukungan akan terbatas.
Dukungan tersedia jika host Functions memiliki masalah saat memulai atau berkomunikasi dengan proses handler kustom. Untuk masalah khusus mengenai cara kerja di dalam proses handler kustom Anda, seperti masalah dengan bahasa pemrogram atau kerangka kerja yang dipilih, Tim Dukungan kami tidak dapat memberikan bantuan dalam konteks ini.
Langkah berikutnya
Mulai membangun aplikasi Azure Functions di Go atau Rust dengan mulai cepat penanganan kustom.