Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

75 gracefully shutdown server #101

Merged
merged 25 commits into from
Jul 11, 2024
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
723909e
feat(server): gracefully shutting down mediator-server
Christiantyemele Jun 27, 2024
c792ebe
feat(shutdown): gracefully shutting down generic server
Christiantyemele Jun 28, 2024
5f9800f
fix(shutdown): gracefully shutting down mediator server
Christiantyemele Jun 28, 2024
4161afb
fix(test): adding shutdown test plus reformating
Christiantyemele Jul 2, 2024
2b6b60a
fix(test): adding test and code reformating
Christiantyemele Jul 2, 2024
6c42a8d
fix(update): updated shutdown to include unmounting of plugins
Christiantyemele Jul 3, 2024
a5eb619
feat(): gracefully shutdown server
Christiantyemele Jul 4, 2024
47a5fb9
feat(): gracefull shutdown
Christiantyemele Jul 4, 2024
cb75633
fix(): correcting typos
Christiantyemele Jul 4, 2024
5ac7f82
fix(): fixing dependencies
Christiantyemele Jul 4, 2024
8381763
fix(global): global fix of shutdown impl
Christiantyemele Jul 10, 2024
7d19446
fix(config): fixing dependencies
Christiantyemele Jul 10, 2024
89730c5
fix(test): added test for plugin unloading and some code formating
Christiantyemele Jul 10, 2024
9d4c701
Update main.rs
Christiantyemele Jul 10, 2024
6810104
Update main.rs
Christiantyemele Jul 10, 2024
5339244
fix(update): removed tokio_utils
Christiantyemele Jul 10, 2024
7b4dac4
Merge branch '75-gracefully-shutdown-server' of github.com:adorsys/di…
Christiantyemele Jul 10, 2024
329d301
fix(global): reformatting
Christiantyemele Jul 11, 2024
2a61cd0
Merge branch 'main' into 75-gracefully-shutdown-server
Christiantyemele Jul 11, 2024
3b7b958
fix(): resloved conflicts
Christiantyemele Jul 11, 2024
705266d
fix(global): fixing code formatting
Christiantyemele Jul 11, 2024
018b671
Fix formatting
IngridPuppet Jul 11, 2024
6f2fd07
Update main.rs
Christiantyemele Jul 11, 2024
711ab8e
Update container.rs
Christiantyemele Jul 11, 2024
1bb00cd
Merge pull request #124 from adorsys/75-gracefully-shutdown-server-patch
Christiantyemele Jul 11, 2024
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
2 changes: 2 additions & 0 deletions generic-server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@ server-plugin = { path = "../server-plugin" }
chrono = { version = "0.4.26", optional = true }
did-endpoint = { path = "../did-endpoint", optional = true }
oob-messages = { path = "../oob-messages", optional = true }
once_cell = "1.19.0"
IngridPuppet marked this conversation as resolved.
Show resolved Hide resolved

[dev-dependencies]
nix = { version = "0.29.0", features = ["feature"] }
tower = { version = "0.4.13", features = ["util"] }

[features]
Expand Down
17 changes: 10 additions & 7 deletions generic-server/src/lib.rs
IngridPuppet marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
pub mod plugin;
pub mod util;

use plugin::container::PluginContainer;

use axum::Router;
use tower_http::catch_panic::CatchPanicLayer;
use tower_http::trace::TraceLayer;

