html2pdf-api
Thread-safe headless browser pool for high-performance HTML to PDF conversion with native Rust web framework integration.
A production-ready Rust library for managing a pool of headless Chrome browsers to convert HTML to PDF. Designed for high-performance web APIs with built-in support for popular Rust web frameworks.
✨ Features
- 🔄 Thread-Safe Pool Management - Efficient browser reuse with RAII handles
- ❤️ Automatic Health Monitoring - Background health checks with automatic browser retirement
- ⏰ TTL-Based Lifecycle - Configurable browser time-to-live prevents memory leaks
- 🚀 Production-Ready - Comprehensive error handling and graceful shutdown
- 🌐 Framework Integration - First-class support for Actix-web, Rocket, and Axum
- 🔧 Flexible Configuration - Environment variables, config files, or direct configuration
- 📊 Pool Statistics - Real-time metrics for monitoring
- 🎯 Cross-Platform - Works on Linux, macOS, and Windows
Installation
Add to your Cargo.toml:
[]
= "0.1"
Feature Flags
| Feature | Description | Default |
|---|---|---|
env-config |
Load configuration from environment variables | Yes |
actix-integration |
Actix-web framework support | No |
rocket-integration |
Rocket framework support | No |
axum-integration |
Axum framework support | No |
test-utils |
Mock factory for testing | No |
Enable features as needed:
[]
= { = "0.1", = ["actix-integration", "env-config"] }
Quick Start
Basic Usage
use *;
use Duration;
async
Environment Configuration
Enable the env-config feature for simpler initialization:
use init_browser_pool;
async
Environment Variables
| Variable | Type | Default | Description |
|---|---|---|---|
BROWSER_POOL_SIZE |
usize | 5 | Maximum browsers in pool |
BROWSER_WARMUP_COUNT |
usize | 3 | Browsers to pre-create on startup |
BROWSER_TTL_SECONDS |
u64 | 3600 | Browser lifetime before retirement |
BROWSER_WARMUP_TIMEOUT_SECONDS |
u64 | 60 | Maximum warmup duration |
BROWSER_PING_INTERVAL_SECONDS |
u64 | 15 | Health check frequency |
BROWSER_MAX_PING_FAILURES |
u32 | 3 | Failures before browser removal |
CHROME_PATH |
String | auto | Custom Chrome/Chromium binary path |
Web Framework Integration
Actix-web
use ;
use *;
async
async
Rocket
use ;
use *;
async
async
Axum
use ;
use *;
async
async
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) │
└─────────────────────────────────────────────┘
Key Design Decisions
- RAII Pattern: Browsers are automatically returned to the pool when
BrowserHandleis dropped - Lock Ordering: Strict lock ordering (active → available) prevents deadlocks
- Health Checks: Lock-free health checks avoid blocking other operations
- Staggered Warmup: TTLs are offset to prevent simultaneous browser expiration
- Graceful Shutdown: Condvar signaling enables immediate shutdown response
⚙️ Configuration Guide
Recommended Production Settings
use Duration;
use BrowserPoolConfigBuilder;
let config = new
.max_pool_size // Adjust based on load
.warmup_count // Pre-warm half the pool
.browser_ttl // 1 hour lifetime
.ping_interval // Check every 30s
.max_ping_failures // Tolerate transient failures
.warmup_timeout // 2 min warmup limit
.build?;
Custom Chrome Path
use ChromeBrowserFactory;
// Linux
let factory = with_path;
// macOS
let factory = with_path;
// Windows
let factory = with_path;
Testing
Use the test-utils feature for testing without Chrome:
use MockBrowserFactory;
// Factory that always fails (for error handling tests)
let factory = always_fails;
// Factory that fails after N creations (for exhaustion tests)
let factory = fail_after_n;
let pool = builder
.factory
.enable_keep_alive // Disable for faster tests
.build?;
Monitoring
let stats = pool.stats;
println!;
println!;
println!;
// For metrics systems
gauge!;
gauge!;
❗ Error Handling
use ;
match pool.get
Requirements
- Rust: 1.85 or later
- Tokio: Runtime required for async operations
Chrome/Chromium
No installation required!
The library automatically downloads a compatible Chromium binary if Chrome is not detected on your system. Downloaded binaries are cached for future use:
| Platform | Cache Location |
|---|---|
| Linux | ~/.local/share/headless-chrome |
| macOS | ~/Library/Application Support/headless-chrome |
| Windows | C:\Users\<User>\AppData\Roaming\headless-chrome\data |
First run: May take a few minutes to download Chromium (~170MB)
Subsequent runs: Uses cached version instantly
Chrome/Chromium - Manual Installation (Optional)
While not required, you can install Chrome manually if preferred:
Ubuntu/Debian:
macOS:
Windows: Download from google.com/chrome
Examples
See the examples directory for complete working examples:
actix_web_example.rs- Actix-web integrationrocket_example.rs- Rocket integrationaxum_example.rs- Axum integration
Run examples:
# Actix-web
# Rocket
# Axum
Contributing
Contributions are welcome! Please see CONTRIBUTING.md for guidelines.
License
Licensed:
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
Acknowledgments
This crate builds upon the excellent headless_chrome crate.