Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions content/en/_index.html
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,8 @@ <h4 class="section-text-bold">
</h4>
<p class="section-text">
Fission is extensible to any programming language (Python, NodeJS,
Go, C#, PHP are supported today). It abstracts away containers by
default, but you can build your own containers if you need to.
Go, Rust, C#, PHP are supported today). It abstracts away containers
by default, but you can build your own containers if you need to.
</p>
</div>
</div>
Expand Down Expand Up @@ -238,8 +238,8 @@ <h4 class="section-text-bold">Wide Language Support</h4>
</div>
<p class="section-text">
Fission is extensible to any programming language of your choice.
Python, NodeJS, Go, C#, PHP are supported today, but you can build
your own custom containers if you need to.
Python, NodeJS, Go, Rust, C#, PHP are supported today, but you can
build your own custom containers if you need to.
</p>
</div>
</div>
Expand Down
1 change: 1 addition & 0 deletions content/en/docs/usage/languages/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Each environment has a runtime image (`*-env`) and, where dependency building is
| Node.js | `ghcr.io/fission/node-env` | `ghcr.io/fission/node-builder` | [Node.js]({{% ref "nodejs.md" %}}) |
| Python | `ghcr.io/fission/python-env` | `ghcr.io/fission/python-builder` | [Python]({{% ref "python.md" %}}) |
| Go | `ghcr.io/fission/go-env` | `ghcr.io/fission/go-builder` | [Go]({{% ref "go.md" %}}) |
| Rust | `ghcr.io/fission/rust-env` | `ghcr.io/fission/rust-builder` | [Rust]({{% ref "rust.md" %}}) |
| Java (JVM) | `ghcr.io/fission/jvm-env` | `ghcr.io/fission/jvm-builder` | [Java]({{% ref "java.md" %}}) |
| Ruby | `ghcr.io/fission/ruby-env` | `ghcr.io/fission/ruby-builder` | [environments repo](https://github.com/fission/environments/tree/master/ruby) |
| PHP | `ghcr.io/fission/php-env` | `ghcr.io/fission/php-builder` | [environments repo](https://github.com/fission/environments/tree/master/php7) |
Expand Down
317 changes: 317 additions & 0 deletions content/en/docs/usage/languages/rust.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,317 @@
---
title: "Rust Functions"
description: "Writing Rust functions with fission"
weight: 10
---

Fission supports Rust as a first-class function language.
Rust functions are compiled by the builder into native server binaries built on [axum](https://docs.rs/axum) and [tokio](https://tokio.rs), so invocations run at native speed with no per-request process startup.

In this usage guide we'll cover how to use this environment, write functions, and work with dependencies.

### Before you start

We'll assume you have Fission and Kubernetes set up.
If not, head over to the [install guide]({{% ref "../../installation/_index.en.md" %}}).
Verify your Fission setup with:

```bash
fission version
```

### Add the Rust environment to your cluster

Rust is a compiled language, so source code must be compiled before it runs.
The builder manager inside Fission does this automatically whenever a Rust function or package is created: the Rust builder converts a source package into a deployable native binary.

```bash
fission environment create --name rust \
--image ghcr.io/fission/rust-env \
--builder ghcr.io/fission/rust-builder
```

#### Rust environment image list

| Image | Builder Image |
|-------|---------------|
| [ghcr.io/fission/rust-env](https://github.com/fission/environments/pkgs/container/rust-env/versions?filters%5Bversion_type%5D=tagged) | [ghcr.io/fission/rust-builder](https://github.com/fission/environments/pkgs/container/rust-builder/versions?filters%5Bversion_type%5D=tagged) |

### Write a simple function in Rust

A single-file function is one `.rs` file that defines `pub async fn handler`.
Any [axum handler](https://docs.rs/axum/latest/axum/handler/index.html) signature works, so you can use extractors, `Json`, headers, and so on.

Here is a hello world example (`hello.rs`):

```rust
use fission_rust::IntoResponse;

pub async fn handler() -> impl IntoResponse {
"Hello, World!\n"
}
```

Create and test the function:

```bash
fission fn create --name helloworld --env rust --src hello.rs
```

Before accessing the function, make sure its package build has succeeded:

```bash
fission pkg info --name <pkg-name>
```

Now test it:

```bash
$ fission fn test --name helloworld
Hello, World!
```

{{% notice info %}}
See [here]({{% ref "../triggers/_index.md" %}}) for how to set up different triggers for a Rust function.
{{% /notice %}}

Single-file functions may use the crates pre-baked into the builder: `fission-rust`, `axum`, `tokio`, `serde`, and `serde_json`.
For other dependencies, use a [Cargo project](#working-with-dependencies-cargo-projects).

### HTTP requests and HTTP responses

The function receives every request routed to it; axum extractors give you typed access to all parts of the request.

#### Accessing HTTP Requests

##### Headers

```rust
use fission_rust::IntoResponse;
use fission_rust::axum::http::HeaderMap;

pub async fn handler(headers: HeaderMap) -> impl IntoResponse {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[LanguageTool] reported by reviewdog 🐶
It appears that a white space is missing. (SPACE_BEFORE_PARENTHESIS[1])
Suggestions: (
URL: https://languagetool.org/insights/post/punctuation-guide/#what-are-parentheses
Rule: https://community.languagetool.org/rule/show/SPACE_BEFORE_PARENTHESIS?lang=en-US&subId=1
Category: TYPOGRAPHY

let v = headers
.get("x-my-header")
.and_then(|v| v.to_str().ok())
.unwrap_or("not set");
format!("x-my-header: {v}\n")
}
```

Create an HTTP trigger and call it:

```bash
fission httptrigger create --method GET --url "/<url>" --function <fn-name>
```

```bash
$ curl http://$FISSION_ROUTER/<url> -H 'X-My-Header: foo'
x-my-header: foo
```

##### Query string

```rust
use std::collections::HashMap;
use fission_rust::IntoResponse;
use fission_rust::axum::extract::Query;

pub async fn handler(Query(params): Query<HashMap<String, String>>) -> impl IntoResponse {
params.get("key-name").cloned().unwrap_or_default()
}
```

```bash
$ curl "http://$FISSION_ROUTER/<url>?key-name=123"
123
```

##### Request Body

###### Plain text

```rust
use fission_rust::IntoResponse;

pub async fn handler(body: String) -> impl IntoResponse {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[LanguageTool] reported by reviewdog 🐶
It appears that a white space is missing. (SPACE_BEFORE_PARENTHESIS[1])
Suggestions: (
URL: https://languagetool.org/insights/post/punctuation-guide/#what-are-parentheses
Rule: https://community.languagetool.org/rule/show/SPACE_BEFORE_PARENTHESIS?lang=en-US&subId=1
Category: TYPOGRAPHY

body
}
```

```bash
$ curl -X POST http://$FISSION_ROUTER/<url> -d foobar

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[LanguageTool] reported by reviewdog 🐶
Possible typo: you repeated a word (ENGLISH_WORD_REPEAT_RULE)
Suggestions: foobar
Rule: https://community.languagetool.org/rule/show/ENGLISH_WORD_REPEAT_RULE?lang=en-US
Category: MISC

foobar
```

###### JSON

```rust
use fission_rust::IntoResponse;
use fission_rust::axum::Json;
use serde::{Deserialize, Serialize};

#[derive(Deserialize, Serialize)]
pub struct Msg {
content: String,
}

pub async fn handler(Json(msg): Json<Msg>) -> impl IntoResponse {
Json(msg)
}
```

```bash
$ curl -X POST http://$FISSION_ROUTER/<url> \
-H 'Content-Type: application/json' -d '{"content": "foobar"}'
{"content":"foobar"}
```

#### Controlling HTTP Responses

##### Setting response headers and status codes

Return a tuple of status, headers, and body — axum converts it into a response:

```rust
use fission_rust::IntoResponse;
use fission_rust::axum::http::StatusCode;

pub async fn handler() -> impl IntoResponse {
(
StatusCode::CREATED,
[("x-request-handled-by", "fission-rust")],
"created\n",
)
}
```

```bash
$ curl -i http://$FISSION_ROUTER/<url>
HTTP/1.1 201 Created
x-request-handled-by: fission-rust
...
```

Handler panics are caught by the runtime: the request returns HTTP 500 and the function keeps serving.

### Multiple module files

A source archive may contain a `handler.rs` plus extra module files.
Each file becomes a crate-root module, so `handler.rs` can reach a sibling `util.rs` as `crate::util`:

```rust
// util.rs
pub fn greeting() -> String {
"Hello from a sibling module!\n".to_string()
}
```

```rust
// handler.rs
use fission_rust::IntoResponse;

pub async fn handler() -> impl IntoResponse {
crate::util::greeting()
}
```

```bash
zip -r function.zip handler.rs util.rs
fission pkg create --name multimod --env rust --src function.zip
```

### Working with dependencies (Cargo projects)

For third-party crates, supply a full Cargo binary crate as the source package.
The only contract: **the binary must serve HTTP on `127.0.0.1:$FISSION_RUNTIME_PORT`**.

The easiest way is the `fission-rust` SDK:

```toml
# Cargo.toml
[package]
name = "echo-example"
version = "0.1.0"
edition = "2024"

[dependencies]
fission-rust = { git = "https://github.com/fission/environments" }
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }
serde_json = "1"
```

```rust
// src/main.rs
use fission_rust::IntoResponse;
use fission_rust::axum::Json;
use serde_json::Value;

async fn handler(body: String) -> impl IntoResponse {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[LanguageTool] reported by reviewdog 🐶
It appears that a white space is missing. (SPACE_BEFORE_PARENTHESIS[1])
Suggestions: (
URL: https://languagetool.org/insights/post/punctuation-guide/#what-are-parentheses
Rule: https://community.languagetool.org/rule/show/SPACE_BEFORE_PARENTHESIS?lang=en-US&subId=1
Category: TYPOGRAPHY

let value: Value = serde_json::from_str(&body)
.unwrap_or_else(|_| Value::String(body));
Json(value)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[LanguageTool] reported by reviewdog 🐶
It appears that a white space is missing. (SPACE_BEFORE_PARENTHESIS[1])
Suggestions: (
URL: https://languagetool.org/insights/post/punctuation-guide/#what-are-parentheses
Rule: https://community.languagetool.org/rule/show/SPACE_BEFORE_PARENTHESIS?lang=en-US&subId=1
Category: TYPOGRAPHY

}

#[tokio::main]
async fn main() {
fission_rust::serve(handler).await;
}
```

Archive and create the package as usual:

```bash
$ zip -r echo.zip Cargo.toml src
$ fission pkg create --name echo --env rust --src echo.zip
$ fission fn create --name echo --env rust --pkg echo
```

#### Bring your own framework

Because the contract is just "serve HTTP on `$FISSION_RUNTIME_PORT`", any Rust web framework works — actix-web, rocket, warp, or raw hyper:

```rust
// src/main.rs — plain axum without the SDK
use axum::{Router, routing::get};

#[tokio::main]
async fn main() {
let port: u16 = std::env::var("FISSION_RUNTIME_PORT")
.ok().and_then(|p| p.parse().ok()).unwrap_or(8889);
let app = Router::new().route("/", get(|| async { "Hello!\n" }));
let listener = tokio::net::TcpListener::bind(("127.0.0.1", port)).await.unwrap();
axum::serve(listener, app).await.unwrap();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[LanguageTool] reported by reviewdog 🐶
It appears that a white space is missing. (SPACE_BEFORE_PARENTHESIS[1])
Suggestions: (
URL: https://languagetool.org/insights/post/punctuation-guide/#what-are-parentheses
Rule: https://community.languagetool.org/rule/show/SPACE_BEFORE_PARENTHESIS?lang=en-US&subId=1
Category: TYPOGRAPHY

}
```

#### Multiple binaries and entrypoints

If the project defines several `[[bin]]` targets, the builder deploys all of them and the function's `--entrypoint` selects one by name:

```bash
fission fn create --name myfn --env rust --pkg mypkg --entrypoint <binary-name>
```

A project with a single binary needs no entrypoint — it is always deployed under the default name `handler`.

### How it works

The runtime image runs a small supervisor that implements the Fission environment interface.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[LanguageTool] reported by reviewdog 🐶
A comma is probably missing here. (MISSING_COMMA_AFTER_INTRODUCTORY_PHRASE[1])
Suggestions: specialization,
URL: http://englishplus.com/grammar/00000074.htm
Rule: https://community.languagetool.org/rule/show/MISSING_COMMA_AFTER_INTRODUCTORY_PHRASE?lang=en-US&subId=1
Category: PUNCTUATION

At specialization it starts your compiled function binary **once** and then reverse-proxies all requests to it over a pooled local connection, so steady-state overhead is a single localhost hop.
If the function process exits, the pod is replaced automatically.

### Modifying/Rebuilding the environment images

Refer to the [Rust environment guide](https://github.com/fission/environments/blob/master/rust/README.md) to learn about rebuilding the environment images.

### Resource usage

Like any function, you can bound a Rust function's resources:

```bash
fission fn create --name echo --env rust --pkg echo \
--mincpu 20 --maxcpu 100 --minmemory 64 --maxmemory 128
```

Compiled Rust functions are typically small (a hello world binary is around 1 MB) and have low memory floors, so they are a good fit for tight resource limits.
Use `kubectl top pod -l functionName=<name>` while benchmarking to find the right values.
11 changes: 11 additions & 0 deletions static/data/environments.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,17 @@
}
]
},
{
"name": "Rust",
"logo": "/images/lang-logo/rust-logo.svg",
"repo": "https://github.com/fission/environments/tree/master/rust",
"images": [
{
"main": "rust-env",
"builder": "rust-builder"
}
]
},
{
"name": "Python",
"logo": "/images/lang-logo/python-logo.svg",
Expand Down
1 change: 1 addition & 0 deletions static/images/lang-logo/rust-logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions tools/environments.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
'jvm-env': 'Java',
'jvm-jersey-env-25': 'Java (JVM-Jersey)',
'ruby-env': 'Ruby',
'rust-env': 'Rust',
'python-env': 'Python',
'python-fastapi-env': 'Python (FastAPI)',
'binary-env': 'Misc',
Expand Down