Skip to content

Commit 5c23616

Browse files
committed
add axum streaming example
1 parent f45ca50 commit 5c23616

File tree

3 files changed

+92
-0
lines changed

3 files changed

+92
-0
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[package]
2+
name = "http-axum-streaming"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[dependencies]
7+
axum = "0.8"
8+
bytes = "1"
9+
futures-util = "0.3"
10+
lambda_http = { path = "../../lambda-http", default-features = false, features = [
11+
"apigw_rest", "apigw_http", "tracing"
12+
] }
13+
thiserror = "2.0"
14+
tokio = { version = "1", features = ["macros"] }
15+
tokio-stream = "0.1.2"
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# AWS Lambda Function example
2+
3+
This example demonstrates building a **streaming** HTTP response with Axum, deployed on AWS Lambda using a custom runtime.
4+
5+
## Build & Deploy
6+
7+
1. Install [cargo-lambda](https://github.com/cargo-lambda/cargo-lambda#installation)
8+
2. Build the function with `cargo lambda build --release`
9+
3. Deploy the function to AWS Lambda with `cargo lambda deploy --enable-function-url --iam-role YOUR_ROLE`
10+
4. Enable Lambda streaming response on Lambda console: change the function url's invoke mode to `RESPONSE_STREAM`
11+
5. Verify the function works: `curl -v -N <function-url>`. The results should be streamed back with 0.5 second pause between each word.
12+
13+
## Build for ARM 64
14+
15+
Build the function with `cargo lambda build --release --arm64`
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
use axum::{
2+
body::Body,
3+
http,
4+
http::{
5+
header::{CACHE_CONTROL, CONTENT_TYPE},
6+
StatusCode,
7+
},
8+
response::{IntoResponse, Response},
9+
routing::get,
10+
Router,
11+
};
12+
use bytes::Bytes;
13+
use lambda_http::{lambda_runtime, tracing, Error, StreamAdapter};
14+
use std::{convert::Infallible, time::Duration};
15+
use thiserror::Error;
16+
use tokio::sync::mpsc;
17+
use tokio_stream::wrappers::ReceiverStream;
18+
19+
#[derive(Debug, Error)]
20+
pub enum AppError {
21+
#[error("{0}")]
22+
Http(#[from] http::Error),
23+
}
24+
25+
impl IntoResponse for AppError {
26+
fn into_response(self) -> Response {
27+
(StatusCode::INTERNAL_SERVER_ERROR, self.to_string()).into_response()
28+
}
29+
}
30+
31+
type AppResult<T = Response> = Result<T, AppError>;
32+
33+
async fn stream_handler() -> AppResult {
34+
let (tx, rx) = mpsc::channel::<Result<Bytes, Infallible>>(8);
35+
let body = Body::from_stream(ReceiverStream::new(rx));
36+
37+
tokio::spawn(async move {
38+
for msg in ["Hello", "world", "from", "Lambda!"] {
39+
tokio::time::sleep(Duration::from_millis(500)).await;
40+
if tx.send(Ok(Bytes::from(format!("{msg}\n")))).await.is_err() {
41+
break;
42+
}
43+
}
44+
});
45+
46+
Ok(Response::builder()
47+
.status(StatusCode::OK)
48+
.header(CONTENT_TYPE, "text/plain; charset=utf-8")
49+
.header(CACHE_CONTROL, "no-cache")
50+
.body(body)?)
51+
}
52+
53+
#[tokio::main]
54+
async fn main() -> Result<(), Error> {
55+
tracing::init_default_subscriber();
56+
57+
let app = Router::new().route("/", get(stream_handler));
58+
59+
let runtime = lambda_runtime::Runtime::new(StreamAdapter::from(app));
60+
61+
runtime.run().await
62+
}

0 commit comments

Comments
 (0)