(state: &Proxy, instance_id: &str)
| 165 | } |
| 166 | |
| 167 | async fn fetch_with_retry(state: &Proxy, instance_id: &str) { |
| 168 | let cfg = &state.config.proxy.port_policy_fetch; |
| 169 | let mut attempt = 0u32; |
| 170 | let mut backoff = cfg.backoff_initial; |
| 171 | loop { |
| 172 | let result = |
| 173 | match tokio::time::timeout(cfg.timeout, fetch_and_store(state, instance_id)).await { |
| 174 | Ok(r) => r, |
| 175 | // The Info() RPC took too long. Treat as transient — the CVM |
| 176 | // may just be slow to come up. |
| 177 | Err(_) => Err(FetchError::Transient(anyhow::anyhow!( |
| 178 | "Info() rpc timed out after {:?}", |
| 179 | cfg.timeout |
| 180 | ))), |
| 181 | }; |
| 182 | match result { |
| 183 | Ok(()) => { |
| 184 | debug!("port_policy cached for instance {instance_id} (attempt {attempt})"); |
| 185 | return; |
| 186 | } |
| 187 | Err(FetchError::Permanent(err)) => { |
| 188 | // Either the instance was recycled while queued, or the |
| 189 | // agent responded with data we can't parse. Retrying won't |
| 190 | // change either; bail. |
| 191 | debug!("port_policy fetch for {instance_id}: permanent failure: {err:#}"); |
| 192 | return; |
| 193 | } |
| 194 | Err(FetchError::Transient(err)) => { |
| 195 | warn!("port_policy fetch for {instance_id} failed (attempt {attempt}): {err:#}"); |
| 196 | } |
| 197 | } |
| 198 | if attempt >= cfg.max_retries { |
| 199 | warn!( |
| 200 | "port_policy fetch for {instance_id} giving up after {} attempts", |
| 201 | attempt + 1 |
| 202 | ); |
| 203 | return; |
| 204 | } |
| 205 | tokio::time::sleep(backoff).await; |
| 206 | attempt += 1; |
| 207 | backoff = (backoff * 2).min(cfg.backoff_max); |
| 208 | } |
| 209 | } |
| 210 | |
| 211 | async fn fetch_and_store(state: &Proxy, instance_id: &str) -> Result<(), FetchError> { |
| 212 | let (ip, agent_port) = { |
no test coverage detected