/azure-functions-rs

Create Azure Functions with Rust!

Primary LanguageRustMIT LicenseMIT

Notice

⚠️

This project is no longer being actively maintained by the original author.

Forks or derivative works are encouraged!

Azure Functions for Rust

crates-status docs-status all-contributors-status gitter-status build-status dependabot-status license-status

A framework for implementing Azure Functions in Rust.

🚩 Disclaimer
This project is not an officially recognized Microsoft product and is not an endorsement of any future product offering from Microsoft.

Microsoft and Azure are registered trademarks of Microsoft Corporation.

If you would like the Azure Functions team to consider supporting Rust, please vote up this feedback item.

Example

A simple HTTP-triggered Azure Function:

use azure_functions::{
    bindings::{HttpRequest, HttpResponse},
    func,
};

#[func]
pub fn greet(req: HttpRequest) -> HttpResponse {
    format!(
        "Hello from Rust, {}!\n",
        req.query_params().get("name").map_or("stranger", |x| x)
    )
    .into()
}

Azure Functions for Rust also supports async functions:

use azure_functions::{
    bindings::{HttpRequest, HttpResponse},
    func,
};
use futures::future::ready;

#[func]
pub async fn greet_async(req: HttpRequest) -> HttpResponse {
    // Use ready().await to simply demonstrate the async/await feature
    ready(format!(
        "Hello from Rust, {}!\n",
        req.query_params().get("name").map_or("stranger", |x| x)
    ))
    .await
    .into()
}

See Building an async Azure Functions application for more information.

Get Started

Table of Contents

Installation

Requirements

.NET Core SDK

A .NET Core SDK is required to synchronize Azure Functions Host binding extensions.

For example, using the Cosmos DB bindings will need the Microsoft.Azure.WebJobs.Extensions.CosmosDB extensions installed for the Azure Functions Host.

This happens automatically by Azure Functions for Rust when the application is initialized.

Follow the download instructions for the 2.2 .NET Core SDK to install for Windows, macOS, or your Linux distro.

Azure Functions Core Tools

Install version 2 or higher of the Azure Functions Core Tools.

If you are on Windows, you must add %ProgramFiles%\nodejs\node_modules\azure-functions-core-tools\bin (where func.exe is located) to the PATH environment variable.

Installing the Azure Functions for Rust SDK

Install the Azure Functions for Rust SDK using cargo install:

cargo install azure-functions-sdk

This installs a new cargo command named func that can be used to create and run new Azure Functions applications.

Creating a new Azure Functions application

Use the cargo func new-app command to create a new Azure Functions application:

cargo func new-app hello

This will create a new application in the ./hello directory with a module named functions where the exported Azure Functions are expected to be placed.

Adding a simple HTTP-triggered application

Use the cargo func new command to create a new HTTP-triggered Azure Function named hello:

cargo func new http -n hello

The source for the function will be in src/functions/hello.rs.

Building the Azure Functions application

To build your Azure Functions application, just use cargo build:

cargo build

If you are using a nightly compiler, you can enable improved error messages during compilation.

Add the following to your Cargo.toml:

[features]
unstable = ["azure-functions/unstable"]

Build your application:

cargo build --features unstable

This enables Azure Functions for Rust to emit diagnostic messages that will include the position of an error within an attribute.

Building an async Azure Functions application

To build with support for async Azure Functions, add the following to your Cargo.toml:

[dependencies]
futures-preview = "0.3.0-alpha.19"

And then build:

cargo build

Running the Azure Functions application

To build and run your Azure Functions application, use cargo func run:

cargo func run

If you need to enable the unstable feature, pass the --features option to cargo:

cargo func run -- --features unstable

The cargo func run command builds and runs your application locally using the Azure Function Host that was installed by the Azure Functions Core Tools.

By default, the host will be configured to listen on 0.0.0.0:8080.

For the hello function added previously, it can be invoked from http://localhost:8080/api/hello.

Debugging the Azure Functions application

The easiest way to debug the Azure Functions application is to use Visual Studio Code with the CodeLLDB extension.

By default, the Azure Functions for Rust SDK will create a Visual Studio Code launch configuration when you run cargo func new-app.

This will enable a Debug launch configuration that will build and run your application locally before attaching the lldb debugger to the Rust worker process.

Deploying the Azure Functions application

In the future, there will be a cargo func deploy command to deploy the Azure Functions application directly to Azure.

Until that time, you must manually build and push the Docker image to a repository that can be accessed by Azure.

Note: this requires Docker that is at least 18.06 for the experimental BuildKit support.

To enable the BuildKit support, set the DOCKER_BUILDKIT environment variable to 1 before running docker build.

Start by building your image with docker build -t $TAG_NAME .:

docker build -t $TAG_NAME .

Where $TAG_NAME is the tag name to use (e.g. username/my-functions-app).

Use docker push to push the image to a repository that is accessible to Azure Functions.

docker push $TAG_NAME

Create the "Function App (Classic)" in Azure using the "Linux (Preview)" OS. Under the "Publish" setting, select "Docker Image".

From the "Configure Container" section, select the repository and enter the image you pushed.

That's it! Once the Functions App starts in Azure, you should be able to view the functions and run them.

