html2pdf_api/traits/healthcheck.rs
1//! Health check trait for browser instances.
2//!
3//! This module provides the [`Healthcheck`] trait, which defines how
4//! browser instances verify they are still functional and responsive.
5//!
6//! # Overview
7//!
8//! The browser pool periodically pings active browsers to detect failures.
9//! When a browser fails too many consecutive health checks, it is removed
10//! from the pool and replaced.
11//!
12//! # Default Implementation
13//!
14//! [`TrackedBrowser`](crate::TrackedBrowser) implements this trait by:
15//! 1. Creating a new tab
16//! 2. Closing the tab
17//! 3. Updating the last ping timestamp
18//!
19//! This is a lightweight operation that verifies the browser process
20//! is alive and the CDP (Chrome DevTools Protocol) connection works.
21
22use crate::error::Result;
23
24/// Trait for browser-like objects that support health checking.
25///
26/// Implementors must provide a [`ping()`](Self::ping) method that verifies
27/// the browser is still functional and responsive.
28///
29/// # Thread Safety
30///
31/// This trait requires `Send + Sync` because browsers may be health-checked
32/// from a background thread while being used from another thread.
33///
34/// # Example Implementation
35///
36/// ```rust,ignore
37/// use html2pdf_api::{Healthcheck, Result, BrowserPoolError};
38///
39/// struct MyBrowser {
40/// inner: SomeBrowserType,
41/// }
42///
43/// impl Healthcheck for MyBrowser {
44/// fn ping(&self) -> Result<()> {
45/// // Try to create a tab to verify browser is responsive
46/// let tab = self.inner.new_tab()
47/// .map_err(|e| BrowserPoolError::HealthCheckFailed(e.to_string()))?;
48///
49/// // Clean up
50/// let _ = tab.close();
51///
52/// Ok(())
53/// }
54/// }
55/// ```
56///
57/// # How It's Used
58///
59/// The browser pool's keep-alive thread calls `ping()` on all active browsers
60/// at regular intervals (configured via
61/// [`ping_interval`](crate::BrowserPoolConfig::ping_interval)).
62///
63/// ```text
64/// Keep-Alive Thread
65/// │
66/// ├─── ping() ──→ Browser 1 ──→ ✓ OK
67/// │
68/// ├─── ping() ──→ Browser 2 ──→ ✗ Failed (count: 1)
69/// │
70/// └─── ping() ──→ Browser 3 ──→ ✓ OK
71/// ```
72///
73/// After [`max_ping_failures`](crate::BrowserPoolConfig::max_ping_failures)
74/// consecutive failures, the browser is removed and replaced.
75pub trait Healthcheck: Send + Sync {
76 /// Perform a health check on the browser.
77 ///
78 /// Should perform a lightweight operation like creating/closing a tab
79 /// to verify the browser process is still responsive.
80 ///
81 /// # Implementation Guidelines
82 ///
83 /// - **Keep it fast**: Health checks run frequently; avoid heavy operations
84 /// - **Don't hold locks**: Release any locks before performing I/O
85 /// - **Be idempotent**: Multiple calls should be safe
86 /// - **Clean up**: Close any tabs or resources created during the check
87 ///
88 /// # Errors
89 ///
90 /// Returns [`BrowserPoolError::HealthCheckFailed`](crate::BrowserPoolError::HealthCheckFailed)
91 /// if the health check fails (browser unresponsive or crashed).
92 ///
93 /// # Example
94 ///
95 /// ```rust,ignore
96 /// use html2pdf_api::{Healthcheck, Result};
97 ///
98 /// fn check_browser_health<T: Healthcheck>(browser: &T) -> Result<()> {
99 /// browser.ping()?;
100 /// println!("Browser is healthy!");
101 /// Ok(())
102 /// }
103 /// ```
104 fn ping(&self) -> Result<()>;
105}