Azure Functions is functions runtime that is able to launch a function created by multiple language, as serverless on cloud (see Microsoft Docs [Supported languages in Azure Functions]). What it is serverless means less code, less maintainance of infrastructure, thus developers are able to focus on code for only business process, managers can save on costs as result. Furthermore, when procuring members of some project as using microservices architecture, managers can orchestrate several teams of various language programmers.
In this article, create simple rust program that can run on local environment for that will deploy to Azure Functions later.
In the article [How to compile Rust assembly runnable on Linux for deployment to Azure Functions] describes creation of assembly to deploy Azure Functions.
In the article [Rust QR code generator App of Azure Functions] describes how to modify the simple of this article (simple rust project) to QR code generator.

Added at 9th Feb. 2022 :
Please read Microsoft Docs [Work with Azure Functions Core Tools] and install it, you can execute command [func start] on console (or tarminal of Visual Studio code, Windows and so on.) when restart PC.

>>Sample project of Rust language to create QR Code

・Azure Functions Visual Studio Code Extensions

This article uses Visual Studio Code and it’s extensions and Rust (see Install Rust).

For debugging on local development environment and upload to Azure Functions, it needs Azure Functions Core Tools. This tool installed along with other tools of Azure if install Azure Tools Extension (left figure), or if aim to just install Azure Functions extension, install individual(right figure).

・Create local Rust project for Azure Functions

It is super easy to create Rust project that run on Windows using Visual Studio Code extension of Azure Functions.

At first, open work folder in Visual Studio Code. Work folder is able to create using the [Open Folder] dialog box. Select the [Open folder…] of the [File] menu, then right click on any directory and select the [New] then select the [Folder] (Left figure).

While open work folder, create Rust project using extension of Azure Functions. Select the [Create New Project…] icon of the [FUNCTIONS] area of the [Azure] extension. (Right figure)

[Command Palette] is shown when select [Create New Project…] icon. there are several steps to create new project, exclude step of ‘Function name’ (This setting is used for URL of Functions) and step of ‘Folder of the project’, put values of table below. These values are for sample project.

