NAME

Feersum::Runner - feersum script core

SYNOPSIS

use Feersum::Runner;
my $runner = Feersum::Runner->new(
    listen => 'localhost:5000',
    pre_fork => 0,
    quiet => 1,
    app_file => 'app.feersum',
);
$runner->run($feersum_app);

DESCRIPTION

Process manager for Feersum. Handles listen sockets, pre-forking, hot restart, TLS, daemonization, and graceful shutdown.

METHODS

Feersum::Runner->new(%params)

Returns a Feersum::Runner singleton. If called again while not running, the previous instance is replaced with a new one using the provided params.

listen

Listen address as an arrayref containing one or more address strings, e.g., listen => ['localhost:5000'], or a plain string for a single address. Formats: host:port for IPv4, [host]:port for IPv6 (e.g., ['[::1]:8080']).

Important: IPv6 addresses require reuseport AND pre_fork to be enabled, plus Perl 5.14+ with Socket IPv6 support. Without these, only IPv4 addresses are supported.

Alternatively, use host and port parameters.

pre_fork

Fork this many worker processes.

By default the app is loaded once in the parent and workers inherit it via fork (copy-on-write friendly). Set preload_app => 0 to load the app independently in each worker instead.

preload_app

Controls whether the app is loaded before or after forking workers (default: true / load before fork).

When true (default), the app and all its modules are loaded once in the parent process. Workers inherit the loaded code via fork, benefiting from OS copy-on-write memory sharing. Use after_fork to reconnect per-process resources (database handles, etc.).

When false, workers fork first and each loads the app independently. This is useful when the app has per-process initialization that cannot be deferred to after_fork, or when you want to test that module loading works in the worker environment. Requires app_file.

Feersum::Runner->new(
    pre_fork    => 4,
    preload_app => 0,
    app_file    => 'app.psgi',
    after_fork  => sub { ... },
)->run;
hot_restart

Enable generation-based hot restart. Requires app_file.

The entry process becomes a supervisor that manages "generations". Each generation is a forked child that re-runs the app file, loading the app and the modules it pulls in from scratch. On SIGHUP, a new generation is forked; if it starts successfully, the old generation is gracefully shut down via SIGQUIT. Failed restarts are rolled back (old generation continues serving).

Works with pre_fork: each generation forks its own workers. The app and the modules it loads are picked up fresh in each generation (the app file is re-run via do in a new fork, not re-done in a single long-lived process). Modules already loaded by the supervisor before run() are inherited via fork and not reloaded -- restart the supervisor to refresh those.

TLS (tls, or the flat tls_cert_file/tls_key_file) and HTTP/2 (h2) configuration is propagated to every generation, so hot restart works with HTTPS and H2.

Note that under plackup the .psgi path must also be given to plackup itself (positionally or via -a) -- app_file only tells Feersum what to re-run per generation, and plackup otherwise tries to load its own default app.psgi.

plackup -s Feersum --app-file=app.psgi --hot-restart=1 --pre-fork=4 app.psgi
kill -HUP <master-pid>   # zero-downtime restart, reloads app code
backlog

Listen socket backlog size (default: SOMAXCONN). Set to a higher value (e.g. 65535) if the kernel's somaxconn is tuned above the compile-time SOMAXCONN constant. The kernel silently clamps to its own maximum.

keepalive

Enable/disable http keepalive requests.

reverse_proxy

Enable reverse proxy mode. When enabled, Feersum trusts X-Forwarded-For and X-Forwarded-Proto headers from upstream proxies:

  • REMOTE_ADDR is set to the first IP in X-Forwarded-For (the original client)

  • psgi.url_scheme is set from X-Forwarded-Proto (http or https)

For the native interface, use $req->client_address and $req->url_scheme to get the forwarded values (these respect reverse_proxy mode automatically).

Only enable this when Feersum is behind a trusted proxy that sets these headers.

proxy_protocol

Enable PROXY protocol support (HAProxy protocol). When enabled, Feersum expects each new connection to begin with a PROXY protocol header before any HTTP data. Both v1 (text) and v2 (binary) formats are auto-detected and supported.

