Implement a Rust worker that supports an unmodified host.
This commit changes the CLI for the Rust worker to support an unmodified Azure Functions Host. Additionally, documentation has been updated. A Dockerfile has been added to easily build Docker images for the examples so they can be deployed to Azure.
This commit is contained in:
parent
418eda3b2e
commit
5715ffd4a9
|
@ -0,0 +1,4 @@
|
|||
target/
|
||||
Cargo.lock
|
||||
.vscode/
|
||||
.git/
|
|
@ -9,7 +9,4 @@ Cargo.lock
|
|||
# These are backup files generated by rustfmt
|
||||
**/*.rs.bk
|
||||
|
||||
# Example generated script root directories
|
||||
examples/**/root
|
||||
|
||||
.vscode/
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
FROM peterhuene/azure-functions-rs-ci:latest AS build-env
|
||||
|
||||
COPY . /src
|
||||
|
||||
ARG EXAMPLE
|
||||
|
||||
RUN if [ -z "$EXAMPLE" ]; then echo "The EXAMPLE argument is required."; exit 1; fi \
|
||||
&& cd /src/examples/$EXAMPLE \
|
||||
&& cargo run --release -- init --worker-path /usr/local/bin/rust_worker --script-root /home/site/wwwroot
|
||||
|
||||
FROM microsoft/azure-functions-dotnet-core2.0:dev-nightly
|
||||
|
||||
COPY --from=build-env ["/usr/local/bin/rust_worker", "/usr/local/bin/rust_worker"]
|
||||
COPY --from=build-env ["/home/site/wwwroot", "/home/site/wwwroot"]
|
||||
COPY --from=build-env ["/src/azure-functions/worker.config.json", "/azure-functions-host/workers/rust/worker.config.json"]
|
63
README.md
63
README.md
|
@ -10,7 +10,7 @@ in [Rust](https://www.rust-lang.org/en-US/).
|
|||
|
||||
## Disclaimer
|
||||
|
||||
Althougth the maintainer of this repository is a Microsoft employee, this project is not an official Microsoft product
|
||||
Although the maintainer of this repository is a Microsoft employee, this project is not an official Microsoft product
|
||||
and is not an endorsement of any future product offering from Microsoft.
|
||||
|
||||
This project is simply a labor of love by a developer who would like to see the Rust ecosystem flourish.
|
||||
|
@ -57,9 +57,9 @@ The current list of supported bindings:
|
|||
| Rust Type | Azure Functions Binding |
|
||||
|-------------------------------------------|-------------------------|
|
||||
| `azure_functions::bindings::HttpRequest` | HTTP Trigger |
|
||||
| `azure_functions::bindings::HttpResponse` | HTTP Output |
|
||||
| `azure_functions::bindings::QueueMessage` | Output Queue Message |
|
||||
| `azure_functions::bindings::HttpResponse` | Output HTTP Response |
|
||||
| `azure_functions::bindings::QueueTrigger` | Queue Trigger |
|
||||
| `azure_functions::bindings::QueueMessage` | Output Queue Message |
|
||||
| `azure_functions::bindings::TimerInfo` | Timer Trigger |
|
||||
| `azure_functions::Context`* | Invocation Context |
|
||||
|
||||
|
@ -88,8 +88,7 @@ This repository is split into multiple Rust crates:
|
|||
* [azure-functions-shared](https://github.com/peterhuene/azure-functions-rs/tree/master/azure-functions-shared) - The `azure-functions-shared` crate that defines types and functions that are shared between the `azure-functions-codegen` and `azure-functions` crates.
|
||||
* Note: the `azure-functions-shared/protobuf` directory is the git submodule for [Azure Functions Language Worker Protocol](https://github.com/Azure/azure-functions-language-worker-protobuf).
|
||||
* [azure-functions-shared-codegen](https://github.com/peterhuene/azure-functions-rs/tree/master/azure-functions-shared-codegen) - The `azure-functions-shared-codegen` crate that defines the procedural macros used by the shared `azure-functions-shared` crate.
|
||||
* [examples/http](https://github.com/peterhuene/azure-functions-rs/tree/master/examples/http) - An example of an HTTP-triggered function.
|
||||
* [examples/timer](https://github.com/peterhuene/azure-functions-rs/tree/master/examples/timer) - An example of a timer-triggered function.
|
||||
* [examples](https://github.com/peterhuene/azure-functions-rs/tree/master/examples) - The directory containing example Azure Functions.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
|
@ -127,3 +126,57 @@ cargo test
|
|||
```
|
||||
|
||||
Right now there are only doc tests, but more tests are coming soon.
|
||||
|
||||
## Deploying to Azure Functions
|
||||
|
||||
Deploying to Azure Functions is best accomplished with a Docker image for your Rust Azure Functions application.
|
||||
|
||||
Copy this content to a `Dockerfile` at the root of your source:
|
||||
|
||||
```docker
|
||||
FROM peterhuene/azure-functions-rs-ci:latest AS build-env
|
||||
|
||||
COPY . /src
|
||||
|
||||
RUN cargo run --release -- init --worker-path /usr/local/bin/rust_worker --script-root /home/site/wwwroot
|
||||
|
||||
FROM microsoft/azure-functions-dotnet-core2.0:dev-nightly
|
||||
|
||||
COPY --from=build-env ["/usr/local/bin/rust_worker", "/usr/local/bin/rust_worker"]
|
||||
COPY --from=build-env ["/home/site/wwwroot", "/home/site/wwwroot"]
|
||||
|
||||
RUN mkdir /azure-functions-host/workers/rust \
|
||||
&& curl https://gist.githubusercontent.com/peterhuene/00ba85ed18bb42437355f63829f2471e/raw/9d29d3b8eaf01e1d2d44e7df2a569a9730fbafa3/worker.config.json > /azure-functions-host/workers/rust/worker.config.json
|
||||
```
|
||||
|
||||
Add a `.dockerignore` at the root of your source with the following contents:
|
||||
|
||||
```
|
||||
target/
|
||||
Cargo.lock
|
||||
.vscode/
|
||||
.git/
|
||||
```
|
||||
|
||||
Build the Docker image:
|
||||
|
||||
```
|
||||
docker build -t $IMAGE:latest .
|
||||
```
|
||||
|
||||
Where `$IMAGE` is the name of the tag for the image (e.g. `peterhuene/azure-functions-rs-example`).
|
||||
|
||||
Push the image to a repository:
|
||||
|
||||
```
|
||||
docker push $IMAGE
|
||||
```
|
||||
|
||||
Create the Function App in [Azure](https://portal.azure.com) using the Docker "OS", specifying the image that was pushed:
|
||||
|
||||
![Azure Portal](docs/images/create-function-app.png)
|
||||
|
||||
Add a new setting for `WEBSITES_ENABLE_APP_SERVICE_STORAGE` under `Application Settings` and set it to `false`.
|
||||
This will enable the Docker image itself to provide the service storage (i.e. script root and worker).
|
||||
|
||||
Finally, restart the Function App. After the application has initialized again, your Rust Azure Functions should be displayed in the Azure Portal.
|
||||
|
|
|
@ -1,149 +1,71 @@
|
|||
use clap::{App, Arg};
|
||||
use registry::Registry;
|
||||
use serde::Serialize;
|
||||
use serde_json::Serializer;
|
||||
use std::env::{current_dir, current_exe};
|
||||
use std::fs;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use clap::{App, Arg, SubCommand};
|
||||
|
||||
pub fn create_app<'a, 'b>() -> App<'a, 'b> {
|
||||
App::new("Azure Functions Language Worker for Rust")
|
||||
.version(env!("CARGO_PKG_VERSION"))
|
||||
.about("Provides an Azure Functions Worker for functions written in Rust.")
|
||||
.arg(
|
||||
Arg::with_name("host")
|
||||
.long("host")
|
||||
.value_name("HOST")
|
||||
.help("The hostname of the Azure Functions Host.")
|
||||
.conflicts_with("create")
|
||||
.required_unless("create"),
|
||||
.subcommand(
|
||||
SubCommand::with_name("init")
|
||||
.about("Initializes the Rust language worker and script root.")
|
||||
.arg(
|
||||
Arg::with_name("worker_path")
|
||||
.long("worker-path")
|
||||
.value_name("WORKER_PATH")
|
||||
.help("The path to place the Rust language worker.")
|
||||
.required(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("script_root")
|
||||
.long("script-root")
|
||||
.value_name("SCRIPT_ROOT")
|
||||
.help("The directory to create the script root.")
|
||||
.required(true),
|
||||
)
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("port")
|
||||
.long("port")
|
||||
.value_name("PORT")
|
||||
.help("The port of the Azure Functions Host.")
|
||||
.conflicts_with("create")
|
||||
.required_unless("create"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("worker_id")
|
||||
.long("workerId")
|
||||
.value_name("WORKER_ID")
|
||||
.help("The worker ID to use when registering with the Azure Functions Host.")
|
||||
.conflicts_with("create")
|
||||
.required_unless("create"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("request_id")
|
||||
.long("requestId")
|
||||
.value_name("REQUEST_ID")
|
||||
.help("The request ID to use when communicating with the Azure Functions Host.")
|
||||
.hidden(true)
|
||||
.conflicts_with("create")
|
||||
.required_unless("create"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("max_message_length")
|
||||
.long("grpcMaxMessageLength")
|
||||
.value_name("MAXIMUM")
|
||||
.help("The maximum message length to use for gRPC messages.")
|
||||
.conflicts_with("create")
|
||||
.required_unless("create"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("create")
|
||||
.long("create")
|
||||
.value_name("APP_ROOT")
|
||||
.help("Creates the Azure Functions App at the given root directory.\nCannot be used with other options."),
|
||||
.subcommand(
|
||||
SubCommand::with_name("run")
|
||||
.about("Runs the Rust language worker.")
|
||||
.arg(
|
||||
Arg::with_name("worker_config")
|
||||
.value_name("WORKER_CONFIG")
|
||||
.help("The path to the Rust worker configuration file.")
|
||||
.required(false)
|
||||
.index(1)
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("host")
|
||||
.long("host")
|
||||
.value_name("HOST")
|
||||
.help("The hostname of the Azure Functions Host.")
|
||||
.required(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("port")
|
||||
.long("port")
|
||||
.value_name("PORT")
|
||||
.help("The port of the Azure Functions Host.")
|
||||
.required(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("worker_id")
|
||||
.long("workerId")
|
||||
.value_name("WORKER_ID")
|
||||
.help("The worker ID to use when registering with the Azure Functions Host.")
|
||||
.required(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("request_id")
|
||||
.long("requestId")
|
||||
.value_name("REQUEST_ID")
|
||||
.help("The request ID to use when communicating with the Azure Functions Host.")
|
||||
.hidden(true)
|
||||
.required(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("max_message_length")
|
||||
.long("grpcMaxMessageLength")
|
||||
.value_name("MAXIMUM")
|
||||
.help("The maximum message length to use for gRPC messages.")
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
pub fn generate_functions_app(root: &str, registry: Arc<Mutex<Registry>>) {
|
||||
const FUNCTION_FILE: &'static str = "function.json";
|
||||
const RUST_SCRIPT_FILE: &'static str = "run.rs";
|
||||
|
||||
let root = current_dir()
|
||||
.expect("failed to get current directory")
|
||||
.join(root);
|
||||
|
||||
if root.exists() {
|
||||
println!(
|
||||
"Using existing Azure Functions application at '{}'.",
|
||||
root.display()
|
||||
);
|
||||
} else {
|
||||
println!(
|
||||
"Creating Azure Functions application at '{}'.",
|
||||
root.display()
|
||||
);
|
||||
|
||||
fs::create_dir_all(&root).expect(&format!(
|
||||
"Failed to create Azure Functions application directory '{}'",
|
||||
root.display()
|
||||
));
|
||||
}
|
||||
|
||||
let host_json = root.join("host.json");
|
||||
if !host_json.exists() {
|
||||
println!(
|
||||
"Creating empty host configuration file '{}'.",
|
||||
host_json.display()
|
||||
);
|
||||
fs::write(&host_json, "{}").expect(&format!("Failed to create '{}'", host_json.display()));
|
||||
}
|
||||
|
||||
println!("Copying current worker executable.");
|
||||
fs::copy(
|
||||
current_exe().expect("Failed to determine the path to the current executable"),
|
||||
root.join("rust_worker"),
|
||||
).expect("Failed to copy worker executable");
|
||||
|
||||
for entry in fs::read_dir(&root).expect("failed to read script root directory") {
|
||||
let path = root.join(entry.expect("failed to read script root entry").path());
|
||||
if !path.is_dir() || !path.join(RUST_SCRIPT_FILE).exists() {
|
||||
continue;
|
||||
}
|
||||
|
||||
println!("Deleting existing function directory '{}'.", path.display());
|
||||
|
||||
fs::remove_dir_all(&path).expect(&format!(
|
||||
"Failed to delete function directory '{}",
|
||||
path.display()
|
||||
));
|
||||
}
|
||||
|
||||
for (name, info) in registry.lock().unwrap().iter() {
|
||||
let function_dir = root.join(name);
|
||||
fs::create_dir(&function_dir).expect(&format!(
|
||||
"Failed to create function directory '{}'",
|
||||
function_dir.display()
|
||||
));
|
||||
|
||||
let script_file = function_dir.join(RUST_SCRIPT_FILE);
|
||||
println!(
|
||||
"Creating script file '{}' for Azure Function '{}'.",
|
||||
script_file.display(),
|
||||
name
|
||||
);
|
||||
fs::write(
|
||||
&script_file,
|
||||
"// This file is intentionally empty.\n// It is needed by the Azure Functions Host to register the Azure Function."
|
||||
).expect(&format!("Failed to create '{}'", script_file.display()));
|
||||
|
||||
let function_json = function_dir.join(FUNCTION_FILE);
|
||||
println!(
|
||||
"Creating function configuration file '{}' for Azure Function '{}'.",
|
||||
function_json.display(),
|
||||
name
|
||||
);
|
||||
|
||||
let mut output = fs::File::create(&function_json)
|
||||
.expect(&format!("Failed to create '{}'", function_json.display()));
|
||||
info.serialize(&mut Serializer::pretty(&mut output))
|
||||
.expect(&format!(
|
||||
"Failed to serialize metadata for function '{}'",
|
||||
name
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
//! The following Azure Functions trigger bindings are supported:
|
||||
//!
|
||||
//! * [HTTP triggers](bindings/struct.HttpRequest.html)
|
||||
//! * [Timer triggers](bindings/struct.TimerInfo.html)
|
||||
//! * [Queue triggers](bindings/struct.QueueTrigger.html)
|
||||
//! * [Timer triggers](bindings/struct.TimerInfo.html)
|
||||
//!
|
||||
//! The following Azure Functions output bindings are supported:
|
||||
//!
|
||||
|
@ -30,10 +30,9 @@
|
|||
//! log = "0.4.2"
|
||||
//! ```
|
||||
//!
|
||||
//! Azure Functions are implemented by applying a trigger attribute to a Rust function.
|
||||
//! Azure Functions are implemented by applying a `#[func]` attribute to a Rust function.
|
||||
//!
|
||||
//! For example, let's create `src/greet.rs` that implements a HTTP triggered function by
|
||||
//! applying the `func` attribute:
|
||||
//! For example, let's create `src/greet.rs` that implements a HTTP triggered function:
|
||||
//!
|
||||
//! ```rust
|
||||
//! # #![feature(use_extern_macros)] extern crate azure_functions;
|
||||
|
@ -74,19 +73,19 @@
|
|||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! Run the application with the `--create <root>` option, where `<root>` is the path to
|
||||
//! the desired Azure Functions application root directory:
|
||||
//! Initialize the application with the `init` command, where `$AzureWebJobsScriptRoot` is
|
||||
//! the desired Azure Functions script root directory:
|
||||
//!
|
||||
//! ```bash
|
||||
//! $ export AzureWebJobsScriptRoot=path-to-root
|
||||
//! $ cargo run -q -- --create $AzureWebJobsScriptRoot
|
||||
//! $ cargo run -q -- init --worker-path /tmp/example/rust_worker --script-root /tmp/example/root
|
||||
//! ```
|
||||
//!
|
||||
//! Run the Azure Functions Host:
|
||||
//! Run the [Azure Functions Host](https://github.com/azure/azure-functions-host):
|
||||
//!
|
||||
//! ```bash
|
||||
//! $ cd azure-functions-host/src/WebJobs.Script.WebHost
|
||||
//! $ dotnet run
|
||||
//! $ PATH=/tmp/example:$PATH AzureWebJobsScriptRoot=/tmp/example/root dotnet run
|
||||
//! ```
|
||||
//!
|
||||
//! The above Azure Function can be invoked with `http://localhost:5000/api/greet?name=John`.
|
||||
|
@ -135,33 +134,118 @@ pub use azure_functions_shared::Context;
|
|||
|
||||
use futures::Future;
|
||||
use registry::Registry;
|
||||
use serde::Serialize;
|
||||
use serde_json::Serializer;
|
||||
use std::env::{current_dir, current_exe};
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn worker_main(args: impl Iterator<Item = String>, functions: &[&'static codegen::Function]) {
|
||||
let matches = cli::create_app().get_matches_from(args);
|
||||
let registry = Arc::new(Mutex::new(Registry::new(functions)));
|
||||
fn initialize_app(worker_path: &str, script_root: &str, registry: Arc<Mutex<Registry>>) {
|
||||
const FUNCTION_FILE: &'static str = "function.json";
|
||||
const RUST_SCRIPT_FILE: &'static str = "run.rs";
|
||||
|
||||
if let Some(root) = matches.value_of("create") {
|
||||
cli::generate_functions_app(root, registry);
|
||||
return;
|
||||
let script_root = current_dir()
|
||||
.expect("failed to get current directory")
|
||||
.join(script_root);
|
||||
|
||||
if script_root.exists() {
|
||||
println!(
|
||||
"Using existing Azure Functions application at '{}'.",
|
||||
script_root.display()
|
||||
);
|
||||
} else {
|
||||
println!(
|
||||
"Creating Azure Functions application at '{}'.",
|
||||
script_root.display()
|
||||
);
|
||||
|
||||
fs::create_dir_all(&script_root).expect(&format!(
|
||||
"Failed to create Azure Functions application directory '{}'",
|
||||
script_root.display()
|
||||
));
|
||||
}
|
||||
|
||||
let client = rpc::Client::new(
|
||||
matches
|
||||
.value_of("worker_id")
|
||||
.expect("A worker id is required.")
|
||||
.to_owned(),
|
||||
matches
|
||||
.value_of("max_message_length")
|
||||
.map(|len| len.parse::<i32>().expect("Invalid maximum message length")),
|
||||
);
|
||||
let host_json = script_root.join("host.json");
|
||||
if !host_json.exists() {
|
||||
println!(
|
||||
"Creating empty host configuration file '{}'.",
|
||||
host_json.display()
|
||||
);
|
||||
fs::write(&host_json, "{}").expect(&format!("Failed to create '{}'", host_json.display()));
|
||||
}
|
||||
|
||||
let host = matches.value_of("host").expect("A host is required.");
|
||||
let port = matches
|
||||
.value_of("port")
|
||||
.map(|port| port.parse::<u32>().expect("Invalid port number"))
|
||||
.expect("Port number is required.");
|
||||
let worker_dir = Path::new(worker_path)
|
||||
.parent()
|
||||
.expect("expected to get a parent of the worker path");
|
||||
fs::create_dir_all(&worker_dir).expect(&format!(
|
||||
"Failed to create directory for worker executable '{}'",
|
||||
worker_dir.display()
|
||||
));
|
||||
|
||||
println!("Copying current worker executable to '{}'.", worker_path);
|
||||
fs::copy(
|
||||
current_exe().expect("Failed to determine the path to the current executable"),
|
||||
worker_path,
|
||||
).expect("Failed to copy worker executable");
|
||||
|
||||
for entry in fs::read_dir(&script_root).expect("failed to read script root directory") {
|
||||
let path = script_root.join(entry.expect("failed to read script root entry").path());
|
||||
if !path.is_dir() || !path.join(RUST_SCRIPT_FILE).exists() {
|
||||
continue;
|
||||
}
|
||||
|
||||
println!("Deleting existing function directory '{}'.", path.display());
|
||||
|
||||
fs::remove_dir_all(&path).expect(&format!(
|
||||
"Failed to delete function directory '{}",
|
||||
path.display()
|
||||
));
|
||||
}
|
||||
|
||||
for (name, info) in registry.lock().unwrap().iter() {
|
||||
let function_dir = script_root.join(name);
|
||||
fs::create_dir(&function_dir).expect(&format!(
|
||||
"Failed to create function directory '{}'",
|
||||
function_dir.display()
|
||||
));
|
||||
|
||||
let script_file = function_dir.join(RUST_SCRIPT_FILE);
|
||||
println!(
|
||||
"Creating script file '{}' for Azure Function '{}'.",
|
||||
script_file.display(),
|
||||
name
|
||||
);
|
||||
fs::write(
|
||||
&script_file,
|
||||
"// This file is intentionally empty.\n// It is needed by the Azure Functions Host to register the Azure Function."
|
||||
).expect(&format!("Failed to create '{}'", script_file.display()));
|
||||
|
||||
let function_json = function_dir.join(FUNCTION_FILE);
|
||||
println!(
|
||||
"Creating function configuration file '{}' for Azure Function '{}'.",
|
||||
function_json.display(),
|
||||
name
|
||||
);
|
||||
|
||||
let mut output = fs::File::create(&function_json)
|
||||
.expect(&format!("Failed to create '{}'", function_json.display()));
|
||||
info.serialize(&mut Serializer::pretty(&mut output))
|
||||
.expect(&format!(
|
||||
"Failed to serialize metadata for function '{}'",
|
||||
name
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
fn run_worker<'a>(
|
||||
worker_id: &str,
|
||||
host: &str,
|
||||
port: u32,
|
||||
max_message_length: Option<i32>,
|
||||
registry: Arc<Mutex<Registry>>,
|
||||
) {
|
||||
let client = rpc::Client::new(worker_id.to_string(), max_message_length);
|
||||
|
||||
println!("Connecting to Azure Functions host at {}:{}.", host, port);
|
||||
|
||||
|
@ -178,3 +262,43 @@ pub fn worker_main(args: impl Iterator<Item = String>, functions: &[&'static cod
|
|||
.wait()
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn worker_main(args: impl Iterator<Item = String>, functions: &[&'static codegen::Function]) {
|
||||
let matches = cli::create_app().get_matches_from(args);
|
||||
let registry = Arc::new(Mutex::new(Registry::new(functions)));
|
||||
|
||||
if let Some(matches) = matches.subcommand_matches("init") {
|
||||
initialize_app(
|
||||
matches
|
||||
.value_of("worker_path")
|
||||
.expect("A binary path is required."),
|
||||
matches
|
||||
.value_of("script_root")
|
||||
.expect("A script root is required."),
|
||||
registry,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(matches) = matches.subcommand_matches("run") {
|
||||
run_worker(
|
||||
matches
|
||||
.value_of("worker_id")
|
||||
.expect("A worker id is required."),
|
||||
matches.value_of("host").expect("A host is required."),
|
||||
matches
|
||||
.value_of("port")
|
||||
.map(|port| port.parse::<u32>().expect("Invalid port number"))
|
||||
.expect("A port number is required."),
|
||||
matches
|
||||
.value_of("max_message_length")
|
||||
.map(|len| len.parse::<i32>().expect("Invalid maximum message length")),
|
||||
registry,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
cli::create_app().print_help().unwrap();
|
||||
println!();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"Description":{
|
||||
"Language": "Rust",
|
||||
"Extension": ".rs",
|
||||
"DefaultExecutablePath": "rust_worker",
|
||||
"DefaultWorkerPath": "worker.config.json",
|
||||
"Arguments": ["run"]
|
||||
}
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 209 KiB |
|
@ -6,4 +6,4 @@ authors = ["Peter Huene <peterhuene@protonmail.com>"]
|
|||
[dependencies]
|
||||
azure-functions = { version = "0.1.4", path = "../../azure-functions" }
|
||||
log = "0.4.2"
|
||||
serde_json = "1.0.21"
|
||||
serde_json = "1.0.21"
|
||||
|
|
|
@ -4,7 +4,7 @@ This package is an example of a simple HTTP-triggered Azure Function.
|
|||
|
||||
## Example function implementation
|
||||
|
||||
The example anonymous, HTTP-triggered Azure Function:
|
||||
The example HTTP-triggered Azure Function:
|
||||
|
||||
```rust
|
||||
use azure_functions::bindings::{HttpRequest, HttpResponse};
|
||||
|
@ -22,7 +22,7 @@ pub fn greet(context: &Context, req: &HttpRequest) -> HttpResponse {
|
|||
}
|
||||
```
|
||||
|
||||
# Running the example
|
||||
# Running the example locally
|
||||
|
||||
## Prerequisites
|
||||
|
||||
|
@ -41,27 +41,40 @@ rustup default nightly
|
|||
|
||||
The Azure Functions Host is implemented with .NET Core, so download and install a [.NET Core SDK](https://www.microsoft.com/net/download).
|
||||
|
||||
### Custom fork of Azure Functions Host
|
||||
### Azure Functions Host
|
||||
|
||||
Currently, the Azure Functions Host does not support the Rust language worker. Until that time, Azure Functions written in Rust must be executed locally using a [fork of the Azure Functions Host that does](https://github.com/peterhuene/azure-functions-host/tree/rust-worker-provider).
|
||||
|
||||
Run the following command to clone the fork:
|
||||
Clone the Azure Functions Host from GitHub:
|
||||
|
||||
```
|
||||
git clone -b rust-worker-provider git@github.com:peterhuene/azure-functions-host.git
|
||||
git clone git@github.com:azure/azure-functions-host.git
|
||||
```
|
||||
|
||||
## Create the script root
|
||||
|
||||
Run the following command to create the "script root" for the example:
|
||||
Use `dotnet` to build the Azure Functions Host:
|
||||
|
||||
```
|
||||
cargo run -q -- --create root
|
||||
cd azure-functions-host/src/WebJobs.Script.WebHost
|
||||
dotnet build
|
||||
```
|
||||
|
||||
This will build and run the sample to create the "script root" containing the Rust worker and the example Azure Function metadata.
|
||||
## Register the Rust language worker
|
||||
|
||||
Remember the path to the root directory from this step as it will be needed for running the Azure Functions Host below.
|
||||
The Azure Functions Host uses JSON configuration files to register language workers.
|
||||
|
||||
Create the configuration file to register the Rust language worker:
|
||||
|
||||
```
|
||||
mkdir azure-functions-host/src/WebJobs.Script.WebHost/bin/Debug/netcoreapp2.1/workers/rust
|
||||
cp azure-functions-rs/azure-functions/worker.config.json azure-functions-host/src/WebJobs.Script.WebHost/bin/Debug/netcoreapp2.1/workers/rust
|
||||
```
|
||||
|
||||
## Initialize the example application
|
||||
|
||||
Run the following command to build and initialize the Rust Azure Functions application:
|
||||
|
||||
```
|
||||
cd azure-functions-rs/examples/http
|
||||
cargo run --release -- init --worker-path /tmp/http-example/rust_worker --script-root /tmp/http-example/root
|
||||
```
|
||||
|
||||
## Start the Azure Functions Host
|
||||
|
||||
|
@ -69,15 +82,11 @@ Run the following commands to start the Azure Functions Host:
|
|||
|
||||
```
|
||||
cd azure-functions-host/src/WebJobs.Script.WebHost
|
||||
AzureWebJobsScriptRoot=$SCRIPT_ROOT_PATH dotnet run
|
||||
PATH=/tmp/http-example:$PATH AzureWebJobsScriptRoot=/tmp/http-example/root dotnet run
|
||||
```
|
||||
|
||||
Where `$SCRIPT_ROOT_PATH` above represents the path to the root directory created from running `cargo run` above.
|
||||
|
||||
_Note: the syntax above works on macOS and Linux; on Windows, set the `AzureWebJobsScriptRoot` environment variable before running `dotnet run`._
|
||||
|
||||
_Note: if using bindings that require storage (such as timer triggers), you must set the `AzureWebJobsStorage` environment variable to an Azure Storage connection string._
|
||||
|
||||
## Invoke the `greet` function
|
||||
|
||||
The easiest way to invoke the function is to use `curl`:
|
||||
|
|
|
@ -36,7 +36,7 @@ pub fn queue_with_output(trigger: &QueueTrigger) -> QueueMessage {
|
|||
}
|
||||
```
|
||||
|
||||
# Running the example
|
||||
# Running the example locally
|
||||
|
||||
## Prerequisites
|
||||
|
||||
|
@ -55,27 +55,40 @@ rustup default nightly
|
|||
|
||||
The Azure Functions Host is implemented with .NET Core, so download and install a [.NET Core SDK](https://www.microsoft.com/net/download).
|
||||
|
||||
### Custom fork of Azure Functions Host
|
||||
### Azure Functions Host
|
||||
|
||||
Currently, the Azure Functions Host does not support the Rust language worker. Until that time, Azure Functions written in Rust must be executed locally using a [fork of the Azure Functions Host that does](https://github.com/peterhuene/azure-functions-host/tree/rust-worker-provider).
|
||||
|
||||
Run the following command to clone the fork:
|
||||
Clone the Azure Functions Host from GitHub:
|
||||
|
||||
```
|
||||
git clone -b rust-worker-provider git@github.com:peterhuene/azure-functions-host.git
|
||||
git clone git@github.com:azure/azure-functions-host.git
|
||||
```
|
||||
|
||||
## Create the script root
|
||||
|
||||
Run the following command to create the "script root" for the example:
|
||||
Use `dotnet` to build the Azure Functions Host:
|
||||
|
||||
```
|
||||
cargo run -q -- --create root
|
||||
cd azure-functions-host/src/WebJobs.Script.WebHost
|
||||
dotnet build
|
||||
```
|
||||
|
||||
This will build and run the sample to create the "script root" containing the Rust worker and the example Azure Function metadata.
|
||||
## Register the Rust language worker
|
||||
|
||||
Remember the path to the root directory from this step as it will be needed for running the Azure Functions Host below.
|
||||
The Azure Functions Host uses JSON configuration files to register language workers.
|
||||
|
||||
Create the configuration file to register the Rust language worker:
|
||||
|
||||
```
|
||||
mkdir azure-functions-host/src/WebJobs.Script.WebHost/bin/Debug/netcoreapp2.1/workers/rust
|
||||
cp azure-functions-rs/azure-functions/worker.config.json azure-functions-host/src/WebJobs.Script.WebHost/bin/Debug/netcoreapp2.1/workers/rust
|
||||
```
|
||||
|
||||
## Initialize the example application
|
||||
|
||||
Run the following command to build and initialize the Rust Azure Functions application:
|
||||
|
||||
```
|
||||
cd azure-functions-rs/examples/queue
|
||||
cargo run --release -- init --worker-path /tmp/queue-example/rust_worker --script-root /tmp/queue-example/root
|
||||
```
|
||||
|
||||
## Start the Azure Functions Host
|
||||
|
||||
|
@ -83,10 +96,10 @@ Run the following commands to start the Azure Functions Host:
|
|||
|
||||
```
|
||||
cd azure-functions-host/src/WebJobs.Script.WebHost
|
||||
AzureWebJobsScriptRoot=$SCRIPT_ROOT AzureWebJobsStorage=$CONNECTION_STRING dotnet run
|
||||
PATH=/tmp/queue-example:$PATH AzureWebJobsScriptRoot=/tmp/queue-example/root AzureWebJobsStorage=$CONNECTION_STRING dotnet run
|
||||
```
|
||||
|
||||
Where `$SCRIPT_ROOT` above represents the path to the root directory created from running `cargo run` above and `$CONNECTION_STRING` is the Azure Storage connection string the Azure Functions host should use.
|
||||
Where `$CONNECTION_STRING` is the Azure Storage connection string the Azure Functions host should use.
|
||||
|
||||
_Note: the syntax above works on macOS and Linux; on Windows, set the environment variables before running `dotnet run`._
|
||||
|
||||
|
@ -110,5 +123,8 @@ info: Function.queue[0]
|
|||
Executed 'Functions.queue' (Succeeded, Id=01912ed1-83aa-4ac7-ae2a-9b2b1ae80830)
|
||||
```
|
||||
|
||||
Likewise, to invoke the `queue_with_output` function, post a message to the `echo-in` queue. After the function invokes,
|
||||
you should see the same message posted back to the `echo-out` queue.
|
||||
## Invoke the `queue_with_output` function
|
||||
|
||||
To invoke the `queue_with_output` function, post a message to the `echo-in` queue.
|
||||
|
||||
After the function invokes, you should see the same message posted back to the `echo-out` queue.
|
|
@ -4,5 +4,5 @@ version = "0.1.0"
|
|||
authors = ["Peter Huene <peterhuene@protonmail.com>"]
|
||||
|
||||
[dependencies]
|
||||
azure-functions = { version = "0.1.3", path = "../../azure-functions" }
|
||||
azure-functions = { version = "0.1.4", path = "../../azure-functions" }
|
||||
log = "0.4.2"
|
||||
|
|
|
@ -18,7 +18,7 @@ pub fn timer(info: &TimerInfo) {
|
|||
}
|
||||
```
|
||||
|
||||
# Running the example
|
||||
# Running the example locally
|
||||
|
||||
## Prerequisites
|
||||
|
||||
|
@ -37,27 +37,40 @@ rustup default nightly
|
|||
|
||||
The Azure Functions Host is implemented with .NET Core, so download and install a [.NET Core SDK](https://www.microsoft.com/net/download).
|
||||
|
||||
### Custom fork of Azure Functions Host
|
||||
### Azure Functions Host
|
||||
|
||||
Currently, the Azure Functions Host does not support the Rust language worker. Until that time, Azure Functions written in Rust must be executed locally using a [fork of the Azure Functions Host that does](https://github.com/peterhuene/azure-functions-host/tree/rust-worker-provider).
|
||||
|
||||
Run the following command to clone the fork:
|
||||
Clone the Azure Functions Host from GitHub:
|
||||
|
||||
```
|
||||
git clone -b rust-worker-provider git@github.com:peterhuene/azure-functions-host.git
|
||||
git clone git@github.com:azure/azure-functions-host.git
|
||||
```
|
||||
|
||||
## Create the script root
|
||||
|
||||
Run the following command to create the "script root" for the example:
|
||||
Use `dotnet` to build the Azure Functions Host:
|
||||
|
||||
```
|
||||
cargo run -q -- --create root
|
||||
cd azure-functions-host/src/WebJobs.Script.WebHost
|
||||
dotnet build
|
||||
```
|
||||
|
||||
This will build and run the sample to create the "script root" containing the Rust worker and the example Azure Function metadata.
|
||||
## Register the Rust language worker
|
||||
|
||||
Remember the path to the root directory from this step as it will be needed for running the Azure Functions Host below.
|
||||
The Azure Functions Host uses JSON configuration files to register language workers.
|
||||
|
||||
Create the configuration file to register the Rust language worker:
|
||||
|
||||
```
|
||||
mkdir azure-functions-host/src/WebJobs.Script.WebHost/bin/Debug/netcoreapp2.1/workers/rust
|
||||
cp azure-functions-rs/azure-functions/worker.config.json azure-functions-host/src/WebJobs.Script.WebHost/bin/Debug/netcoreapp2.1/workers/rust
|
||||
```
|
||||
|
||||
## Initialize the example application
|
||||
|
||||
Run the following command to build and initialize the Rust Azure Functions application:
|
||||
|
||||
```
|
||||
cd azure-functions-rs/examples/timer
|
||||
cargo run --release -- init --worker-path /tmp/timer-example/rust_worker --script-root /tmp/timer-example/root
|
||||
```
|
||||
|
||||
## Start the Azure Functions Host
|
||||
|
||||
|
@ -65,10 +78,10 @@ Run the following commands to start the Azure Functions Host:
|
|||
|
||||
```
|
||||
cd azure-functions-host/src/WebJobs.Script.WebHost
|
||||
AzureWebJobsScriptRoot=$SCRIPT_ROOT AzureWebJobsStorage=$CONNECTION_STRING dotnet run
|
||||
PATH=/tmp/timer-example:$PATH AzureWebJobsScriptRoot=/tmp/timer-example/root AzureWebJobsStorage=$CONNECTION_STRING dotnet run
|
||||
```
|
||||
|
||||
Where `$SCRIPT_ROOT` above represents the path to the root directory created from running `cargo run` above and `$CONNECTION_STRING` is the Azure Storage connection string the Azure Functions host should use.
|
||||
Where `$CONNECTION_STRING` is the Azure Storage connection string the Azure Functions host should use.
|
||||
|
||||
_Note: the syntax above works on macOS and Linux; on Windows, set the environment variables before running `dotnet run`._
|
||||
|
||||
|
|
Loading…
Reference in New Issue