azure-samples / functions-custom-handlers Goto Github PK
View Code? Open in Web Editor NEWSample code for Azure Functions custom handlers
License: MIT License
Sample code for Azure Functions custom handlers
License: MIT License
Hi, I'm using a custom handler so I write a function in Rust: https://github.com/squamishaccess/squamishaccess-signup-function-rs
My main blocker right now is figuring out how to log properly.
Logging to the stdio only seems to show up in a local (VS Code) log stream, and not in the function monitor panel log stream. Ideally I'd like to make log traces to the "invocations" panel, I'm unsure if that is scraped from file system logs or Application Insights.
Additionally, it doesn't seem to parse JSON logs. Here is an example:
2020-10-23T23:05:47.930 [Trace] Sending invocation id:cae182d4-f137-4a62-bc79-76d9265924e1
2020-10-23T23:05:47.930 [Debug] Forwarding httpTrigger invocation for function: 'Paypal-IPN' invocationId: 'cae182d4-f137-4a62-bc79-76d9265924e1'
2020-10-23T23:05:47.931 [Debug] Sending invocation for function: 'Paypal-IPN' invocationId: 'cae182d4-f137-4a62-bc79-76d9265924e1'
2020-10-23T23:05:47.940 [Information] {"level":30,"time":1603494347939,"msg":"<-- Request received","method":POST,"path":/api/Paypal-IPN}
2020-10-23T23:05:47.946 [Information] {"level":30,"time":1603494347939,"msg":"cae182d4-f137-4a62-bc79-76d9265924e1 PayPal IPN Notification Event received successfully."}
The lines that say ... [Information] {"level":30, ...
are from my json logger.
I am trying to use the R example code provided in this repo which works fine until I try and run it inside a Docker container. I have tried multiple variations on the base Dockerfile listed here as well as the R-specific one in this article: https://docs.microsoft.com/en-us/azure/azure-functions/functions-create-function-linux-custom-image
My Dockerfile presently looks like:
# To enable ssh & remote debugging on app service change the base image to the one below
# FROM mcr.microsoft.com/azure-functions/node:2.0-appservice
FROM mcr.microsoft.com/azure-functions/node:3.0
ENV AzureWebJobsScriptRoot=/home/site/wwwroot \
AzureFunctionsJobHost__Logging__Console__IsEnabled=true
RUN apt update
RUN apt install -y r-base
RUN R -e "install.packages('httpuv', repos='http://cran.rstudio.com/')"
COPY . /home/site/wwwroot
RUN cd /home/site/wwwroot
I've attached the full logs from attempting to run this but the only failure is:
fail: Worker.HttpWorkerProcess.bbbfc2f8-34a3-4a6b-89d9-8a537071af94[0]
Failed to start Worker Channel. Process fileName: Rscript
System.ComponentModel.Win32Exception (2): No such file or directory
at System.Diagnostics.Process.ForkAndExecProcess(String filename, String[] argv, String[] envp, String cwd, Boolean redirectStdin, Boolean redirectStdout, Boolean redirectStderr, Boolean setCredentials, UInt32 userId, UInt32 groupId, UInt32[] groups, Int32& stdinFd, Int32& stdoutFd, Int32& stderrFd, Boolean usesTerminal, Boolean throwOnNoExec)
at System.Diagnostics.Process.StartCore(ProcessStartInfo startInfo)
at System.Diagnostics.Process.Start()
at Microsoft.Azure.WebJobs.Script.Workers.WorkerProcess.StartProcessAsync() in /src/azure-functions-host/src/WebJobs.Script/Workers/ProcessManagement/WorkerProcess.cs:line 65
As a test, I ran a shell in the base image: mcr.microsoft.com/azure-functions/node:3.0
and manually executed all the build steps in the Dockerfile. They all completed successfully and I could happily execute Rscript
both with and without the full path to the executable
Any help greatly appreciated
Example Dockerfile that works with Linux Function apps is something I really would like to see
I have created a Golang custom handler that is running on a windows consumption plan. The Function App runtime version is 3.0.13353.0. I have followed the sample Golang code in this repo and modified it to trigger on event hub events.
My host.json
file is:
{
"version": "2.0",
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[1.*, 2.0.0)"
},
"extensions": {
"eventHubs": {
"batchCheckpointFrequency": 1,
"eventProcessorOptions": {
"maxBatchSize": 512,
"prefetchCount": 1024
}
}
},
"httpWorker": {
"description": {
"defaultExecutablePath": "main.exe"
}
}
}
and my function.json
file is:
{
"bindings": [
{
"type": "eventHubTrigger",
"name": "events",
"direction": "in",
"eventHubName": "diagnostic-logs",
"consumerGroup": "consumer-group",
"cardinality": "many",
"connection": "DIAGNOSTIC_LOGS_EVENT_HUB_CONNECTION_STRING"
}
]
}
In addition to modifying the code to be triggered off of event hub events, I also added the ability to fetch a secret from Key Vault on start up. Because of this, I have assigned the Function App a system assigned managed service identity and have given it permissions get
secrets from a Key Vault.
My code is as follows:
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"net/http"
"os"
"strings"
"github.com/Azure/azure-sdk-for-go/services/keyvault/2016-10-01/keyvault"
"github.com/Azure/go-autorest/autorest/azure"
"github.com/Azure/go-autorest/autorest/azure/auth"
)
var (
mySecret string
)
type InvokeResponse struct {
Outputs map[string]interface{}
Logs []string
ReturnValue interface{}
}
type InvokeRequest struct {
Data map[string]interface{}
Metadata map[string]interface{}
}
func init() {
authorizer, err := auth.NewAuthorizerFromEnvironmentWithResource(strings.TrimSuffix(azure.PublicCloud.KeyVaultEndpoint, "/"))
if err != nil {
fmt.Println("Failed to create authorizer")
os.Exit(1)
}
secretsClient := keyvault.New()
secretsClient.Authorizer = authorizer
fmt.Println("Fetching secret")
secret, err := secretsClient.GetSecret(context.Background(), os.Getenv("AZU_KEY_VAULT_URI"), "my-secret", "")
if err != nil {
fmt.Printf("Failed to fetch secret: %s\n", err)
os.Exit(1)
}
mySecret = *secret.Value
fmt.Println("Successfully fetched secret")
}
func eventHubTrigger(w http.ResponseWriter, r *http.Request) {
fmt.Println("Triggered")
invokeResponse := InvokeResponse{Logs: []string{"success"}}
js, err := json.Marshal(invokeResponse)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
w.Write(js)
}
func main() {
httpInvokerPort, exists := os.LookupEnv("FUNCTIONS_HTTPWORKER_PORT")
if exists {
fmt.Println("FUNCTIONS_HTTPWORKER_PORT: " + httpInvokerPort)
}
mux := http.NewServeMux()
mux.HandleFunc("/diagnostic_logs", eventHubTrigger)
log.Println("Go server Listening...on httpInvokerPort:", httpInvokerPort)
log.Fatal(http.ListenAndServe(":"+httpInvokerPort, mux))
}
The main thing to call out is the init()
function which fetches the secret from Key Vault.
Every execution of the function is throwing a System.Net.Sockets.SocketException
exception for me. The message for the exception is "An attempt was made to access a socket in a way forbidden by its access permissions. An attempt was made to access a socket in a way forbidden by its access permissions."
I can see the line fmt.Println("Fetching secret")
printing in App Insights but nothing else seems to be printed after this. If I were to remove the fetching of the secret from Key Vault (so the whole init()
function), the function executes fine.
I don't know if this issue is related to custom handlers, but I would appreciate some guidance.
Hi,
Is there any detailed instruction about supported keys in Outsputs and ReturnValue of response payload?
Thanks.
The Go example says:
Name Trigger Input Output
SimpleHttpTriggerWithReturn | HTTP | Event Hub | n/a
Since I don't see any Event Hub in the function.json, is this a mistake in the README?
I deployed a basic Go custom handler to a brand new function app and am unable to invoke it. I get an HTTP 502 error, with the message "There is a problem with the page you are looking for, and it cannot be displayed. When the Web server (while acting as a gateway or proxy) contacted the upstream content server, it received an invalid response from the content server.".
Running func host start
works just fine, so I'm not entirely sure what's causing it not to work once deployed.
host.json
{
"version": "2.0",
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[1.*, 2.0.0)"
},
"httpWorker": {
"description": {
"defaultExecutablePath": "server.exe"
}
}
}
function.json
{
"bindings": [
{
"type": "httpTrigger",
"authLevel": "anonymous",
"direction": "in",
"methods": ["GET", "POST"],
"name": "req"
},
{
"type": "http",
"direction": "out",
"name": "$return"
}
]
}
server.go
package main
import (
"net/http"
"log"
"os"
"fmt"
)
func handler(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello World from go worker"))
}
func main() {
httpInvokerPort, exists := os.LookupEnv("FUNCTIONS_HTTPWORKER_PORT")
if exists {
fmt.Println("FUNCTIONS_HTTPWORKER_PORT: " + httpInvokerPort)
}
log.Println("Go server Listening...on httpInvokerPort:", httpInvokerPort)
http.HandleFunc("/convert", handler)
log.Fatal(http.ListenAndServe(":"+httpInvokerPort, nil))
}
Directory Structure
convert/
function.json
host.json
server.exe
server.go
Project Setup Commands
az group create --name EpubToKpx-rg --location westus
az storage account create --name epubtokpxstorage --location westus --resource-group EpubToKpx-rg --sku Standard_LRS
az functionapp create --resource-group EpubToKpx-rg --os-type Windows --consumption-plan-location westus --functions-version 3 --name epubtokpx --storage-account epubtokpxstorage
go build -o server.exe server.go
func host start
func azure functionapp publish epubtokpx
Is there documentation or an example that someone could point me to for how to implement a Timer trigger?
I've reviewed the available samples and documentation but wasn't able to find anything for Golang custom handlers using a Timer trigger.
Hi, it is more question than issue.
I know, I can ask it on stackowerflow, but since I'm asking about official way, only you know it.
Is there official way to connect to CosmosDB through RUst custom handler ?
Thanks
Why did code samples for C#, Java, and Node were deleted by Pull Request #12?
Description
I have set up a CI/CD pipeline in Azure DevOps for my Azure Function (written in GoLang) that seems to run successfully, including steps for building, packaging, and deploying the function. However, despite the successful deployment, the function does not get triggered when the associated Event Subscription receives events.
Pipeline Configuration
`trigger:
pool:
vmImage: 'ubuntu-latest'
variables:
directory: '.'
functionAppName: ''
resourceGroupName: ''
azureSubscription: 'Microsoft Azure Sponsorship (***)'
stages:
stage: Build
displayName: 'Build Stage'
jobs:
task: GoTool@0
inputs:
version: '1.21.0'
displayName: 'Installing Go 1.21.0'
script: |
echo "Construindo a aplicação..."
GOOS=linux GOARCH=amd64 go build -o $(directory)/main
workingDirectory: $(directory)
displayName: 'Build Application Binary'
script: |
echo "Zip the project folder"
zip -r config.zip .
workingDirectory: $(directory)
displayName: 'Zip the project folder'
task: PublishBuildArtifacts@1
inputs:
pathtoPublish: '$(directory)/config.zip'
artifactName: 'drop'
publishLocation: 'Container'
stage: Deploy
displayName: 'Deploy Stage'
dependsOn: Build
condition: succeeded('Build')
jobs:
task: DownloadBuildArtifacts@0
inputs:
buildType: 'current'
downloadType: 'single'
artifactName: 'drop'
downloadPath: '$(System.ArtifactsDirectory)'
script: |
ls $(System.ArtifactsDirectory)/drop/
ls $(System.ArtifactsDirectory)/
displayName: 'Check if necessary zip is in the right directory'
task: AzureCLI@2
inputs:
azureSubscription: $(azureSubscription)
scriptType: 'bash'
scriptLocation: 'inlineScript'
inlineScript: |
az functionapp deployment source config-zip --resource-group
displayName: 'Deploy via Azure CLI'
``
task: AzureCLI@2
inputs:
azureSubscription: $(azureSubscription)
scriptType: 'bash'
scriptLocation: 'inlineScript'
inlineScript: |
az functionapp deployment list-publishing-profiles --name
displayName: 'Verify deploy via Azure CLI'
`
host.json
{ "version": "2.0", "logging": { "logLevel": { "Function": "Information", "Host.Results": "Information", "Host.Aggregator": "Information", "FunctionApp": "Information" } }, "extensionBundle": { "id": "Microsoft.Azure.Functions.ExtensionBundle", "version": "[3.*, 4.0.0)" }, "customHandler": { "description": { "defaultExecutablePath": "main", "workingDirectory": "", "arguments": [] } } }
function.json
{
"bindings": [
{
"type": "eventGridTrigger",
"name": "eventGridEvent",
"direction": "in"
}
]
}
Issue Observed:
The pipeline completes successfully without any errors, and the deployment seems to be working fine.
However, the function does not trigger when the Event Subscription receives an event.
Attempts to Resolve:
I have verified that the Event Subscription is correctly configured and pointing to the function.
The function works as expected when deployed manually or tested locally.
There are no errors or issues in the Azure portal regarding the function or the Event Subscription.
Seeking Guidance:
Is there something I'm missing in my pipeline configuration that could cause this issue?
Are there any known issues with Azure Functions (especially custom handlers in GoLang) not being triggered by Event Subscriptions after a pipeline deployment?
Any guidance or suggestions on what else I can check or how to troubleshoot this further would be greatly appreciated.
I'm trying to understand custom handlers, and how you write them in an arbitrary language.
R is a good example of this.
The R sample here though doesn't seem to tell me anything about where the R runtime actually comes from. The only Dockerfile provided uses a "node" base image.
Naively I was expecting there to be a Dockerfile for the R sample that specified some kind of base image that contained an R runtime environment? But I probably misunderstand how custom handlers, and custom image work.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.