@@ -7,7 +7,8 @@ mod ui_state;
77#[ cfg( test) ]
88pub use self :: app_state:: tests;
99pub use self :: ui_state:: {
10- Status , StatusLevel , SubscriptionState , UiPlatformState , UiState , WebhookUrlType ,
10+ DatabaseStatus , Status , StatusLevel , SubscriptionState , UiPlatformState , UiState ,
11+ WebhookUrlType ,
1112} ;
1213
1314use crate :: {
@@ -27,8 +28,8 @@ pub use app_state::AppState;
2728use handlers:: SecutilsOpenApi ;
2829use serde_json:: json;
2930use sqlx:: postgres:: PgPoolOptions ;
30- use std:: sync:: Arc ;
31- use tracing:: info;
31+ use std:: { sync:: Arc , time :: Duration } ;
32+ use tracing:: { info, warn } ;
3233use tracing_actix_web:: TracingLogger ;
3334use utoipa:: OpenApi ;
3435use utoipa_rapidoc:: RapiDoc ;
@@ -57,22 +58,43 @@ pub async fn run(config: Config, http_port: u16) -> Result<(), anyhow::Error> {
5758 config. db. port,
5859 urlencoding:: encode( & config. db. name)
5960 ) ;
60- let database = Database :: create (
61- PgPoolOptions :: new ( )
62- . max_connections ( config. db . max_connections )
63- . min_connections ( config. db . min_connections )
64- . acquire_timeout ( config. db . acquire_timeout )
65- . max_lifetime ( config. db . max_lifetime )
66- . idle_timeout ( config. db . idle_timeout )
67- . test_before_acquire ( true )
68- . connect ( & db_url)
69- . await ?,
70- )
71- . await ?;
61+ let pool_options = PgPoolOptions :: new ( )
62+ . max_connections ( config. db . max_connections )
63+ . min_connections ( config. db . min_connections )
64+ . acquire_timeout ( config. db . acquire_timeout )
65+ . max_lifetime ( config. db . max_lifetime )
66+ . idle_timeout ( config. db . idle_timeout )
67+ . test_before_acquire ( true ) ;
68+
69+ let pool = {
70+ const MAX_RETRIES : u32 = 5 ;
71+ let mut attempt = 0 ;
72+ loop {
73+ match pool_options. clone ( ) . connect ( & db_url) . await {
74+ Ok ( pool) => break pool,
75+ Err ( err) => {
76+ attempt += 1 ;
77+ if attempt >= MAX_RETRIES {
78+ return Err ( err) . context ( format ! (
79+ "Failed to connect to database after {MAX_RETRIES} attempts"
80+ ) ) ;
81+ }
82+
83+ let delay = Duration :: from_secs ( 1 << attempt. min ( 4 ) ) ;
84+ warn ! (
85+ attempt,
86+ max_retries = MAX_RETRIES ,
87+ "Failed to connect to database: {err}. Retrying in {delay:?}…"
88+ ) ;
89+ tokio:: time:: sleep ( delay) . await ;
90+ }
91+ }
92+ }
93+ } ;
7294
7395 let api = Arc :: new ( Api :: new (
7496 config. clone ( ) ,
75- database ,
97+ Database :: create ( pool ) . await ? ,
7698 search_index,
7799 Network :: create ( & config) ?,
78100 create_templates ( ) ?,
0 commit comments