NAME

    IPC::Manager - Decentralized local IPC through various protocols.

DESCRIPTION

    IPC::Manager provides a way to do message based IPC between local (on a
    single machine) processes. It provides multiple protocols for doing
    this, as well as pluggable serialization.

    The idea is to first initialize a data store, provide the info to
    access the data store, then any process may use that info to
    send/recieve messages. The datastore can be temporary (guarded) or
    persistent.

SYNOPSIS

        use IPC::Manager qw/ipcm_connect ipcm_spawn/;
    
        # Let the system pick a protocol and serialization
        my $ipcm = ipcm_spawn();
    
        my $info = $ipcm->info;
        print "You can connect to the IPC using this string: $info\n";
    
        # Get a connection
        my $con1 = ipcm_connect(con1 => $info);
        my $con2 = ipcm_connect(con2 => $info);
    
        # Send a message
        $con1->send_message(con2 => {hello => 'world'});
    
        # Get messages
        if (my @messages = $con2->get_messages) {
            # hashref: {hello => 'world'}
            my $payload = $message[0]->content;
            ...
        }
    
        # Cleanup the datastore (unless `guard => 0` was passed in).
        $guard = undef;

    The idea is to use the ipcm data store as the medium for transferring
    messages. You can use the string returned by $ipcm->info from any
    process to reach the data store.

    You can set up persistent data stores, in which case the ipcm_spawn()
    export is not needed. How to set up a persistent data store is
    documented in each client protocol.

    Messages are instances of IPC::Manager::Message. You can make the
    instances yourself manually and send them, or you can let
    send_message() create them for you:

        $con1->send_message(con2 => IPC::Manager::Message->new(content => \%CONTENT, ...));
        $con1->send_message(con2 => \%CONTENT);