pub fn app() -> Router {
pub fn app() -> (PluginContainer<'static>, Router) {
let mut container = PluginContainer::default();
let _ = container.load();

Router::new() //
.merge(container.routes().unwrap_or_default())
.layer(TraceLayer::new_for_http())
.layer(CatchPanicLayer::new())

let router = Router::new()
.merge(container.routes().unwrap_or_default())
.layer(TraceLayer::new_for_http())
.layer(CatchPanicLayer::new());
(container, router)
IngridPuppet marked this conversation as resolved.
Show resolved Hide resolved
}



54 changes: 43 additions & 11 deletions generic-server/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,43 @@
use generic_server::app;

use axum::Server;
use generic_server::app;
use std::net::SocketAddr;

#[tokio::main]
async fn main() {
// Start server
let port = std::env::var("SERVER_LOCAL_PORT").unwrap_or("3000".to_owned());
let addr: SocketAddr = format!("127.0.0.1:{port}").parse().unwrap();
tracing::info!("listening on {addr}");
generic_server_with_gracefull_shutdown(addr).await
}

async fn generic_server_with_gracefull_shutdown(addr: SocketAddr) {
// Load dotenv-flow variables
IngridPuppet marked this conversation as resolved.
Show resolved Hide resolved
dotenv_flow::dotenv_flow().ok();

// Enable logging
config_tracing();

// Start server
let port = std::env::var("SERVER_LOCAL_PORT").unwrap_or("3000".to_owned());
let addr: SocketAddr = format!("127.0.0.1:{port}").parse().unwrap();
tracing::info!("listening on {addr}");
Server::bind(&addr)
.serve(app().into_make_service())
.await
.unwrap();
}
// Load plugins
let (mut plugin_container, router) = app();

// spawn task for server
tokio::spawn(async move {
Server::bind(&addr)
.serve(router.into_make_service())
.await
.unwrap();
});

tokio::select! {
_ = tokio::signal::ctrl_c() => {
tracing::info!("\nshuting down gracefully");
let _ = plugin_container.unload();}
IngridPuppet marked this conversation as resolved.
Show resolved Hide resolved
};
IngridPuppet marked this conversation as resolved.
Show resolved Hide resolved
}
fn config_tracing() {
use tracing::Level;
IngridPuppet marked this conversation as resolved.
Show resolved Hide resolved

use tracing_subscriber::{filter, layer::SubscriberExt, util::SubscriberInitExt};

let tracing_layer = tracing_subscriber::fmt::layer();
Expand All @@ -36,3 +51,20 @@ fn config_tracing() {
.with(filter)
.init();
}

#[cfg(test)]
mod tests {
use super::generic_server_with_gracefull_shutdown;
use std::net::SocketAddr;

#[tokio::test]
async fn test_server_shutdown() {
let port = std::env::var("SERVER_LOCAL_PORT").unwrap_or("3000".to_owned());
let addr: SocketAddr = format!("127.0.0.1:{port}").parse().unwrap();
tracing::info!("listening on {addr}");

// run server in background
tokio::spawn(generic_server_with_gracefull_shutdown(addr));
// send a shutdown signal to main thread
}
}
50 changes: 48 additions & 2 deletions generic-server/src/plugin/container.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use std::collections::{HashMap, HashSet};

use axum::Router;
use server_plugin::{Plugin, PluginError};
use std::collections::{HashMap, HashSet};

use super::PLUGINS;

Expand Down Expand Up @@ -89,6 +88,37 @@ impl<'a> PluginContainer<'a> {
}
}

/// unload container plugins
pub fn unload(&mut self) -> Result<(), PluginContainerError> {
// Unmount plugins and clearing the vector of routes
let errors: HashMap<_, _> = self
.plugins
.iter()
.filter_map(|plugin| match plugin.unmount() {
Ok(_) => {
tracing::info!("Unmounted plugin {}", plugin.name());
None
IngridPuppet marked this conversation as resolved.
Show resolved Hide resolved
}
Err(err) => {
tracing::error!("error unmounting plugin {}", plugin.name());
Some((plugin.name().to_owned(), err))
}
})
.collect();

// Flag as unloaded
self.loaded = false;

// Return state of completion
if errors.is_empty() {
self.collected_routes.clear();
tracing::debug!("plugin container unloaded");
Ok(())
} else {
Err(PluginContainerError::PluginErrorMap(errors))
}
}

/// Merge collected routes from all plugins successfully initialized.
pub fn routes(&self) -> Result<Router, PluginContainerError> {
if self.loaded {
Expand Down Expand Up @@ -268,4 +298,20 @@ mod tests {
PluginContainerError::Unloaded
);
}
#[test]
fn test_unloading() {
IngridPuppet marked this conversation as resolved.
Show resolved Hide resolved
// loading container from test_loading
let mut container = PluginContainer {
loaded: false,
collected_routes: vec![],
plugins: &vec![Box::new(FirstPlugin {}), Box::new(SecondPlugin {})],
};
assert!(container.load().is_ok());
assert!(container.routes().is_ok());

IngridPuppet marked this conversation as resolved.
Show resolved Hide resolved
// unloading container and clearing routes
assert!(container.unload().is_ok());

assert_eq!(container.collected_routes.len(), 0);
}
}
Loading