Return HTTP status 503 to all requests during startup (fixes #3780) (#4005)

* Return HTTP status 503 to all requests during startup (fixes #3780)

* add message

* fmt

* remove err

* dont run startup server if http disabled

* ci
startup-error-503-comment
Nutomic 2023-10-05 00:19:58 +02:00 committed by GitHub
parent 626c7ebc85
commit 6950dd90e5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 35 additions and 13 deletions

View File

@ -1,10 +1,5 @@
use crate::error::{LemmyError, LemmyErrorType}; use crate::error::{LemmyError, LemmyErrorType};
use actix_web::{ use actix_web::{dev::ServiceResponse, middleware::ErrorHandlerResponse, HttpResponse};
dev::ServiceResponse,
http::header,
middleware::ErrorHandlerResponse,
HttpResponse,
};
pub fn jsonify_plain_text_errors<BODY>( pub fn jsonify_plain_text_errors<BODY>(
res: ServiceResponse<BODY>, res: ServiceResponse<BODY>,
@ -28,9 +23,7 @@ pub fn jsonify_plain_text_errors<BODY>(
let error = res let error = res
.error() .error()
.expect("expected an error object in the response"); .expect("expected an error object in the response");
let response = HttpResponse::build(res.status()) let response = HttpResponse::build(res.status()).json(LemmyErrorType::Unknown(error.to_string()));
.append_header(header::ContentType::json())
.json(LemmyErrorType::Unknown(error.to_string()));
let service_response = ServiceResponse::new(req, response); let service_response = ServiceResponse::new(req, response);
Ok(ErrorHandlerResponse::Response( Ok(ErrorHandlerResponse::Response(

View File

@ -16,10 +16,11 @@ use crate::{
use activitypub_federation::config::{FederationConfig, FederationMiddleware}; use activitypub_federation::config::{FederationConfig, FederationMiddleware};
use actix_cors::Cors; use actix_cors::Cors;
use actix_web::{ use actix_web::{
dev::ServerHandle, dev::{ServerHandle, ServiceResponse},
middleware::{self, ErrorHandlers}, middleware::{self, ErrorHandlerResponse, ErrorHandlers},
web::Data, web::Data,
App, App,
HttpResponse,
HttpServer, HttpServer,
Result, Result,
}; };
@ -54,6 +55,7 @@ use lemmy_utils::{
use reqwest::Client; use reqwest::Client;
use reqwest_middleware::{ClientBuilder, ClientWithMiddleware}; use reqwest_middleware::{ClientBuilder, ClientWithMiddleware};
use reqwest_tracing::TracingMiddleware; use reqwest_tracing::TracingMiddleware;
use serde_json::json;
use std::{env, ops::Deref, time::Duration}; use std::{env, ops::Deref, time::Duration};
use tokio::signal::unix::SignalKind; use tokio::signal::unix::SignalKind;
use tracing::subscriber::set_global_default; use tracing::subscriber::set_global_default;
@ -115,9 +117,13 @@ pub(crate) const REQWEST_TIMEOUT: Duration = Duration::from_secs(10);
/// Placing the main function in lib.rs allows other crates to import it and embed Lemmy /// Placing the main function in lib.rs allows other crates to import it and embed Lemmy
pub async fn start_lemmy_server(args: CmdArgs) -> Result<(), LemmyError> { pub async fn start_lemmy_server(args: CmdArgs) -> Result<(), LemmyError> {
let scheduled_tasks_enabled = !args.disable_scheduled_tasks;
let settings = SETTINGS.to_owned(); let settings = SETTINGS.to_owned();
let mut startup_server_handle = None;
if args.http_server {
startup_server_handle = Some(create_startup_server()?);
}
// Run the DB migrations // Run the DB migrations
let db_url = get_database_url(Some(&settings)); let db_url = get_database_url(Some(&settings));
run_migrations(&db_url); run_migrations(&db_url);
@ -179,7 +185,7 @@ pub async fn start_lemmy_server(args: CmdArgs) -> Result<(), LemmyError> {
rate_limit_cell.clone(), rate_limit_cell.clone(),
); );
if scheduled_tasks_enabled { if !args.disable_scheduled_tasks {
// Schedules various cleanup tasks for the DB // Schedules various cleanup tasks for the DB
let _scheduled_tasks = tokio::task::spawn(scheduled_tasks::setup(context.clone())); let _scheduled_tasks = tokio::task::spawn(scheduled_tasks::setup(context.clone()));
} }
@ -207,6 +213,9 @@ pub async fn start_lemmy_server(args: CmdArgs) -> Result<(), LemmyError> {
let outgoing_activities_task = tokio::task::spawn(handle_outgoing_activities(request_data)); let outgoing_activities_task = tokio::task::spawn(handle_outgoing_activities(request_data));
let server = if args.http_server { let server = if args.http_server {
if let Some(startup_server_handle) = startup_server_handle {
startup_server_handle.stop(true).await;
}
Some(create_http_server( Some(create_http_server(
federation_config.clone(), federation_config.clone(),
settings.clone(), settings.clone(),
@ -253,6 +262,26 @@ pub async fn start_lemmy_server(args: CmdArgs) -> Result<(), LemmyError> {
Ok(()) Ok(())
} }
/// Creates temporary HTTP server which returns status 503 for all requests.
fn create_startup_server() -> Result<ServerHandle, LemmyError> {
let startup_server = HttpServer::new(move || {
App::new().wrap(ErrorHandlers::new().default_handler(move |req| {
let (req, _) = req.into_parts();
let response =
HttpResponse::ServiceUnavailable().json(json!({"error": "Lemmy is currently starting"}));
let service_response = ServiceResponse::new(req, response);
Ok(ErrorHandlerResponse::Response(
service_response.map_into_right_body(),
))
}))
})
.bind((SETTINGS.bind, SETTINGS.port))?
.run();
let startup_server_handle = startup_server.handle();
tokio::task::spawn(startup_server);
Ok(startup_server_handle)
}
fn create_http_server( fn create_http_server(
federation_config: FederationConfig<LemmyContext>, federation_config: FederationConfig<LemmyContext>,
settings: Settings, settings: Settings,