SYNOPSIS
        # Standalone: run a command with restart on failure
        shell$ aep --command /usr/bin/myapp --command-args "--foreground" --command-restart -1

        # Lock server: orchestrate startup order for docker-compose
        shell$ aep --lock-server --lock-server-order "db,redis,app" \
                   --lock-server-exhaust-action exit

        # Lock server with parallel groups (redis1 and redis2 start simultaneously)
        shell$ aep --lock-server --lock-server-order "db,redis1||redis2,nginx"

        # Lock client via TCP (default for Docker networking)
        shell$ aep --lock-client --lock-id db --command /usr/bin/postgres \
                   --lock-trigger "both:text:ready to accept connections" \
                   --lock-transport tcp --lock-client-host aep-master

        # Lock client with timeout (start after 30s even without server)
        shell$ aep --lock-client --lock-id db --command /usr/bin/postgres \
                   --lock-client-timeout 30

        # Docker health check (returns JSON status)
        shell$ aep --docker-health-check

        # Quiet mode (errors only)
        shell$ aep --quiet --lock-client --lock-id db --command /usr/bin/myapp

        # Verbose mode (includes packet dumps)
        shell$ aep --verbose --lock-server --lock-server-order "db,app"

DESCRIPTION
    AEP (Advanced Entry Point) is a container entrypoint tool that runs
    commands within Docker containers and provides a lock server/client
    mechanism for orchestrating multi-container startup order.

    In multi-container environments (docker-compose, Kubernetes pods),
    services often start simultaneously but depend on each other. AEP solves
    this by providing a lock server that controls the order in which
    services start, waiting for each service to report readiness before
    allowing the next to begin.

    AEP communicates between containers over both TCP and Unix domain
    sockets using a JSON protocol. TCP transport is the default for Docker
    networking, eliminating the need for shared volumes. It supports five
    trigger types for detecting when a service is ready: time delay, text
    match, regex match, TCP connect probe, and external script.

    The lock-server-order option supports parallel groups using the "||"
    operator. For example, "db,redis1||redis2,nginx" starts db first, then
    redis1 and redis2 simultaneously, then nginx after both are ready.

