Skip to content

Commit f254183

Browse files
committed
perf: Refactor code and optimize cache in main.rs and Cargo.toml
- Remove unnecessary dependencies from Cargo.toml - Optimize cache key type from String to u64 in src/main.rs - Increase cache expiration time from 60 seconds to 10 minutes - Replace logging statements with print statements in src/main.rs - Add a 3-second sleep to allow SPA content to load before fetching it
1 parent b2efd13 commit f254183

File tree

2 files changed

+36
-44
lines changed

2 files changed

+36
-44
lines changed

Cargo.toml

-3
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,3 @@ serde = { version = "1.0", features = ["derive"] }
1010
tokio = { version = "1", features = ["full"] }
1111
serde_json = "1.0"
1212
lru = "0.12"
13-
select = "0.5"
14-
log = "0.4"
15-
env_logger = "0.10"

src/main.rs

+36-41
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,22 @@ use warp::Filter;
66
use serde::Deserialize;
77
use std::collections::VecDeque;
88
use lru::LruCache;
9-
use tokio::time::{Duration, Instant};
109
use std::num::NonZeroUsize;
11-
use std::env;
12-
use log::{info, error};
10+
use std::time::{Duration, Instant};
11+
use std::collections::hash_map::DefaultHasher;
12+
use std::hash::{Hash, Hasher};
13+
14+
const CACHE_TTL: Duration = Duration::from_secs(600); // 10 minutes
1315