Azure Functions Bindings

Azure Functions supports a wide variety of input and output bindings that can be used by a function.

In a language like C#, parameters can be annotated with attributes describing how the parameters are bound.

Rust does not support attributes on parameters, so the #[binding] attribute is applied on the function with a name that matches the parameter's identifier. The arguments to the attribute depend on the binding type.

The #[func] attribute is used to turn an ordinary Rust function into an Azure Function. It works by examining the parameters and return type to the function and automatically mapping them to corresponding bindings.

The current list of supported bindings:

Rust Type Azure Functions Binding Direction Vec<T>
Blob Input and Ouput Blob in, inout, out No
BlobTrigger Blob Trigger in, inout No
CosmosDbDocument Input and Output Cosmos DB Document in, out Yes
CosmosDbTrigger Cosmos DB Trigger in No
DurableActivityContext Durable Activity Trigger in No
DurableOrchestrationClient Durable Orchestration Client in No
DurableOrchestrationContext Durable Orchestration Trigger in No
EventGridEvent Event Grid Trigger in No
EventHubMessage Event Hub Output Message out Yes
EventHubTrigger Event Hub Trigger in No
GenericInput Generic Input in No
GenericOutput Generic Output out No
GenericTrigger Generic Trigger in No
HttpRequest HTTP Trigger in No
HttpResponse Output HTTP Response out No
QueueMessage Output Queue Message out Yes
QueueTrigger Queue Trigger in No
SendGridMessage SendGrid Email Message out Yes
ServiceBusMessage Service Bus Output Message out Yes
ServiceBusTrigger Service Bus Trigger in No
SignalRConnectionInfo SignalR Connection Info in No
SignalRGroupAction SignalR Group Action out Yes
SignalRMessage SignalR Message out Yes
Table Input and Ouput Table in, out No
TimerInfo Timer Trigger in No
TwilioSmsMessage Twilio SMS Message Output out Yes

More bindings will be implemented in the future, including support for retreiving data from custom bindings.

Bindings in Rust

Azure Functions for Rust automatically infers the direction of bindings depending on how the binding is used in a function's declaration.

Input bindings

Parameters of type T or &T, where T is a trigger or input binding type, are inferred to be bindings with an in direction.

#[func]
...
pub fn example(..., blob: Blob) {
    ...
}
#[func]
...
pub fn example(..., blob: &Blob) {
    ...
}

Additionally, some input binding types support parameters of type Vec<T> and &Vec<T> where T is an input binding type:

#[func]
...
pub fn example(..., documents: Vec<CosmosDbDocument>) {
    ...
}

The following input bindings support parameters of type Vec<T>:

  • CosmosDbDocument

Input-output (inout) bindings

Parameters of type &mut T, where T is a trigger or input binding type that supports the inout direction, are inferred to be bindings with an inout direction.

#[func]
...
pub fn example(..., blob: &mut Blob) {
    ...
}

Note: inout direction bindings are currently not implemented for languages other than C#.

See this issue regarding this problem with the Azure Functions Host.

Output bindings

Functions that return a type T, where T is an output binding type, or a tuple of output binding types, are inferred to be bindings with an out direction.

#[func]
...
pub fn example(...) -> Blob {
    ...
}

Functions may also return Option<T> for any output binding type T; a None value will skip outputting a value.

#[func]
...
pub fn example(...) -> Option<Blob> {
    ...
}
#[func]
...
pub fn example(...) -> (HttpResponse, Option<Blob>) {
    ...
}

Additionally, some output binding types support returning Vec<T> where T is an output binding type:

#[func]
...
pub fn example(...) -> Vec<CosmosDbDocument>) {
    ...
}

The following output bindings support returning type Vec<T>:

  • CosmosDbDocument
  • EventHubMessage
  • QueueMessage
  • SendGridMessage
  • ServiceBusMessage
  • SignalRGroupAction
  • SignalRMessage
  • TwilioSmsMessage

For functions that return a single output binding type, the binding has a special name of $return and is treated as the return value of the function.

For functions that return a tuple of output binding types, the first value of the tuple has the binding name of $return and is treated as the return value of the function. The remaining values have binding names output1, output2, ..., output(N-1) where N is the number of types in the tuple, and are treated as output bindings only.

Unit tuples () can be used in a tuple to "skip" a binding:

#[func]
...
pub fn example(...) -> ((), Blob) {
    ...
}

For the above example, there is no $return binding and the Azure Function "returns" no value. Instead, a single output binding named output1 is used.

Contributors

Thanks goes to these wonderful people (emoji key):


Peter Huene

💻 🐛 📖 🤔 🚇 🚧 📦 👀 ⚠️

Ryan Levick

💻 🤔 🚧 👀 🚇

Thomas Eckert

💻 🖋 🎨 📖 🤔 🚇 🚧 👀

R. Tyler Croy

💻 📖 👀 🤔

Denis Molokanov

💻 ⚠️ 🎨 🤔

Scott Lyons

💻 ⚠️ 🎨 🤔

Rohan Prinja

💻

Christian Brevik

🐛 💻

Danny Browning

💻 🚧

This project follows the all-contributors specification. Contributions of any kind welcome!