ARGUMENTS
  Config related
   config-env
    Default value: disabled

    Only read configuration from environment variables.

   config-file
    Default value: disabled

    Read configuration from a YAML file.

   config-args
    Default value: disabled

    Only read configuration from command line arguments.

   config-merge (default)
    Default value: enabled

    Merge together env, config file and args to generate the final
    configuration.

   config-order (default)
    Default value: 'env,file,args' (left to right)

    The order to merge configuration sources. Later sources override earlier
    ones.

  Environment related
   env-prefix (default)
    Default value: AEP_

    When scanning the environment, aep will look for this prefix to identify
    which environment variables it should use as configuration. For example,
    setting "AEP_SOCKETPATH=/var/run/aep.sock" overrides the default socket
    path.

  Command related (what to run)
   command (string)
    What to actually run within the container. Default is "aep --help".

   command-args (string)
    The arguments to add to the command, comma separated. Default is
    nothing.

    Example: "--list,--as-service,--with-long "arg",--foreground"

   command-norestart
    If the command exits, do not attempt to restart it. Exit immediately.

   command-restart (integer)
    If the command exits, how many times to retry it. Default 0. Set to -1
    for infinite restarts.

   command-restart-delay (integer)
    The time in milliseconds to wait before retrying the command. Default
    1000.

  Lock commands (server)
    These options control the lock server, which orchestrates the startup
    order of multiple containers to prevent race conditions.

   lock-server
    Default value: disabled

    Act as a lock server. Other aep instances (lock clients) will connect
    and wait for permission to start their commands.

   lock-server-host (string)
    What host to bind to. Defaults to 0.0.0.0.

   lock-server-port (integer)
    What port to bind to. Defaults to 60000.

   lock-server-default (string)
    Default value: ignore

    If a client connects with a lock-id not in the order list, what action
    to take.

    *   ignore - Do not send a run signal. The client will wait
        indefinitely.

    *   run - Immediately tell the unknown client to start.

    *   runlast - Queue the client and run it after the order list is
        exhausted.

   lock-server-order (string)
    The list of lock-ids and the order to allow them to run, comma
    separated. Use "||" within a step to run multiple clients in parallel.

    Example: "db,redis,nginx"

    Example with parallel groups: "db,redis1||redis2,nginx"

    In the parallel example, "db" starts first, then "redis1" and "redis2"
    start simultaneously. Only after both report trigger success does
    "nginx" start.

    Each entry must match a lock-id sent by a connecting client. The server
    sends a "run" signal to each client in order, waiting for each to report
    success (via its lock-trigger) before advancing to the next.

   lock-server-exhaust-action (string)
    Default value: idle

    What to do when all clients in the order list have reported success.

    *   exit - Exit with code 0.

    *   idle - Do nothing, keep the server running.

    *   restart - Reset the order list and start the cycle again.

    *   execute - Start the server's own command (from --command).

  Lock commands (client)
   lock-client
    Default value: disabled

    Become a lock client. This aep will connect to a lock server and wait
    for permission to start its command.

   lock-client-host (string)
    What host to connect to. Defaults to "aep-master" (assumes Docker DNS).

   lock-client-port (integer)
    What port to connect to. Defaults to 60000.

   lock-client-noretry
    If the connection to the lock server fails, exit immediately instead of
    retrying. Overrides lock-client-retry.

   lock-client-retry (integer)
    Maximum number of connection retry attempts. Set to 0 for infinite
    retries. Defaults to 3.

   lock-client-retry-delay (integer)
    How long to wait in seconds before retrying the connection. Defaults to
    5.

   lock-client-timeout (integer)
    Maximum seconds to wait for the lock server to send the "run" signal. If
    the timeout expires without receiving permission, the command starts
    anyway and a warning is logged. Set to 0 (default) to wait forever.

   lock-transport (string)
    Default value: auto

    Which transport to use for connecting to the lock server.

    *   auto - Try TCP first, fall back to Unix socket if TCP fails.

    *   tcp - Use TCP only. Connect to lock-client-host:lock-client-port.

    *   unix - Use Unix socket only.

   lock-trigger (string)
    Default: none:time:10000

    How to determine that the command started successfully. After the
    trigger fires, the client reports success to the lock server, which then
    allows the next client in the order to start.

    The syntax is:

        handle:filter:specification

    "handle" can be "stderr", "stdout", "both", or "none".

    Available filters:

    *   time - Wait this many milliseconds and then report success.

        Example: "none:time:2000"

    *   regex - Wait until this regex matches output.

        Example: "both:regex:ok|success"

    *   text - Wait until this exact text appears in output.

        Example: "both:text:success"

    *   script - Run an external script and use its exit code (0 = success).
        Runs with a 30-second timeout. Retries every second on failure.

        Example: "none:script:/opt/check_state"

    *   connect - Try to connect to a TCP host:port. No data is sent or
        received. Retries every second on failure.

        Example: "none:connect:127.0.0.1:6767"

   lock-id (string)
    The identity this client reports to the lock server. Must match an entry
    in the server's "--lock-server-order" list (unless
    "--lock-server-default" is set to "run" or "runlast").

  Output control
   quiet
    Suppress informational output. Only errors and the final exit message
    are shown.

   verbose
    Show detailed debug output including packet contents (the serialized
    JSON sent and received).

  Other
   docker-health-check
    Connect to the lock server and request a health status report. The
    server responds with JSON containing the current order progress,
    connected clients, and which services have been cleared or are still
    waiting.

    Returns exit code 0 (healthy) with JSON on stdout, or exit code 1
    (unhealthy) if the connection fails.

ENVIRONMENT
    AEP_SOCKETPATH
        Path to the Unix domain socket for lock server/client communication.
        Default: "/tmp/aep.sock"

BUGS
    For any feature requests or bug reports please visit:

    <https://github.com/PaulGWebster/p5-App-aep>

    You may also find the author 'daemon' on IRC:

    *   irc.libera.org #perl

AUTHOR
    Paul G Webster <daemon@cpan.org>

COPYRIGHT AND LICENSE
    This software is copyright (c) 2023-2026 by Paul G Webster.

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