1416
#[tokio::main]
1517
async fn main() {
16-
env_logger::init();
17-
1818
let args: Vec<&OsStr> = vec![
1919
OsStr::new("--no-sandbox"),
2020
OsStr::new("--disable-gpu"),
2121
OsStr::new("--disable-dev-shm-usage"),
2222
OsStr::new("--headless"),
2323
OsStr::new("--disable-software-rasterizer"),
2424
OsStr::new("--no-zygote"),
25-
OsStr::new("--single-process"),
2625
];
2726

2827
let browser = Arc::new(
@@ -36,14 +35,7 @@ async fn main() {
3635

3736
let semaphore = Arc::new(Semaphore::new(4));
3837
let tab_pool = Arc::new(Mutex::new(VecDeque::new()));
39-
40-
let cache_maxsize = env::var("CACHE_MAXSIZE")
41-
.unwrap_or_else(|_| "100".to_string())
42-
.parse::<usize>()
43-
.expect("CACHE_MAXSIZE must be a positive integer");
44-
45-
let cache_size = NonZeroUsize::new(cache_maxsize).expect("CACHE_MAXSIZE must be a non-zero integer");
46-
let cache = Arc::new(Mutex::new(LruCache::new(cache_size))); // Cache max size from environment variable
38+
let cache = Arc::new(Mutex::new(LruCache::new(NonZeroUsize::new(1000).unwrap())));
4739

4840
let render_route = warp::path("html")
4941
.and(warp::query::<RenderQuery>())
@@ -53,7 +45,7 @@ async fn main() {
5345
.and(with_cache(cache.clone()))
5446
.and_then(render_handler);
5547

56-
info!("Server running on http://0.0.0.0:8080");
48+
println!("Server running on http://0.0.0.0:8080");
5749
warp::serve(render_route).run(([0, 0, 0, 0], 8080)).await;
5850
}
5951

@@ -81,8 +73,8 @@ fn with_tab_pool(
8173
}
8274

8375
fn with_cache(
84-
cache: Arc<Mutex<LruCache<String, (String, Instant)>>>,
85-
) -> impl Filter<Extract = (Arc<Mutex<LruCache<String, (String, Instant)>>>,), Error = std::convert::Infallible> + Clone {
76+
cache: Arc<Mutex<LruCache<u64, (String, Instant)>>>,
77+
) -> impl Filter<Extract = (Arc<Mutex<LruCache<u64, (String, Instant)>>>,), Error = std::convert::Infallible> + Clone {
8678
warp::any().map(move || cache.clone())
8779
}
8880

@@ -96,63 +88,66 @@ async fn render_handler(
9688
browser: Arc<Browser>,
9789
semaphore: Arc<Semaphore>,
9890
tab_pool: Arc<Mutex<VecDeque<Arc<Tab>>>>,
99-
cache: Arc<Mutex<LruCache<String, (String, Instant)>>>,
91+
cache: Arc<Mutex<LruCache<u64, (String, Instant)>>>,
10092
) -> Result<impl warp::Reply, warp::Rejection> {
10193
let _permit = semaphore.acquire().await;
10294

103-
let cache_ttl_secs = env::var("CACHE_TTL")
104-
.unwrap_or_else(|_| "60".to_string())
105-
.parse::<u64>()
106-
.expect("CACHE_TTL must be a positive integer");
107-
let cache_ttl = Duration::new(cache_ttl_secs, 0);
95+
let hash = hash_url(&query.url);
10896

109-
info!("Initial request to {}", query.url);
110-
111-
let start_time = Instant::now();
112-
97+
// Check if the response is in the cache and if it's still valid.
11398
let mut cache_guard = cache.lock().await;
114-
if let Some((content, timestamp)) = cache_guard.get(&query.url) {
115-
if timestamp.elapsed() < cache_ttl {
116-
info!("Cache hit for {}", query.url);
117-
return Ok(warp::reply::html(content.clone()));
99+
if let Some((response, timestamp)) = cache_guard.get(&hash) {
100+
if timestamp.elapsed() < CACHE_TTL {
101+
return Ok(warp::reply::html(response.clone()));
118102
}
119103
}
120104

105+
// If not, use headless_chrome to get the DOM.
106+
drop(cache_guard); // release the lock before using headless_chrome
121107
let tab = {
122108
let mut pool = tab_pool.lock().await;
123109
if let Some(tab) = pool.pop_front() {
124110
tab
125111
} else {
126112
browser.new_tab().map_err(|e| {
127-
error!("Failed to create new tab: {:?}", e);
113+
eprintln!("Failed to create new tab: {:?}", e);
128114
warp::reject::custom(CustomError)
129115
})?
130116
}
131117
};
132118

133119
tab.navigate_to(&query.url).map_err(|e| {
134-
error!("Failed to navigate to URL: {:?}", e);
120+
eprintln!("Failed to navigate to URL: {:?}", e);
135121
warp::reject::custom(CustomError)
136122
})?;
137123
tab.wait_until_navigated().map_err(|e| {
138-
error!("Failed to wait until navigated: {:?}", e);
124+
eprintln!("Failed to wait until navigated: {:?}", e);
139125
warp::reject::custom(CustomError)
140126
})?;
141127

128+
// Wait for a bit to allow SPA content to load.
129+
tokio::time::sleep(Duration::from_secs(3)).await;
130+
142131
let content = tab.get_content().map_err(|e| {
143-
error!("Failed to get content: {:?}", e);
132+
eprintln!("Failed to get content: {:?}", e);
144133
warp::reject::custom(CustomError)
145134
})?;
146135

136+
{
137+
let mut cache_guard = cache.lock().await;
138+
cache_guard.put(hash, (content.clone(), Instant::now()));
139+
}
140+
147141
{
148142
let mut pool = tab_pool.lock().await;
149143
pool.push_back(Arc::clone(&tab));
150144
}
151145

152-
cache_guard.put(query.url.clone(), (content.clone(), Instant::now()));
153-
154-
let duration = start_time.elapsed();
155-
info!("Got {} in {:?} for {}", content.len(), duration, query.url);
156-
157146
Ok(warp::reply::html(content))
158-
}
147+
}
148+
149+
fn hash_url(url: &str) -> u64 {
150+
let mut hasher = DefaultHasher::new();
151+
url.hash(&mut hasher);
152+
hasher.finish()
153+
}

0 commit comments

Comments
 (0)