Folder of the project
QRCodeGeneratorOnAzureFunctions(default : Opened folder from Visual Studio Code. This setting make URL of Azure Functions to figure below)
Language
Custom Handler(default : Last used, If first Azure Functions function creation, select this.)
Project template
Http trigger(default : Last used, If first Azure Functions function creation, select this.)
Function name
BlogSampleFunctions(This setting create URL : https://blogsamplefunctions.azurewebsites.net/api/QRCodeGeneratorOnAzureFunctions)
Authorization
Anonymous(default : no authentication)

Return to the [File Explorer], and type [Ctrl] + [Shift] + [`] key for open the [Integrated terminal] (use [Ctrl] + [K] + [S] for comfirming conbination of keys for your keybord type). Then type [ cargo init –name qrcode_generator ] on the [Integrated terminal] to create Rust project package (this name value is not relate a name of Azure Functions). After package creation, type [ cargo run ] to run project. It is OK that it shows [ Hello, world! ] in the [Integrated terminal].

This Rust project package name [qrcode_generator] is same name as Rust assembly file name (and the [exe] extension), so the [cargo run] command create assembly file at [%project root%\target\debug\qrcode_generator.exe] and launch the file. And this value is defined at the [name] value of [package] definition in the [Cargo.toml] file.

[ cargo init ] comand generates rust project files such as the [src/main.rs] file and the [Cargo.toml] file and so on, the [src/main.rs] file is startup file, so [ cargo run ] command executes [ println!(“Hello, world!”) ] statement of the [src/main.rs] file (see figure below).

・Create web server

Create sample projest with modifying [src/main.rs] file that the [ cargo init ] comand generated.

TCP listener is standard function of Rust, although HTTP lisner have to process asyncronous task flow. asyncronous feature is provided with async_std or tokio and so on.

This article select tokio and warp as sample because there is popular and there are a lot of code samples on web. warp is web server framework.

Since warp is for creation of web server, it can listen HTTP request from Azure Functions as HTTP listener. If the setting of Azure Functions environment (host.json at root of project, figure below) to enable forwarding HTTP request, Azure Functions accepts Http request and throw it to the function of Azure Functions that served by warp.

--host.json file (part of the file)
...
  "customHandler": {
    "description": {
      "defaultExecutablePath": "qrcode_generator.exe",
      "workingDirectory": "",
      "arguments": []
    },
    //here is the setting (All figure of host.json is shown later)
    "enableForwardingHttpRequest": true
  }
}

At first, modify the [Cargo.toml] file as below to use these eco-systems. And define to use them at main.rs of the [src] folder.

--Cargo.toml file
[dependencies]
warp = "0.3"
tokio = { version = "1", features = ["rt", "macros", "rt-multi-thread"] }

--src/main.rs file
use std::env;
use std::collections::HashMap;
use std::net::Ipv4Addr;
use warp::{http::Response, Filter};

fn main() {
    println!("Hello, world!");
}

These defines are used as table below.

std::env
Acquire port number that Azure Functions provided.
std::collections::HashMap
Acquire query string of HTTP request.
std::net::Ipv4Addr
Acquire IPv4 address of HTTP request.
warp::{http::Response, Filter}
Create HTTP response, and serve function that defines process of create response.

Next, acquire port number of incomming stream (distination port number of the stream Azure Functions forwards) using definitioned term (FUNCTIONS_CUSTOMHANDLER_PORT).

fn main() {
    let port: u16 = match env::var("FUNCTIONS_CUSTOMHANDLER_PORT") {
        Ok(val) => val.parse().expect("Custom Handler port is not a number!"),
        Err(_) => 3000,
    };
    ...
}

Continues, creating respond in case when HTTP GET message listened. Sample code for POST message is described in the article [How to compile Rust assembly runnable on Linux for deployment to Azure Functions].

async fn main() {
    ...
    let get_source
        = warp::path!("api" / "QRCodeGeneratorOnAzureFunctions")
        .and(warp::query::>())
        .map(|q:HashMap|
            match q.get("source") {
                Some(s) => Response::builder().body(format!("QR Code source [{}]",s)),
                None => Response::builder().body(String::from("Source does not requested"))
            });
    ...
}
ⓘ As additional information

Azure Functions provides global URL as format below (as default).

https://%Function name%.azurewebsites.net/api/%Folder name of project root%

So listening HTTP request use [ warp::path!(“api” / “QRCodeGeneratorOnAzureFunctions”) ] statement. If want to omit path [api], modify host.json as below.

–host.json file (root parameter [extensions], All figure of host.json is shown later)
“extensions”: {“http”: {“routePrefix”: “”}}

At last, create listening part of HTTP GET message. Below is all code of the [src/main.rs] file.

use std::env;
use std::collections::HashMap;
use std::net::Ipv4Addr;
use warp::{http::{Response}, Filter};

#[tokio::main]
async fn main() {
    let port: u16 = match env::var("FUNCTIONS_CUSTOMHANDLER_PORT") {
        Ok(val) => val.parse().expect("Custom Handler port is not a number!"),
        Err(_) => 3000,
    };
    let get_source
        = warp::path!("QRCodeGeneratorOnAzureFunctions")
        .and(warp::query::>())
        .map(|q:HashMap|
            match q.get("source") {
                Some(s) => Response::builder().body(format!("QR Code source [{}]",s)),
                None => Response::builder().body(String::from("Source does not requested"))
            });
    let routes = warp::get().and(get_source);
    warp::serve(routes).run((Ipv4Addr::UNSPECIFIED, port)).await
}

・Run on local

Azure Functions Core Tools has web hosting feature, so build Rust project at first, then define builded assembly path to this tool. Build path is [target/relese] folder that are created when type [cargo build –release] command in the [Integrated terminal]. This tool use execute file at project root folder to host client or upload to Azure Functions. So copy the file from build path to project root.

cp .\target\release\qrcode_generator.exe

This tool hosts the Rust assembly file use [defaultExecutablePath] value in [host.json], the value is defined at description property of customHandler property in the file.

ⓘ As additional information (8th Feb. 2022)

The ‘extensionBundle’ values of [%Project root%\host.json] file makes Azure Function project enable runable the project of other language that .NET runtime does not support.

Type [ func start ] command in the [Integrated terminal] after put value [qrcode_generator.exe] in the [description] property of the[customHandler] property in this file.

Termination is type [Ctrl] + [C] key at terminal.

Next >>How to compile Rust assembly runnable on Linux for deployment to Azure Functions

Tags:

No responses yet

Leave a Reply

Your email address will not be published. Required fields are marked *