mz_testdrive/action/sql_server/
connect.rs1use std::time::Duration;
11
12use anyhow::Context;
13use mz_ore::retry::{Retry, RetryResult};
14use mz_sql_server_util::{Client, Config};
15
16use crate::action::{ControlFlow, State};
17use crate::parser::BuiltinCommand;
18
19fn is_retryable_connect_error(err: &anyhow::Error) -> bool {
26 let msg = format!("{:#}", err);
29 msg.contains("40613") || msg.contains("is not currently available")
30}
31
32pub async fn run_connect(
33 mut cmd: BuiltinCommand,
34 state: &mut State,
35) -> Result<ControlFlow, anyhow::Error> {
36 let name = cmd.args.string("name")?;
37 let initial_backoff = cmd
41 .args
42 .opt_parse::<f64>("retry-initial-backoff")?
43 .map(Duration::from_secs_f64)
44 .unwrap_or(Duration::from_millis(500));
45 let clamp_backoff = cmd
46 .args
47 .opt_parse::<f64>("retry-clamp-backoff")?
48 .map(Duration::from_secs_f64)
49 .unwrap_or(Duration::from_secs(5));
50 let max_duration = cmd
51 .args
52 .opt_parse::<f64>("retry-max-duration")?
53 .map(Duration::from_secs_f64)
54 .unwrap_or(Duration::from_secs(90));
55 cmd.args.done()?;
56
57 let ado_string = cmd.input.join("\n");
58
59 let config = Config::from_ado_string(&ado_string).context("parsing ADO string")?;
60
61 let client = Retry::default()
62 .initial_backoff(initial_backoff)
63 .clamp_backoff(clamp_backoff)
64 .max_duration(max_duration)
65 .retry_async(|_| async {
66 match Client::connect(config.clone())
67 .await
68 .context("connecting to SQL server")
69 {
70 Ok(client) => RetryResult::Ok(client),
71 Err(err) if is_retryable_connect_error(&err) => {
72 println!(">> transient connect error, retrying: {:#}", err);
73 RetryResult::RetryableErr(err)
74 }
75 Err(err) => RetryResult::FatalErr(err),
76 }
77 })
78 .await?;
79 state.sql_server_clients.insert(name.clone(), client);
80
81 Ok(ControlFlow::Continue)
82}