Expand description
§html2pdf-api
Thread-safe browser pool for headless Chrome automation with web framework integration.
This crate provides a production-ready browser pool that manages headless Chrome/Chromium instances with automatic lifecycle management, health monitoring, and graceful shutdown.
§Features
- Connection Pooling: Reuses browser instances to avoid expensive startup costs
- Health Monitoring: Background thread continuously checks browser health
- TTL Management: Automatically retires old browsers and creates replacements
- Race-Free Design: Careful lock ordering prevents deadlocks
- Graceful Shutdown: Clean termination of all background tasks
- RAII Pattern: Automatic return of browsers to pool via Drop
- Web Framework Integration: Optional support for Actix-web, Rocket, and Axum
§Architecture
┌─────────────────────────────────────────────┐
│ Your Web Application │
│ (Actix-web / Rocket / Axum) │
└─────────────────┬───────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ BrowserPool │
│ ┌─────────────────────────────────────────┐ │
│ │ Available Pool (idle browsers) │ │
│ │ [Browser1] [Browser2] [Browser3] │ │
│ └─────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────┐ │
│ │ Active Tracking (in-use browsers) │ │
│ │ {id → Browser} │ │
│ └─────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────┐ │
│ │ Keep-Alive Thread │ │
│ │ (health checks + TTL enforcement) │ │
│ └─────────────────────────────────────────┘ │
└─────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ Headless Chrome Browsers │
│ (managed by headless_chrome crate) │
└─────────────────────────────────────────────┘§Quick Start
ⓘ
use html2pdf_api::prelude::*;
use std::time::Duration;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create pool with custom configuration
let pool = BrowserPool::builder()
.config(
BrowserPoolConfigBuilder::new()
.max_pool_size(5)
.warmup_count(3)
.browser_ttl(Duration::from_secs(3600))
.build()?
)
.factory(Box::new(ChromeBrowserFactory::with_defaults()))
.build()?;
// Warmup the pool (recommended for production)
pool.warmup().await?;
// Use browsers
{
let browser = pool.get()?;
let tab = browser.new_tab()?;
tab.navigate_to("https://example.com")?;
// ... generate PDF, take screenshot, etc.
} // Browser automatically returned to pool
// Graceful shutdown
pool.shutdown_async().await;
Ok(())
}§Environment Configuration
When the env-config feature is enabled, you can initialize the pool
from environment variables (loaded from app.env file or system environment):
use html2pdf_api::init_browser_pool;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let pool = init_browser_pool().await?;
// pool is Arc<Mutex<BrowserPool>>, ready for web handlers
Ok(())
}§Environment File
Create an app.env file in your project root (not .env for better
cross-platform visibility):
BROWSER_POOL_SIZE=5
BROWSER_WARMUP_COUNT=3
BROWSER_TTL_SECONDS=3600§Environment Variables
| Variable | Type | Default | Description |
|---|---|---|---|
BROWSER_POOL_SIZE | usize | 5 | Maximum browsers in pool |
BROWSER_WARMUP_COUNT | usize | 3 | Browsers to pre-create |
BROWSER_TTL_SECONDS | u64 | 3600 | Browser lifetime (seconds) |
BROWSER_WARMUP_TIMEOUT_SECONDS | u64 | 60 | Warmup timeout |
BROWSER_PING_INTERVAL_SECONDS | u64 | 15 | Health check interval |
BROWSER_MAX_PING_FAILURES | u32 | 3 | Failures before removal |
CHROME_PATH | String | auto | Custom Chrome binary path |
§Feature Flags
| Feature | Description |
|---|---|
env-config | Enable environment-based configuration |
actix-integration | Actix-web framework integration |
rocket-integration | Rocket framework integration |
axum-integration | Axum framework integration |
test-utils | Enable mock factory for testing |
§Web Framework Integration
§Actix-web
ⓘ
use actix_web::{web, App, HttpServer};
use html2pdf_api::prelude::*;
async fn generate_pdf(
pool: web::Data<Arc<Mutex<BrowserPool>>>,
) -> impl Responder {
let pool = pool.lock().unwrap();
let browser = pool.get()?;
// ... use browser
}§Rocket
ⓘ
use rocket::State;
use html2pdf_api::prelude::*;
#[get("/pdf")]
async fn generate_pdf(
pool: &State<Arc<Mutex<BrowserPool>>>,
) -> Result<Vec<u8>, Status> {
let pool = pool.lock().unwrap();
let browser = pool.get()?;
// ... use browser
}§Axum
ⓘ
use axum::{Extension, response::IntoResponse};
use html2pdf_api::prelude::*;
async fn generate_pdf(
Extension(pool): Extension<Arc<Mutex<BrowserPool>>>,
) -> impl IntoResponse {
let pool = pool.lock().unwrap();
let browser = pool.get()?;
// ... use browser
}§Error Handling
All fallible operations return Result<T, BrowserPoolError>.
The error type provides context about what went wrong:
ⓘ
use html2pdf_api::{BrowserPool, BrowserPoolError};
match pool.get() {
Ok(browser) => {
// Use browser
}
Err(BrowserPoolError::ShuttingDown) => {
// Pool is shutting down, handle gracefully
}
Err(BrowserPoolError::BrowserCreation(msg)) => {
// Chrome failed to launch
eprintln!("Browser creation failed: {}", msg);
}
Err(e) => {
// Other errors
eprintln!("Pool error: {}", e);
}
}§Testing
For testing without Chrome, enable the test-utils feature and use
MockBrowserFactory:
ⓘ
use html2pdf_api::factory::mock::MockBrowserFactory;
let factory = MockBrowserFactory::always_fails("Test error");
let pool = BrowserPool::builder()
.factory(Box::new(factory))
.enable_keep_alive(false)
.build()?;Re-exports§
pub use config::BrowserPoolConfig;pub use config::BrowserPoolConfigBuilder;pub use error::BrowserPoolError;pub use error::Result;pub use factory::BrowserFactory;pub use factory::ChromeBrowserFactory;pub use factory::create_chrome_options;pub use handle::BrowserHandle;pub use pool::BrowserPool;pub use pool::BrowserPoolBuilder;pub use stats::PoolStats;pub use traits::Healthcheck;pub use config::env::chrome_path_from_env;pub use config::env::from_env;pub use pool::init_browser_pool;
Modules§
- config
- Configuration for browser pool behavior and limits.
- error
- Error types for the browser pool.
- factory
- Browser factory implementations.
- handle
- RAII handle for browser instances.
- integrations
- Web framework integrations.
- pool
- Browser pool with lifecycle management.
- prelude
- Convenient imports for common usage patterns.
- service
- Core PDF generation service.
- stats
- Pool statistics for monitoring and health checks.
- traits
- Traits for abstraction and extensibility.
Type Aliases§
- Shared
Browser Pool - Shared browser pool type for web frameworks.