EXPORTS

    $ipcm = ipcm->spawn(...)

    $con = ipcm->connect(...)

    $con = ipcm->reconnect(...)

      ipcm() is an alias for IPC::Manager. You can use it to call spawn,
      connect, or reconnect without importing ipcm_spawn(), ipcm_connect(),
      or ipcm_reconnect() into your namespace.

    $protocol = ipcm_default_protocol()

    ipcm_default_protocol($protocol)

      Get or set the default protocol. This is undef until set.

    $protocol_list = ipcm_default_protocol_list()

    ipcm_default_protocol_list(\@protocol_list)

      Default set of protocols to try, in the order they should be tried.

    $serializer = ipcm_default_serializer()

    ipcm_default_serializer($serializer)

    ipcm_default_serializer([$class, %args])

    ipcm_default_serializer($class, %args)

      Get or set the default serializer. The default is 'JSON::Zstd' when
      Compress::Zstd 0.20 or newer is installed, otherwise 'JSON'.

      The setter accepts either a class string (uses class methods, no
      construction) or an arrayref whose first element is the class and
      whose remaining elements are constructor arguments. The arrayref form
      (or the flat-list spelling, which is treated identically) builds and
      caches a single shared instance keyed on ($class, %args); subsequent
      ipcm_spawn / ipcm_connect calls with the same spec reuse it.

    $ipcm = ipcm_spawn()

    $ipcm = ipcm_spawn(protocol => $PROTOCOL)

    $ipcm = ipcm_spawn(protocols => \@PROTOCOLS)

    $ipcm = ipcm_spawn(serializer => 'JSON', guard => 1, signal => $SIGNAL)

    $ipcm = ipcm_spawn(dbh => $dbh)

      This will create a new data store for IPC. By default it will be
      temporary and will be destroyed when the $ipcm object falls out of
      scope.

      You can set guard => 0 to prevent the destruction of the datastore
      when the object falls out of scope.

      You can also set a signal, such as 'INT' or 'TERM' to have the signal
      sent to the PID for all clients when the instance is shut down.

      You can set the serializer with the serializer => $CLASS option.
      'IPC::Manager::Serializer::' will be prefixed onto the class name
      unless it is already present, or if the class name starts with '+'.
      To configure a serializer that takes constructor arguments (for
      example to set a custom compression level or dictionary on
      IPC::Manager::Serializer::JSON::Zstd) pass an arrayref of [$class,
      %args]: serializer => ['JSON::Zstd', level => 9]. The arrayref form
      builds a single cached instance shared across all peer connections;
      the string form keeps using class methods directly.

      You can pick a protocol with the protocol => $CLASS option.
      'IPC::Manager::Client::' will be prefixed onto the class name unless
      it is already present, or if the class name starts with '+'.

      If you do not care what protocol is used you can leave it blank, in
      which case one will be picked for you based on what your system
      supports. Order in which it will try protocols is subject to change
      at any time.

      If you want to narrow down to a specific set of protocols you may
      provide a list: protocols => [ 'AtomicPipe', 'UnixSocket',
      'PostgreSQL', ... ]. The first viable protocol will be used.

      Spawning against an existing DBI handle. For DBI-backed protocols you
      may pass dbh => $dbh instead of letting the protocol bootstrap its
      own database. The protocol is auto-detected from $dbh->{Driver}{Name}
      using this map:

          Pg      -> IPC::Manager::Client::PostgreSQL
          MariaDB -> IPC::Manager::Client::MariaDB
          mysql   -> IPC::Manager::Client::MariaDB   (see DBD::mysql note below)
          SQLite  -> IPC::Manager::Client::SQLite

      You can still pass protocol => $CLASS alongside dbh => $dbh to
      override the auto-detection.

      ipcm_spawn runs init_db against the supplied handle to create the
      ipcm_peers and ipcm_messages tables, then returns a Spawn object
      whose route is reassembled from $dbh->{Driver}{Name} and $dbh->{Name}
      so that the $ipcm->info string is still usable by peers reconnecting
      from another process (each peer constructs its own DBI handle from
      the reassembled DSN — the in-process handle is not, and cannot be,
      shared across processes).

      Useful for embedding IPC::Manager inside an application that already
      owns a DBI connection without forcing it to bootstrap a separate one
      (e.g. you already have a long-lived $dbh in a web app and want to use
      the same database for IPC).

      DBD::mysql note. IPC::Manager::Client::MySQL is built against
      DBD::MariaDB, not DBD::mysql. If you happen to pass in a $dbh whose
      driver name is mysql, it is tolerated — the auto-detect map points it
      at the MariaDB client class and things will normally work — but
      DBD::mysql is not in the dependency list and is not exercised by the
      test suite, so this path is best-effort only. Prefer DBD::MariaDB.

      The object returned is an instance of IPC::Manager::Spawn.

    $con = ipcm_connect($name => $info)

      This is used to establish a connection. The $name should be a unique
      name for your connection, it will be used as the 'from' field for any
      message you send, and will be used by other clients to send messages
      to you.

      The $info argument must be the connection info needed to connect to
      the data store. This is always a 3 element arrayref, or a JSON string
      with the 3 element arrayref.

          [$protocol_class, $serializer_class, $route]
          '["PROTOCOL_CLASS", "SERIALIZER_CLASS", "ROUTE"]'

      The protocol should always be an IPC::Manager::Client subclass. The
      serializer slot may be a class string, in which case the receiver
      uses class methods on it, or a [$class, %args] arrayref, in which
      case the receiver constructs (and caches) a configured instance. The
      connection info string itself is always plain JSON; only message
      payloads carried over the chosen protocol are subject to the
      serializer's encoding (e.g. zstd compression). The route is protocol
      specific, it may be a file, a directory, a DBI DSN string, etc.

    $con = ipcm_connect($name, undef, dbh => $dbh)

    $con = ipcm_reconnect($name, undef, dbh => $dbh)

      For DBI-backed protocols you may pass a pre-connected $dbh in place
      of an $info string. The protocol is auto-detected from
      $dbh->{Driver}{Name} (same map as documented under ipcm_spawn), the
      route is reassembled from $dbh->{Driver}{Name} + $dbh->{Name} for
      storage in the resulting Client object, and the Client reuses the
      supplied handle directly instead of calling DBI->connect.

      The same DBD::mysql-is-tolerated-not-supported caveat applies — see
      the ipcm_spawn section above.

    $con = ipcm_reconnect($name => $info)

      Same as 'connect', but used to reconnect as a client that was
      suspended or otherwise disconnected.

    $peer = ipcm_service($name => \&callback)

    $peer = ipcm_service($name, \%params, \&callback)

    $peer = ipcm_service($name, %params)

      Forks a new service process. When called from outside a service the
      return value is an IPC::Manager::Service::Handle connected to the new
      service over a freshly spawned IPC bus.

      When called from inside a running service (i.e. from within a service
      callback) the new service shares the existing IPC bus, and the return
      value is an IPC::Manager::Service::Peer that the calling service can
      use to send requests to the nested service.

      The returned handle or peer carries the first-fork child pid via
      $handle->child_pid - useful for supervisors that track services by
      pid. See "child_pid" in IPC::Manager::Service::Handle for the
      first-fork caveat around post_fork_hook daemonization.

      Void context and the ready race: when called in void context from
      inside a service, ipcm_service forks the nested service and returns
      immediately without waiting for it to finish connecting to the bus.
      If you intend to contact the nested service shortly after (e.g. from
      handle_request), you must wait for it yourself before returning from
      the enclosing callback:

          on_start => sub {
              ipcm_service nested => sub { ... };   # void context - no wait
              $self->peer('nested')->ready(0);      # block until ready
          },

      Failing to do so is a race condition: a request may be forwarded to
      the nested service before it has connected, causing the caller to
      stall indefinitely.

    $pid = ipcm_worker($name, \&callback)

      Fork a named worker process from inside a running service. Dies if
      called outside a service.

      The worker runs \&callback instead of a normal service event loop. It
      is registered with the enclosing service so that it is automatically
      reaped when the service exits.

      Returns the worker PID to the caller (the parent service process);
      the callback is entered in the forked child and the function never
      returns there.