The PROXY protocol header provides the real client IP address when Feersum is behind a load balancer like HAProxy, AWS ELB/NLB, or nginx (with proxy_protocol).

When a valid PROXY header is received:

  • REMOTE_ADDR/REMOTE_PORT are updated to the source address from the header

  • For v1 UNKNOWN, v2 LOCAL, or v2 UNSPEC/AF_UNIX families, the original address is preserved

This option works independently of reverse_proxy. When both are enabled, the PROXY protocol sets the base address, which can then be overridden by X-Forwarded-For headers if reverse_proxy is also enabled.

Important: Only enable this when ALL connections come through a proxy that sends PROXY headers. Connections without valid PROXY headers will be rejected with HTTP 400.

Example HAProxy configuration:

backend feersum_backend
    mode http
    server feersum 127.0.0.1:5000 send-proxy-v2
psgix_io

Enable or disable the psgix.io PSGI extension (default: enabled). When disabled, Feersum skips creating psgix.io in the PSGI env hash, which avoids per-request overhead if your app never uses WebSocket upgrades or raw I/O.

read_timeout

Set read/keepalive timeout in seconds (default: 5). Must be positive (non-zero).

header_timeout

Set maximum time (in seconds) to receive complete HTTP headers (Slowloris protection). Default is 10 seconds. Pass 0 to disable. Connections that don't complete headers within the timeout are closed.

write_timeout

Set maximum time (in seconds) to complete writing a response. Default is 0 (disabled). When enabled, connections that stall during response writing are closed.

max_connection_reqs

Set max requests per connection in case of keepalive - 0(default) for unlimited.

max_accept_per_loop

Set max connections to accept per event loop cycle (default: 64). Lower values give more fair distribution across workers when using epoll_exclusive. Higher values improve throughput under heavy load by reducing syscall overhead.

max_connections

Set maximum concurrent connections (default: 10000; 0 disables the limit). When the limit is reached, Feersum first closes the oldest idle keep-alive connection to make room; if none are idle, the new connection is closed and accepting is paused on that listener until a slot frees. Provides protection against Slowloris-style DoS attacks.

max_read_buf

Set max read buffer size per connection (default: 64 MB). This limits how large the read buffer can grow during header parsing and chunked body reception.

max_body_len

Set max request body size (default: 64 MB). This limits Content-Length values and cumulative chunked body sizes.

max_uri_len

Set max request URI length (default: 8192).

wbuf_low_water

Set write buffer low-water mark in bytes (default: 0). Used with poll_cb() on streaming responses: the callback fires when the buffer drains to or below this threshold.

read_priority
write_priority
accept_priority

Set libev I/O watcher priorities for read, write, and accept operations. Valid range is -2 (lowest) to +2 (highest), default is 0.

tls

Enable TLS 1.3 on all listeners. Pass a hash reference with cert_file and key_file paths:

Feersum::Runner->new(
    listen => ['0.0.0.0:8443'],
    tls    => { cert_file => 'server.crt', key_file => 'server.key' },
    app    => $app,
)->run;

Requires Feersum to be compiled with TLS support (picotls submodule + Alien::OpenSSL). HTTP/2 is not enabled by default; pass h2 => 1 separately to enable it.

tls_cert_file
tls_key_file

Flat alternatives to the tls hash, useful with plackup's pass-through options:

plackup -s Feersum --tls-cert-file=server.crt --tls-key-file=server.key

Both must be specified together. If a tls hash is also provided, it takes precedence and these are ignored.

h2

Enable HTTP/2 negotiation via ALPN on TLS listeners (default: off). Requires TLS to be enabled. When Alien::nghttp2 was available at build time and this option is set, HTTP/2 is negotiated alongside HTTP/1.1 during the TLS handshake.

Feersum::Runner->new(
    listen => ['0.0.0.0:8443'],
    tls    => { cert_file => 'server.crt', key_file => 'server.key' },
    h2     => 1,
    app    => $app,
)->run;

