clean shutdown
This commit is contained in:
+40
-41
@@ -282,10 +282,39 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
|
||||
let listener = TcpListener::bind(&bind_address).await?;
|
||||
info!(address = %bind_address, "sustenance listening");
|
||||
axum::serve(listener, app).await?;
|
||||
axum::serve(listener, app)
|
||||
.with_graceful_shutdown(shutdown_signal())
|
||||
.await?;
|
||||
info!("shutdown complete; closing database");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn shutdown_signal() {
|
||||
let ctrl_c = async {
|
||||
tokio::signal::ctrl_c()
|
||||
.await
|
||||
.expect("failed to install Ctrl+C handler");
|
||||
};
|
||||
|
||||
#[cfg(unix)]
|
||||
let terminate = async {
|
||||
tokio::signal::unix::signal(tokio::signal::unix::SignalKind::terminate())
|
||||
.expect("failed to install signal handler")
|
||||
.recv()
|
||||
.await;
|
||||
};
|
||||
|
||||
#[cfg(not(unix))]
|
||||
let terminate = std::future::pending::<()>();
|
||||
|
||||
tokio::select! {
|
||||
_ = ctrl_c => {},
|
||||
_ = terminate => {},
|
||||
}
|
||||
|
||||
info!("signal received; starting graceful shutdown");
|
||||
}
|
||||
|
||||
async fn home() -> Redirect {
|
||||
Redirect::to("/lists")
|
||||
}
|
||||
@@ -431,10 +460,7 @@ async fn lists_page(
|
||||
State(state): State<AppState>,
|
||||
user: CurrentUser,
|
||||
) -> Result<Response, AppError> {
|
||||
let lists = state
|
||||
.db
|
||||
.list_summaries()
|
||||
.await?;
|
||||
let lists = state.db.list_summaries().await?;
|
||||
Ok(html_response(views::lists_page(
|
||||
&user.session.user,
|
||||
&lists,
|
||||
@@ -498,10 +524,7 @@ async fn add_item(
|
||||
.db
|
||||
.add_item(list_id, name, quantity, note, category_id)
|
||||
.await?;
|
||||
state
|
||||
.hub
|
||||
.publish_list_changed(list_id, revision)
|
||||
.await;
|
||||
state.hub.publish_list_changed(list_id, revision).await;
|
||||
list_fragment_response(&state, &user, list_id).await
|
||||
}
|
||||
|
||||
@@ -518,14 +541,8 @@ async fn check_item(
|
||||
"0" | "false" => false,
|
||||
_ => return Err(AppError::BadRequest("Invalid checked value.".into())),
|
||||
};
|
||||
let revision = state
|
||||
.db
|
||||
.set_item_checked(list_id, item_id, checked)
|
||||
.await?;
|
||||
state
|
||||
.hub
|
||||
.publish_list_changed(list_id, revision)
|
||||
.await;
|
||||
let revision = state.db.set_item_checked(list_id, item_id, checked).await?;
|
||||
state.hub.publish_list_changed(list_id, revision).await;
|
||||
list_fragment_response(&state, &user, list_id).await
|
||||
}
|
||||
|
||||
@@ -554,10 +571,7 @@ async fn edit_item(
|
||||
parse_category_id(form.category_id),
|
||||
)
|
||||
.await?;
|
||||
state
|
||||
.hub
|
||||
.publish_list_changed(list_id, revision)
|
||||
.await;
|
||||
state.hub.publish_list_changed(list_id, revision).await;
|
||||
list_fragment_response(&state, &user, list_id).await
|
||||
}
|
||||
|
||||
@@ -570,10 +584,7 @@ async fn delete_item(
|
||||
verify_csrf(&user, &form.csrf)?;
|
||||
require_access(&state, list_id).await?;
|
||||
let revision = state.db.delete_item(list_id, item_id).await?;
|
||||
state
|
||||
.hub
|
||||
.publish_list_changed(list_id, revision)
|
||||
.await;
|
||||
state.hub.publish_list_changed(list_id, revision).await;
|
||||
list_fragment_response(&state, &user, list_id).await
|
||||
}
|
||||
|
||||
@@ -592,10 +603,7 @@ async fn create_category(
|
||||
));
|
||||
}
|
||||
let revision = state.db.create_category(list_id, name).await?;
|
||||
state
|
||||
.hub
|
||||
.publish_list_changed(list_id, revision)
|
||||
.await;
|
||||
state.hub.publish_list_changed(list_id, revision).await;
|
||||
|
||||
let access = require_access(&state, list_id).await?;
|
||||
let items = state.db.items(list_id).await?;
|
||||
@@ -631,10 +639,7 @@ async fn invitation_page(
|
||||
Path(token): Path<String>,
|
||||
headers: HeaderMap,
|
||||
) -> Result<Response, AppError> {
|
||||
let info = state
|
||||
.db
|
||||
.invitation(token.clone())
|
||||
.await?;
|
||||
let info = state.db.invitation(token.clone()).await?;
|
||||
if !info {
|
||||
return Err(AppError::NotFound);
|
||||
}
|
||||
@@ -655,10 +660,7 @@ async fn accept_invitation(
|
||||
LoggedForm(form): LoggedForm<CsrfForm>,
|
||||
) -> Result<Response, AppError> {
|
||||
verify_csrf(&user, &form.csrf)?;
|
||||
state
|
||||
.db
|
||||
.accept_invitation(token)
|
||||
.await?;
|
||||
state.db.accept_invitation(token).await?;
|
||||
Ok(Redirect::to("/lists").into_response())
|
||||
}
|
||||
|
||||
@@ -817,10 +819,7 @@ async fn list_fragment_response(
|
||||
)))
|
||||
}
|
||||
|
||||
async fn require_access(
|
||||
state: &AppState,
|
||||
list_id: i64,
|
||||
) -> Result<db::GroceryList, AppError> {
|
||||
async fn require_access(state: &AppState, list_id: i64) -> Result<db::GroceryList, AppError> {
|
||||
state
|
||||
.db
|
||||
.list_access(list_id)
|
||||
|
||||
Reference in New Issue
Block a user