/* This file is part of TALER Copyright (C) 2022 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. TALER is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with TALER; see the file COPYING. If not, see */ use std::time::Duration; use log::error; use postgres::{Client, NoTls}; const RECONNECT_DELAY: Duration = Duration::from_secs(5); pub struct AutoReconnect { config: S, client: C, connect: fn(&S) -> Option, check: fn(&mut C) -> bool, } impl AutoReconnect { pub fn new(config: S, connect: fn(&S) -> Option, check: fn(&mut C) -> bool) -> Self { Self { client: Self::connect(&config, connect), connect, check, config, } } /// Create a new client, loop on error fn connect(config: &S, connect: fn(&S) -> Option) -> C { loop { match connect(config) { Some(new) => return new, None => std::thread::sleep(RECONNECT_DELAY), } } } /// Get a mutable connection, block until a connection can be established pub fn client(&mut self) -> &mut C { if (self.check)(&mut self.client) { self.client = Self::connect(&self.config, self.connect); } &mut self.client } } pub type AutoReconnectDb = AutoReconnect; pub fn auto_reconnect_db(config: postgres::Config) -> AutoReconnectDb { AutoReconnect::new( config, |config| { config .connect(NoTls) .map_err(|err| error!("connect DB: {}", err)) .ok() }, |client| client.is_valid(RECONNECT_DELAY).is_err(), ) }