If set without TLS enabled, a fatal error (croak) is raised.

sni

SNI virtual hosting: an arrayref of { sni => $hostname, cert_file => $path, key_file => $path } hashes. Each entry adds a certificate for the given hostname. Requires tls to be set first (provides the default cert); croaks if it is not.

Feersum::Runner->new(
    listen => ['0.0.0.0:8443'],
    tls    => { cert_file => 'default.crt', key_file => 'default.key' },
    sni    => [
        { sni => 'example.com', cert_file => 'ex.crt', key_file => 'ex.key' },
        { sni => 'other.com',   cert_file => 'ot.crt', key_file => 'ot.key' },
    ],
    app    => $app,
)->run;
reuseport

Enable SO_REUSEPORT for better prefork scaling (default: off). When enabled in combination with pre_fork, each worker process creates its own socket bound to the same address. The kernel then distributes incoming connections across workers, eliminating accept() contention and improving multi-core scaling. Requires Linux 3.9+ or similar kernel support.

Note: IPv6 support requires reuseport AND pre_fork to be enabled. Without these, only IPv4 addresses are supported.

epoll_exclusive

Enable EPOLLEXCLUSIVE for better prefork scaling on Linux 4.5+ (default: off). When enabled in combination with pre_fork, only one worker is woken per incoming connection, avoiding the "thundering herd" problem. Use with max_accept_per_loop to tune fairness vs throughput.

max_requests_per_worker

Maximum total requests a worker process will handle before gracefully recycling (default: 0 = unlimited). Effective with pre_fork or hot_restart; the parent (or hot-restart supervisor) automatically forks a replacement worker. Useful for containing memory leaks in long-running applications.

access_log

Code reference called after each response completes (native handler only). Receives ($method, $uri, $elapsed_seconds). For PSGI apps, use Plack::Middleware::AccessLog instead.

access_log => sub {
    my ($method, $uri, $elapsed) = @_;
    warn sprintf "%s %s %.3fms\n", $method, $uri, $elapsed * 1000;
},
graceful_timeout

Seconds to wait for in-flight requests to complete during graceful shutdown before force-exiting (default: 5; 0 force-exits immediately). Also honors the FEERSUM_GRACEFUL_TIMEOUT environment variable (option takes precedence). In prefork mode the parent allows an extra 2 seconds beyond this before force-exiting, so its workers have a chance to drain and exit first.

startup_timeout

Seconds to wait for a hot_restart generation to signal readiness before declaring it failed and rolling back (default: 10; 0 fails the restart immediately).

after_fork

Code reference called in each worker child immediately after fork, before entering the event loop. Use this to reconnect database handles, reseed PRNGs, or close inherited file descriptors:

after_fork => sub { $dbh = DBI->connect(...) },
pid_file

Write the server PID to this file. Removed on clean shutdown.

daemonize

Fork into background, redirect STDIN/STDOUT/STDERR to /dev/null, and call setsid(). The PID file (if specified) is written with the daemon's PID.

user
group

Drop privileges to this user/group after creating listen sockets but before loading the application. Allows binding to privileged ports as root.

max_h2_concurrent_streams

Maximum concurrent HTTP/2 streams per connection (default: 100). Requires H2 support compiled in.

quiet

Don't be so noisy. (default: on)

app_file

Load this filename as a native feersum app.

$runner->run($feersum_app)

Run Feersum with the specified app code reference. Note that this is not a PSGI app, but a native Feersum app.

$runner->assign_request_handler($subref)

For sub-classes to override, assigns an app handler. (e.g. Plack::Handler::Feersum). By default, this assigns a Feersum-native (and not PSGI) handler.

$runner->quit()

Initiate a graceful shutdown. A signal handler for SIGQUIT will call this method.

AUTHOR

Jeremy Stashewsky, stash@cpan.org

COPYRIGHT AND LICENSE

Copyright (C) 2010 by Jeremy Stashewsky & Socialtext Inc.

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.14 or, at your option, any later version of Perl 5 you may have available.