use std::{
sync::{
Arc,
atomic::{AtomicUsize, Ordering},
},
time::Duration,
};
use trillium::{Conn, KnownHeaderName};
use trillium_cache::{
Cache, CacheKey, CacheStorage, FileSystemStorage, InMemoryStorage, TieredStorage,
};
use trillium_client::Client;
use trillium_http::Method;
use trillium_smol::{ClientConfig, SmolRuntime, async_global_executor, config};
fn main() {
env_logger::Builder::from_env(
env_logger::Env::default().default_filter_or("trillium_cache=trace"),
)
.init();
async_global_executor::block_on(run());
}
async fn run() {
let cache_dir = std::env::temp_dir().join("trillium-cache-tiered-example");
let _ = std::fs::remove_dir_all(&cache_dir);
let storage = TieredStorage::new(
InMemoryStorage::new(),
FileSystemStorage::new(&cache_dir),
SmolRuntime::default(),
);
let handler_runs = Arc::new(AtomicUsize::new(0));
let runs = handler_runs.clone();
let server = config()
.with_port(0)
.with_host("127.0.0.1")
.without_signals()
.spawn((Cache::new(storage), move |conn: Conn| {
let runs = runs.clone();
async move {
runs.fetch_add(1, Ordering::SeqCst);
conn.with_response_header(KnownHeaderName::CacheControl, "max-age=600")
.ok("hello from the cached handler")
}
}));
let addr = *server.info().await.tcp_socket_addr().unwrap();
println!("server listening on {addr}\n");
let client = Client::new(ClientConfig::new());
for label in ["request #1 (expect MISS)", "request #2 (expect HIT)"] {
let url = format!("http://{addr}/");
let mut conn = client.get(url.as_str()).await.expect("request failed");
let body = conn.response_body().read_string().await.expect("read body");
println!("[{label}] {body:?}");
}
println!(
"\nhandler ran {} time(s) (expected 1 — the second request was served from the hot tier)",
handler_runs.load(Ordering::SeqCst)
);
let key = CacheKey::new(Method::Get, format!("http://{addr}/").parse().unwrap());
let reopened_cold = FileSystemStorage::new(&cache_dir);
let mut committed = false;
for _ in 0..50 {
if !reopened_cold.get(&key).await.is_empty() {
committed = true;
break;
}
SmolRuntime::default()
.delay(Duration::from_millis(20))
.await;
}
println!(
"cold tier under {} {} the entry after write-back",
cache_dir.display(),
if committed {
"durably holds"
} else {
"did not receive"
}
);
server.shut_down().await;
}