| Crates.io | procref |
| lib.rs | procref |
| version | 0.1.0 |
| created_at | 2026-01-13 06:42:55.131837+00 |
| updated_at | 2026-01-13 06:42:55.131837+00 |
| description | Cross-platform process reference counting for shared service lifecycle management |
| homepage | |
| repository | https://github.com/putao520/procref |
| max_upload_size | |
| id | 2039488 |
| size | 100,066 |
Cross-platform process reference counting for shared service lifecycle management.
procref provides kernel-level reference counting to manage shared services across multiple processes. When multiple processes need to share a single service (like a database server), procref handles:
| Platform | Mechanism | Auto-cleanup on crash |
|---|---|---|
| Linux | System V Semaphore + SEM_UNDO |
✅ Kernel auto-undo |
| macOS | Mach Port send rights | ✅ Kernel auto-release |
| Windows | Named Semaphore | ✅ Handle auto-close |
Trust the kernel, not files.
Unlike file-based approaches that can leave stale state after crashes, procref uses kernel-managed primitives that are automatically cleaned up:
SEM_UNDO flag ensures kernel reverses semaphore operations on exituse procref::{SharedService, ServiceInfo, Result};
#[tokio::main]
async fn main() -> Result<()> {
// Create a shared service manager
let service = SharedService::builder("my-database")
// Called when first client connects (start the service)
.on_first_acquire(|| async {
let port = 5432;
let pid = start_database(port).await?;
Ok(ServiceInfo::new(pid, port))
})
// Called when last client disconnects (stop the service)
.on_last_release(|info| async move {
procref::process::stop(info.pid(), 5000);
Ok(())
})
// Optional: Custom health check
.on_health_check(|info| async move {
check_database_connection(info.port()).await
})
// Optional: Recovery when health check fails
.on_recover(|old_info| async move {
procref::process::stop(old_info.pid(), 1000);
let port = 5432;
let pid = start_database(port).await?;
Ok(ServiceInfo::new(pid, port))
})
.build()?;
// Acquire a reference (starts service if first client)
let handle = service.acquire().await?;
println!("Service running on port {}", handle.port());
// Use the service...
// When handle is dropped, reference is released
// If this is the last client, on_last_release is called
Ok(())
}
| Callback | When Called | Purpose |
|---|---|---|
on_first_acquire |
Count goes 0→1 | Start the service |
on_last_release |
Count goes 1→0 | Stop the service |
on_health_check |
Every acquire (except first) | Verify service is healthy |
on_recover |
Health check fails | Restart/recover the service |
use procref::process;
// Check if a process is alive
if process::is_alive(pid) {
// Process exists
}
// Graceful shutdown (SIGTERM)
process::terminate(pid);
// Forceful shutdown (SIGKILL)
process::kill(pid);
// Graceful with timeout, then forceful
process::stop(pid, 5000); // 5 second timeout
Process A starts:
1. acquire() → count becomes 1 (was 0)
2. on_first_acquire() called → service starts
3. ServiceHandle returned
Process B starts:
1. acquire() → count becomes 2
2. Health check runs
3. ServiceHandle returned
Process A exits (or crashes):
1. Kernel decrements count → becomes 1
2. (If crash, kernel handles this automatically)
Process B exits:
1. release() → count becomes 0
2. on_last_release() called → service stops
When a process crashes:
SEM_UNDO - reverses the semop() that incremented the countNo stale state. No cleanup needed. No race conditions.
┌─────────────────────────────────────────────────────────────┐
│ SharedService │
│ - Lifecycle callbacks (on_first_acquire, on_last_release) │
│ - Health check and recovery │
│ - Service info persistence │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ RefCounter trait │
│ - acquire() / release() │
│ - count() │
│ - try_lock() / unlock() (for startup coordination) │
└─────────────────────────────────────────────────────────────┘
│
┌───────────────┼───────────────┐
▼ ▼ ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ LinuxRefCounter │ │ MacOSRefCounter │ │WindowsRefCounter│
│ (System V sem) │ │ (Mach ports) │ │ (Named sem) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
MIT