CLIENT PROTOCOLS

    See IPC::Manager::Client for common methods across all client types.

 FileSystem Based

    These are all based off of IPC::Manager::Base::FS. These are all based
    on a directory structure of some kind.

    MessageFiles

      IPC::Manager::Client::MessageFiles

      This is the most universal protocol, it works in the most places.

      This uses a directory as the 'route'. Within this directory each
      client creates a subdirectory. Messages are sent by writing a file
      per message to the clients directory. Messages are deleted from the
      filesystem when read.

    AtomicPipe

      IPC::Manager::Client::AtomicPipe

      This uses a directory as the 'route'. This uses the Atomic::Pipe
      library to send atomic messages across pipes. Each client has its own
      FIFO pipe any other process can write to when sending a message.
      Messages are recieved by reading from the pipe. (Multiple writer,
      single reader).

    UnixSocket

      IPC::Manager::Client::UnixSocket

      This uses a directory as the 'route'. This uses unix sockets, one per
      client. Messages are sent by writing them to the correct clients
      socket. (Multiple writer, single reader).

    ConnectionUnix

      IPC::Manager::Client::ConnectionUnix

      Like UnixSocket but uses SOCK_STREAM connection-oriented UNIX
      sockets. Each client either listens for incoming connections
      (default) or registers as a non-listener and may only be reached via
      connections it has itself initiated. Per-connection management
      methods are provided by IPC::Manager::Role::Client::Connection.

 DBI Based

    These are all based off of IPC::Manager::Base::DBI. These all use a
    database as the message store.

    These all have 1 table for tracking clients, and another for tracking
    messages. Messages are deleted once read. The 'route' is a DSN. You
    also usually need to provide a username and password.

        my $con = ipcm_connect(my_con => $info, user => $USER, pass => $PASS);

    MariaDB

      IPC::Manager::Client::MariaDB

    MySQL

      IPC::Manager::Client::MySQL

    PostgreSQL

      IPC::Manager::Client::PostgreSQL

    SQLite

      IPC::Manager::Client::SQLite

CLEANUP

    When using a temporary instance that cleans up after itself, the
    cleanup process will send terminations messages to all clients, then
    wait for them to disconnect. It will also tell you if there is a
    mismtach between sent and recieved messages.

    See IPC::Manager::Spawn for more information.

SOURCE

    The source code repository for IPC::Manager can be found at
    https://github.com/exodist/IPC-Manager.

MAINTAINERS

    Chad Granum <exodist@cpan.org>

AUTHORS

    Chad Granum <exodist@cpan.org>

COPYRIGHT

    Copyright Chad Granum <exodist7@gmail.com>.

    This program is free software; you can redistribute it and/or modify it
    under the same terms as Perl itself.

    See https://dev.perl.org/licenses/

