Atomically acquires a proxy session for a task. Under a per-fingerprint lock, this method: 1. Ensures the proxy container is running and healthy 2. Creates an isolated agent network 3. Connects the proxy to the agent network 4. Resolves the proxy IP on the agent network This prevents the TOCTOU race between proxy shutdown and startup that can occur when multiple tasks share the same proxy contai
(
&self,
task_id: &str,
proxy_config: &ResolvedProxyConfig,
logger: &TaskLogger,
)
| 430 | /// This prevents the TOCTOU race between proxy shutdown and startup that can |
| 431 | /// occur when multiple tasks share the same proxy container. |
| 432 | pub async fn acquire_proxy( |
| 433 | &self, |
| 434 | task_id: &str, |
| 435 | proxy_config: &ResolvedProxyConfig, |
| 436 | logger: &TaskLogger, |
| 437 | ) -> Result<ProxySession> { |
| 438 | let fingerprint = proxy_config.fingerprint(); |
| 439 | // Clone values needed inside the closure (proxy_config fields are used by reference) |
| 440 | let task_id = task_id.to_string(); |
| 441 | let proxy_config = proxy_config.clone(); |
| 442 | |
| 443 | self.sync_manager |
| 444 | .with_lock(&fingerprint, || async { |
| 445 | let proxy_container_name = self.ensure_proxy(&proxy_config, logger).await?; |
| 446 | |
| 447 | let network_name = self.create_agent_network(&task_id).await?; |
| 448 | |
| 449 | if let Err(e) = self |
| 450 | .connect_proxy_to_network(&proxy_container_name, &network_name) |
| 451 | .await |
| 452 | { |
| 453 | // Clean up the network we just created before returning error |
| 454 | self.cleanup_agent_network(&proxy_container_name, &network_name) |
| 455 | .await; |
| 456 | return Err(e); |
| 457 | } |
| 458 | |
| 459 | let proxy_ip = match self |
| 460 | .resolve_proxy_ip(&proxy_container_name, &network_name) |
| 461 | .await |
| 462 | { |
| 463 | Ok(ip) => Some(ip), |
| 464 | Err(e) => { |
| 465 | logger.log(LogLine::tsk_warning(format!( |
| 466 | "Warning: Could not resolve proxy IP for extra_hosts: {e}" |
| 467 | ))); |
| 468 | None |
| 469 | } |
| 470 | }; |
| 471 | |
| 472 | Ok(ProxySession { |
| 473 | proxy_container_name, |
| 474 | network_name, |
| 475 | proxy_ip, |
| 476 | fingerprint: fingerprint.clone(), |
| 477 | }) |
| 478 | }) |
| 479 | .await |
| 480 | } |
| 481 | |
| 482 | /// Atomically releases a proxy session for a task. |
| 483 | /// |