diff --git a/src/chromium/rocket.rs b/src/chromium/rocket.rs index 91a7c00..3e12f7e 100644 --- a/src/chromium/rocket.rs +++ b/src/chromium/rocket.rs @@ -1,9 +1,10 @@ -use std::{sync::{Arc}, time::Duration}; +use std::{sync::Arc, time::Duration}; use async_trait::async_trait; use async_mutex::Mutex; use headless_chrome::{Browser, LaunchOptions}; -use log::{warn, error}; -use rocket::{fairing::{Fairing, self}, Rocket, Build, catcher::Result, Request, Response, request::{FromRequest, Outcome}}; +use log::{error, info}; +use rocket::{fairing::{Fairing, self}, Rocket, Build, Request, request::{FromRequest, Outcome}, futures::pin_mut, http::Status}; +use tokio::time::sleep; #[derive(Default)] pub struct Chromium { @@ -32,7 +33,6 @@ impl Fairing for Chromium { async fn on_ignite(&self, rocket: Rocket) -> fairing::Result { let new_rocket = rocket.manage(ChromiumCoordinator::new().await); let coordinator = new_rocket.state::().unwrap(); - error!("{:p}", &coordinator); Ok(new_rocket) } } @@ -41,61 +41,60 @@ pub struct ChromiumCoordinator { } impl ChromiumCoordinator { - const NUMBER_OF_INSTANCES: usize = 1; + const NUMBER_OF_INSTANCES: usize = 10; pub async fn new() -> Self { - error!("ChromiumCoordinator::new()"); let instances: Arc>> = Arc::new(Mutex::new(Vec::with_capacity(Self::NUMBER_OF_INSTANCES))); while instances.lock().await.len() < Self::NUMBER_OF_INSTANCES { - instances.lock().await.push(BrowserHolder { browser: Browser::new(LaunchOptions { - idle_browser_timeout: Duration::from_secs(1), // Wait inifinity for commands - ..LaunchOptions::default() - }).unwrap() }); + instances.lock().await.push(Self::create_browser_instance()); } Self { instances } } + fn create_browser_instance() -> BrowserHolder { + BrowserHolder { browser: Browser::new(LaunchOptions { + idle_browser_timeout: Duration::MAX, // Wait inifinity for commands + ..LaunchOptions::default() + }).unwrap() } + } + fn spawn_browser(&self) { let instances = self.instances.clone(); tokio::spawn(async move { - error!("Spawn new instance of browser"); + info!("Spawn new instance of browser"); // Create new instance - let browser = Browser::new(LaunchOptions::default()).unwrap(); - instances.lock().await.push( BrowserHolder {browser }); + instances.lock().await.push(Self::create_browser_instance()); }); } - fn try_get_instance(&self) -> Option { + async fn try_get_instance(&self) -> Option { let mut instances = self.instances.lock().await; if instances.len() == 0 { return None; } + self.spawn_browser(); Some(instances.remove(0)) } - pub async fn try_get_browser(&self) -> std::result::Result { - let instances = self.instances.clone(); - - let mut loop_count = 0; - - while instances.lock().await.len() == 0 { - warn!("Waiting for Chromium instances to start..."); - std::thread::sleep(std::time::Duration::from_millis(100)); - if loop_count > 100 * 10 * 60 { - panic!("Can't start Chromium instances"); + async fn loop_get_instance(&self) -> BrowserHolder { + loop { + match self.try_get_instance().await { + Some(instance) => { + return instance + } + None => { + sleep(std::time::Duration::from_millis(100)).await; } - loop_count += 1; } + } + } - let browser = self.instances.lock().await.remove(0); - self.spawn_browser(); - // test connection state + pub async fn try_get_browser(&self) -> std::result::Result { + let browser = self.loop_get_instance().await; match browser.browser.get_version() { Ok(_) => Ok(browser), - Err(_) => { - Err(()) - } + Err(_) => Err(()), } } @@ -103,7 +102,9 @@ impl ChromiumCoordinator { loop { match self.try_get_browser().await { Ok(browser) => return Ok(browser), - Err(_) => {} // all instances may be dead ... we must wait for new instance + Err(_) => { + // all instances may be dead ... we must wait for new instance + } } } } @@ -119,9 +120,23 @@ impl<'r> FromRequest<'r> for BrowserHolder { async fn from_request(request: &'r Request<'_>) -> Outcome { let coordinator = request.rocket().state::().unwrap(); - error!("{:p}", &coordinator); - let browser = coordinator.get_browser().await.unwrap(); - Outcome::Success(browser) + let get_instance = coordinator.get_browser(); + pin_mut!(get_instance); // TODO: wth? + let result = match tokio::time::timeout(std::time::Duration::from_secs(10), &mut get_instance).await { + Ok(maybebrowser) => match maybebrowser { + Ok(browser) => Outcome::::Success(browser), + Err(_) => { + error!("Can't create new instance of browser"); + Outcome::::Error((Status::InternalServerError, ())) + } + }, + Err(_) => { + error!("Can't create new instance of browser (timeout)"); + Outcome::::Error((Status::InternalServerError, ())) + } + }; + + result } }