Changes for version 0.000034 - 2026-04-26
- IPC::Manager::Client::ConnectionUnix::_drain_reads now early-returns "EOF" when its $fh argument is undef. During global destruction perl is free to destroy the IO::Socket::UNIX stored in $entry->{fh} before the Client's DESTROY runs disconnect, leaving $entry->{fh} undef when _read_messages / _resolve_pending walk the connection cache; the unguarded sysread then died with "Can't use an undefined value as a symbol reference" mid-shutdown. Treating a missing handle as already-closed lets the disconnect drain finish cleanly
- IPC::Manager::Serializer::JSON::Zstd now accepts constructor arguments for compression level and preset dictionary: ipcm_spawn(serializer => ['JSON::Zstd', level => 9, dictionary => '/path/to/dict']) builds a single configured instance. The default compression level is 3 (Compress::Zstd's library default); when a dictionary path is supplied the constructor loads it once via Compress::Zstd::CompressionDictionary / DecompressionDictionary and reuses the loaded handles for every serialize/deserialize call. Class-method use (serializer => 'JSON::Zstd') is unchanged: no instance is constructed, level 3 and no dictionary apply. The serializer slot of the cinfo connection-info string accepts the same forms (string class or [$class, %args] arrayref); IPC::Manager caches built instances by class+args so peer connections share one serializer rather than reconstructing per send_message or per peer. The cinfo string itself is still always plain JSON and never compressed
- IPC::Manager::Base::FS::requeue_message / read_resume_file now use 4-byte length-prefixed framing for entries in the resume file instead of newline-delimited records. The newline framing was unsafe for binary serializers (zstd, etc.) whose decoders reject trailing garbage; length-prefixing makes the format safe regardless of the serializer's encoding. Resume files do not survive across processes, so this is not a wire-compat break for any deployment that does not move resume files between IPC::Manager versions
- Add IPC::Manager::Serializer::JSON::Zstd, a subclass of IPC::Manager::Serializer::JSON that zstd-compresses payloads with Compress::Zstd before sending and decompresses them on receipt. Uses Compress::Zstd's default compression level and no preset dictionary. JSON::Zstd is now selected as the default serializer when Compress::Zstd 0.20 or newer is installed; if Compress::Zstd is missing or older, ipcm_default_serializer falls back to plain JSON. Compress::Zstd is added as a runtime recommendation, not a hard dependency. IPC::Manager::Test::test_generic compares the deserialized info string against $guard->serializer instead of hard-coding IPC::Manager::Serializer::JSON, so the check works regardless of which serializer ipcm_default_serializer picked
- IPC::Manager::Client::UnixSocket no longer appends a trailing newline to serialized payloads on send (applies to send_message, _outbox_try_write, and _drain_blocking). The byte was vestigial under SOCK_DGRAM (datagrams self-frame) and broke binary serializers whose decoders reject trailing garbage. JSON receivers tolerated the extra byte, so removing it is wire-compatible with previous JSON-only deployments
- IPC::Manager::Service::Handle::await_all_responses now short-circuits its gone-peer probe. The poll previously ran _gone_pending_peers on every loop iteration just to test "did anyone go away", which calls _pending_peer_active per pending response and can hit the filesystem or the database. The boolean check is now done by a new _have_gone_pending_peers helper that returns on the first gone peer; _gone_pending_peers is still used on the croak path that needs the peer names
- Fix IPC::Manager::Service::Handle::await_all_responses hanging forever when a service crashes without responding. await_all_responses now mirrors await_response's peer-death semantics: pending peers are checked each polling cycle, and if any become inactive it does one final non-blocking drain and croaks "peer(s) ... went away while awaiting responses" instead of polling indefinitely. Also accepts an optional $timeout argument, throwing if the deadline passes with pending responses still outstanding
- Bound the IPC::Manager::Spawn::wait peer-disappear poll. The loop used to call sleep(1) forever waiting for clients to disconnect, so a wedged service or a slow-filesystem CPAN smoker could trap shutdown indefinitely. The poll now respects a deadline (default 60s, overridable via the peer_timeout argument or $ENV{IPC_MANAGER_SPAWN_PEER_TIMEOUT}); when it expires the still-registered peers are warned about and the child-reap loop runs anyway
- On per-subtest alarm timeout, IPC::Manager::Test->run_all/run_one now SIGTERM (then SIGKILL) the subtest's child process group before confessing, so service grandchildren and workers are reaped instead of being orphaned. Orphans were continuing to write Test2::IPC events into the parent's tempdir after the parent exited, producing downstream "IPC Fatal Error: Leftover files in the directory" bailouts on top of the original timeout. The subtest child becomes the leader of its own process group via POSIX::setpgid, which is also called from the parent to close the setpgid race
- Add IPC::Manager::Client::ConnectionUnix, a connection-oriented UNIX-socket driver built on SOCK_STREAM. Each client either listens for incoming connections (default) or drops a marker file under the route directory, and messages flow over established per-peer connections with a 4-byte length-prefixed framing and a hello-frame peer identification handshake. send_message does not auto-reconnect on EPIPE: a failed send drops the cached connection and propagates the error so the caller decides whether to retry; the next send to the same peer establishes a fresh connection. ConnectionUnix is registered in ipcm_default_protocol_list, documented under CLIENT PROTOCOLS, and exercised by the full t/ConnectionUnix/ integration tree
- Add IPC::Manager::Role::Client::Connection, a Role::Tiny role that gives connection-oriented drivers a uniform per-peer connection API (has_connection, connections, disconnect_connection, last_activity, close_idle_connections). Consumers provide _connections (the cache hashref) and _close_connection (handle teardown); the role itself runs no background timer, so close_idle_connections is caller-driven
- Support dynamic select-handle sets in IPC::Manager::Role::Service::Select. Drivers can now advertise have_dynamic_handles_for_select to indicate that handles_for_select changes over the lifetime of the client (e.g. ConnectionUnix accepting new connections), and the service select cache rebuilds its IO::Select set each iteration for those drivers instead of caching it once at startup
- Bump the optional Atomic::Pipe dependency from 0.022 to 0.026 in dist.ini, the AtomicPipe client _viable check, and the Test2::Require::Module gates on every t/AtomicPipe/ and t/unit/atomicpipe_*/ test
- Add IPC::Manager::Role::Outbox: per-peer non-blocking send queue consumed by FIFO/datagram-socket clients. Services flip their client to send_blocking=0 at startup; outbound sends that would EAGAIN are queued and the service event loop drains them when the underlying transport becomes writable. Memory- and DB-backed clients keep the simple blocking send_message via a base-class no-op fallback. Per-peer message order across the outbox is NOT preserved (documented in Role::Outbox POD); callers that need strict order must keep the client in send_blocking=1
- IPC::Manager::Client base class sets $self->{_creator_pid} once in init and uses it (instead of +PID) in DESTROY. The role's init re-runs after fork and rewrites +PID, so DESTROY in a forked child would otherwise unlink the FIFO / socket / route entry the parent still owns. Pinning DESTROY to the originating process keeps cleanup correct across post-fork peer churn. The same base class also gains default fallbacks for the full Outbox API (try_send_message, pending_sends, drain_pending, have_writable_handles, writable_handles, send_blocking, set_send_blocking, can_send_to) so service code can call the API uniformly across all client backends; clients that do not consume Role::Outbox (memory- and DB-backed) treat sends as immediate and never queue
- Client::AtomicPipe and Client::UnixSocket consume Role::Outbox. Writer pipes/sockets are non-blocking when send_blocking=0 and blocking when send_blocking=1 (the default for non-service callers); send_message in either mode preserves the fire-and-die semantics of earlier versions
- Client::ConnectionUnix consumes Role::Outbox with a per-connection send_buffer instead of a whole-payload queue, since SOCK_STREAM partial writes mid-frame cannot be re-sent from the start without corrupting the stream. _outbox_try_write appends the framed bytes to the connection's send_buffer and flushes non-blocking; pending_sends, drain_pending, have_writable_handles and writable_handles are overridden to walk per-connection send_buffers so the service event loop wakes on writability and drains correctly. send_message branches on send_blocking: blocking mode runs the synchronous _send_frame and propagates errors to the caller; non-blocking mode delegates to try_send_message
- Service::Select adds select_write() returning a fresh IO::Select over the client's writable-with-backlog handles. Service::watch now uses IO::Select->select($r, $w, undef, $cycle) so the loop wakes on either readable or writable readiness
Modules
Decentralized local IPC through various protocols.
Base class for DBI based protocols
Base class for filesystem based protocols
Base class for filesystem clients that read via a handle
Base class for all client protocols
Use FIFO pipes for message transfers.
Connection-oriented UNIX socket IPC client.
Single JSON file as a message store
Process-local in-memory message store for testing only
Use MariaDB as a message store.
Use files on disk as a message store.
Use MySQL as a message store.
Use PostgreSQL as a message store.
Use SQLite as a message store.
Use UNIX sockets for message transfers.
Database based clients for IPC::Manager.
Messages sent between clients.
Per-connection management for connection-oriented clients
Non-blocking outbound queue for clients
Role for implementing IPC services with message handling
Role for handling request/response patterns in IPC services.
Role for I/O multiplexing in IPC services
Serializer base class for IPC::Manager.
JSON Serializer for IPC::Manager.
JSON serializer with zstd compression for IPC::Manager.
Base class for creating IPC services
Service that echoes back request content
Handle class for connecting to IPC services
Peer connection class for IPC::Manager services
Internal implementation of ipcm_service and ipcm_worker
Encapsulation of a newly initiated message store.
Reusable protocol-agnostic test suite for IPC::Manager
Utility functions for IPC::Manager