7 releases (4 breaking)

0.5.1 May 4, 2024
0.5.0 Mar 18, 2024
0.4.0 Feb 11, 2024
0.3.1 Jan 27, 2024
0.1.1 Feb 23, 2023

#426 in Unix APIs

MIT/Apache

19KB
246 lines

Docs

Prefork

Fork a process in Rust to create multiple child processes.

This repository contains a Rust crate. See the example code which opens a socket and then forks multiple processes that accept connections on that socket. This is an old fashioned way of multiprocessing, but it is sometimes useful when dealing with systems that run poorly when multi-threaded (e.g. when embedding a Python interpreter).

Contributing

Issues and PRs are welcome. It is possible to login with a Github user id.

This repository is mirrored on codeberg.


lib.rs:

Support for preforking servers.

Preforking is an old fashioned way of multiprocessing, but it is sometimes useful when dealing with systems that run poorly when multi-threaded (e.g. when embedding a Python interpreter).

Features

By default, the crate includes tokio as a dependency to launch async servers. If tokio is not needed, include prefork as a dependency without default features:

[dependencies]
prefork = {version = "...", default-features = false}

Example

This example opens a socket and then forks multiple processes that accept connections on that socket. To run the example, see examples/axum.rs in the code repository:

cargo run --example axum

Webserver example:

use std::{net::TcpListener, process};

use axum::{extract::State, routing::get, Router};

use log::info;
use prefork::Prefork;

async fn child(child_num: u32, listener: TcpListener) {
    let pid = process::id();
    let router = Router::new()
        .route(
            "/",
            get(|State((pid, child_num))| async move {
                format!("Hello from {child_num} with pid {pid}")
            }),
        )
        .with_state((pid, child_num));
    let listener = tokio::net::TcpListener::from_std(listener)
        .expect("bind to port");
    axum::serve(listener, router).await.expect("start server");
}

fn main() {
    let listener = TcpListener::bind("0.0.0.0:3000").expect("bind to port");
    listener.set_nonblocking(true).expect("nonblocking");
    let is_parent = Prefork::from_resource(listener)
        .with_num_processes(10)
        .with_tokio(child)
        .fork()
        .expect("fork");
    if is_parent {
        info!("Parent exit");
    }
}

Dependencies

~4–12MB
~144K SLoC