Server tools to backfill, tail, mirror, and verify PLC logs
49
fork

Configure Feed

Select the types of activity you want to include in your feed.

keep track of pg connection tasks

phil fbf7f9b4 d44a5513

+41 -59
+41 -59
src/plc_pg.rs
··· 4 4 use std::path::PathBuf; 5 5 use std::pin::pin; 6 6 use std::time::Instant; 7 - use tokio::sync::{mpsc, oneshot}; 7 + use tokio::{ 8 + task::{spawn, JoinHandle}, 9 + sync::{mpsc, oneshot}, 10 + }; 8 11 use tokio_postgres::{ 9 12 Client, Error as PgError, NoTls, 10 13 binary_copy::BinaryCopyInWriter, 11 14 connect, 15 + Socket, 12 16 types::{Json, Type}, 17 + tls::MakeTlsConnect 13 18 }; 14 19 15 - fn get_tls(cert: PathBuf) -> MakeTlsConnector { 16 - let cert = std::fs::read(cert).expect("to read cert file"); 17 - let cert = Certificate::from_pem(&cert).expect("to build cert"); 18 - let connector = TlsConnector::builder() 19 - .add_root_certificate(cert) 20 - .build() 21 - .expect("to build tls connector"); 22 - MakeTlsConnector::new(connector) 20 + fn get_tls(cert: PathBuf) -> anyhow::Result<MakeTlsConnector> { 21 + let cert = std::fs::read(cert)?; 22 + let cert = Certificate::from_pem(&cert)?; 23 + let connector = TlsConnector::builder().add_root_certificate(cert).build()?; 24 + Ok(MakeTlsConnector::new(connector)) 25 + } 26 + 27 + async fn get_client_and_task<T>( 28 + uri: &str, 29 + connector: T, 30 + ) -> Result<(Client, JoinHandle<Result<(), PgError>>), PgError> 31 + where 32 + T: MakeTlsConnect<Socket>, 33 + <T as MakeTlsConnect<Socket>>::Stream: Send + 'static, 34 + { 35 + let (client, connection) = connect(uri, connector).await?; 36 + Ok((client, spawn(connection))) 23 37 } 24 38 25 39 /// a little tokio-postgres helper 26 40 /// 27 41 /// it's clone for easiness. it doesn't share any resources underneath after 28 - /// cloning at all so it's not meant for 42 + /// cloning *at all* so it's not meant for eg. handling public web requests 29 43 #[derive(Clone)] 30 44 pub struct Db { 31 45 pg_uri: String, ··· 38 52 // it's what we expect: check for db migrations. 39 53 log::trace!("checking migrations..."); 40 54 41 - let connector = cert.map(get_tls); 55 + let connector = cert.map(get_tls).transpose()?; 42 56 43 - let (client, connection_task) = if let Some(ref connector) = connector { 44 - let (client, connection) = connect(pg_uri, connector.clone()).await?; 45 - let task = tokio::task::spawn(async move { 46 - connection 47 - .await 48 - .inspect_err(|e| log::error!("connection ended with error: {e}")) 49 - .expect("pg validation connection not to blow up"); 50 - }); 51 - (client, task) 57 + let (client, conn_task) = if let Some(ref connector) = connector { 58 + get_client_and_task(pg_uri, connector.clone()).await? 52 59 } else { 53 - let (client, connection) = connect(pg_uri, NoTls).await?; 54 - let task = tokio::task::spawn(async move { 55 - connection 56 - .await 57 - .inspect_err(|e| log::error!("connection ended with error: {e}")) 58 - .expect("pg validation connection not to blow up"); 59 - }); 60 - (client, task) 60 + get_client_and_task(pg_uri, NoTls).await? 61 61 }; 62 62 63 63 let migrations: Vec<String> = client ··· 77 77 ); 78 78 drop(client); 79 79 // make sure the connection worker thing doesn't linger 80 - connection_task.await?; 80 + conn_task.await??; 81 81 log::info!("db connection succeeded and plc migrations appear as expected"); 82 82 83 83 Ok(Self { ··· 86 86 }) 87 87 } 88 88 89 - pub async fn connect(&self) -> Result<Client, PgError> { 89 + #[must_use] 90 + pub async fn connect(&self) -> Result<(Client, JoinHandle<Result<(), PgError>>), PgError> { 90 91 log::trace!("connecting postgres..."); 91 - let client = if let Some(ref connector) = self.cert { 92 - let (client, connection) = connect(&self.pg_uri, connector.clone()).await?; 93 - 94 - // send the connection away to do the actual communication work 95 - // apparently the connection will complete when the client drops 96 - tokio::task::spawn(async move { 97 - connection 98 - .await 99 - .inspect_err(|e| log::error!("connection ended with error: {e}")) 100 - .expect("pg connection not to blow up"); 101 - }); 102 - client 92 + if let Some(ref connector) = self.cert { 93 + get_client_and_task(&self.pg_uri, connector.clone()).await 103 94 } else { 104 - let (client, connection) = connect(&self.pg_uri, NoTls).await?; 105 - 106 - // send the connection away to do the actual communication work 107 - // apparently the connection will complete when the client drops 108 - tokio::task::spawn(async move { 109 - connection 110 - .await 111 - .inspect_err(|e| log::error!("connection ended with error: {e}")) 112 - .expect("pg connection not to blow up"); 113 - }); 114 - client 115 - }; 116 - 117 - Ok(client) 95 + get_client_and_task(&self.pg_uri, NoTls).await 96 + } 118 97 } 119 98 120 99 pub async fn get_latest(&self) -> Result<Option<Dt>, PgError> { 121 - let client = self.connect().await?; 100 + let (client, task) = self.connect().await?; 122 101 let dt: Option<Dt> = client 123 102 .query_opt( 124 103 r#"SELECT "createdAt" ··· 129 108 ) 130 109 .await? 131 110 .map(|row| row.get(0)); 111 + drop(task); 132 112 Ok(dt) 133 113 } 134 114 } ··· 137 117 db: Db, 138 118 mut pages: mpsc::Receiver<ExportPage>, 139 119 ) -> anyhow::Result<&'static str> { 140 - let mut client = db.connect().await?; 120 + let (mut client, task) = db.connect().await?; 141 121 142 122 let ops_stmt = client 143 123 .prepare( ··· 174 154 } 175 155 tx.commit().await?; 176 156 } 157 + drop(task); 177 158 178 159 log::info!( 179 160 "no more pages. inserted {ops_inserted} ops and {dids_inserted} dids in {:?}", ··· 201 182 mut pages: mpsc::Receiver<ExportPage>, 202 183 notify_last_at: Option<oneshot::Sender<Option<Dt>>>, 203 184 ) -> anyhow::Result<&'static str> { 204 - let mut client = db.connect().await?; 185 + let (mut client, task) = db.connect().await?; 205 186 206 187 let t0 = Instant::now(); 207 188 let tx = client.transaction().await?; ··· 316 297 log::trace!("set tables LOGGED: {:?}", t_step.elapsed()); 317 298 318 299 tx.commit().await?; 300 + drop(task); 319 301 log::info!("total backfill time: {:?}", t0.elapsed()); 320 302 321 303 Ok("backfill_to_pg")