Initial commit
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/target
|
||||||
15
Cargo.toml
Normal file
15
Cargo.toml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
[package]
|
||||||
|
name = "web-template"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
axum = "0"
|
||||||
|
libc = "0"
|
||||||
|
tokio = { version = "1", features = ["full"] }
|
||||||
|
tower = "0"
|
||||||
|
tower-http = { version = "0", features = ["trace", "timeout"] }
|
||||||
|
tracing = "0"
|
||||||
|
tracing-subscriber = { version = "0", features = ["json", "env-filter"] }
|
||||||
19
Dockerfile
Normal file
19
Dockerfile
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
ARG ALPINE_VERSION=latest
|
||||||
|
FROM alpine:$ALPINE_VERSION as builder
|
||||||
|
|
||||||
|
COPY Cargo.lock /usr/src/
|
||||||
|
COPY Cargo.toml /usr/src/
|
||||||
|
COPY src/ /usr/src/src/
|
||||||
|
|
||||||
|
WORKDIR /usr/src
|
||||||
|
|
||||||
|
RUN apk add --no-cache rustup build-base && \
|
||||||
|
rustup-init -qy --profile=minimal && \
|
||||||
|
source "$HOME/.cargo/env" && \
|
||||||
|
cargo build --release --target=x86_64-unknown-linux-musl
|
||||||
|
|
||||||
|
FROM alpine:$ALPINE_VERSION
|
||||||
|
|
||||||
|
COPY --from=builder /usr/src/target/x86_64-unknown-linux-musl/release/web-template /usr/bin/
|
||||||
|
|
||||||
|
CMD [ "/usr/bin/web-template" ]
|
||||||
64
src/main.rs
Normal file
64
src/main.rs
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use axum::{routing, Router};
|
||||||
|
use tokio::{
|
||||||
|
net::TcpListener,
|
||||||
|
signal::{self, unix::SignalKind},
|
||||||
|
task::JoinSet,
|
||||||
|
};
|
||||||
|
use tower_http::{timeout::TimeoutLayer, trace::TraceLayer};
|
||||||
|
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> Result<(), std::io::Error> {
|
||||||
|
tracing_subscriber::registry()
|
||||||
|
.with(tracing_subscriber::EnvFilter::from_env("LOG_LEVEL"))
|
||||||
|
.with(tracing_subscriber::fmt::layer().json())
|
||||||
|
.init();
|
||||||
|
|
||||||
|
let app = Router::new()
|
||||||
|
.route("/", routing::get(|| async { "Hello world!" }))
|
||||||
|
.layer((
|
||||||
|
TraceLayer::new_for_http(),
|
||||||
|
TimeoutLayer::new(Duration::from_secs(10)),
|
||||||
|
));
|
||||||
|
|
||||||
|
let listener = TcpListener::bind("0.0.0.0:8080").await.unwrap();
|
||||||
|
|
||||||
|
axum::serve(listener, app)
|
||||||
|
.with_graceful_shutdown(shutdown_signal())
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
const SIGNALS: &'static [(i32, &'static str)] = &[
|
||||||
|
(libc::SIGTERM, "SIGTERM"),
|
||||||
|
(libc::SIGQUIT, "SIGQUIT"),
|
||||||
|
(libc::SIGINT, "SIGINT"),
|
||||||
|
];
|
||||||
|
|
||||||
|
async fn shutdown_signal() {
|
||||||
|
let term_signals = [
|
||||||
|
SignalKind::terminate(),
|
||||||
|
SignalKind::quit(),
|
||||||
|
SignalKind::interrupt(),
|
||||||
|
];
|
||||||
|
|
||||||
|
let mut futures = JoinSet::new();
|
||||||
|
|
||||||
|
for term_signal in term_signals {
|
||||||
|
futures.spawn(async move {
|
||||||
|
signal::unix::signal(term_signal)
|
||||||
|
.expect("failed to install signal handler")
|
||||||
|
.recv()
|
||||||
|
.await;
|
||||||
|
term_signal.as_raw_value()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let kind = futures.join_next().await;
|
||||||
|
|
||||||
|
if let Some(Ok(kind)) = kind {
|
||||||
|
let name = SIGNALS.iter().find(|e| e.0 == kind).unwrap().1;
|
||||||
|
tracing::info!("{} received, shutting down gracefully", name);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user