← Back to Documentation

Application Lifecycle

ARO applications have a well-defined lifecycle from startup to shutdown. This chapter explains how to manage your application's lifecycle.

Lifecycle Overview

1. Load all .aro files
2. Compile and validate
3. Register feature sets with event bus
4. Execute Application-Start
5. Enter event loop
   ↓
   Handle Events (HTTP, Files, Sockets, Domain Events)
   ↓ (shutdown signal)
6. Stop accepting new events
7. Wait for pending events
8. Execute Application-End
9. Stop services
10. Exit

Application-Start

The entry point for every ARO application.

Requirements

Basic Example

(Application-Start: My Application) {
    Log "Starting application..." to the <console>.
    Return an <OK: status> for the <startup>.
}

Full Example

(Application-Start: E-Commerce Platform) {
    Log "Starting E-Commerce Platform..." to the <console>.

    (* Load configuration *)
    Read the <config: JSON> from the <file: "./config.json">.
    Publish as <app-config> <config>.

    (* Start the HTTP server — routes and port come from openapi.yaml *)
    Start the <http-server> with <contract>.

    (* Start the file watcher for uploads *)
    Start the <file-monitor> with "./uploads".

    Log "Platform ready" to the <console>.

    (* Keep the application running so events can be processed *)
    Keepalive the <application> for the <events>.

    Return an <OK: status> for the <startup>.
}

Application-End

Exit handlers for cleanup when the application stops.

Success Handler

Called on graceful shutdown (SIGTERM, SIGINT, or programmatic stop):

(Application-End: Success) {
    Log "Shutting down gracefully..." to the <console>.

    (* Stop accepting new requests *)
    Stop the <http-server> with <application>.

    Log "Shutdown complete. Goodbye!" to the <console>.
    Return an <OK: status> for the <shutdown>.
}

Error Handler

Called when the application crashes or encounters a fatal error:

(Application-End: Error) {
    Extract the <error> from the <shutdown: error>.
    Extract the <reason> from the <shutdown: reason>.

    Log "FATAL ERROR: ${reason}" to the <console>.

    Return an <OK: status> for the <error-handling>.
}

Shutdown Context

Available variables in Application-End handlers:

VariableDescriptionAvailable In
<shutdown: reason>Human-readable reasonBoth
<shutdown: code>Exit code (0 = success)Both
<shutdown: signal>Signal name (SIGTERM, etc.)Success
<shutdown: error>Error objectError only

Rules

Keeping Applications Alive

For servers that should run indefinitely, use the Keepalive action:

(Application-Start: My Server) {
    Start the <http-server> with <contract>.
    Keepalive the <application> for the <events>.
    Return an <OK: status> for the <startup>.
}

The Keepalive action blocks until interrupted (Ctrl+C or kill signal).

Service Initialization

HTTP Server

(Application-Start: Web Server) {
    Start the <http-server> with <contract>.
    Keepalive the <application> for the <events>.
    Return an <OK: status> for the <startup>.
}

(Application-End: Success) {
    Stop the <http-server> with <application>.
    Return an <OK: status> for the <shutdown>.
}

File Watcher

(Application-Start: File Processor) {
    Start the <file-monitor> with "./inbox".
    Keepalive the <application> for the <events>.
    Return an <OK: status> for the <startup>.
}

Socket Server

(Application-Start: Socket Server) {
    Start the <socket-server> with { port: 9000 }.
    Keepalive the <application> for the <events>.
    Return an <OK: status> for the <startup>.
}

Multiple Services

(Application-Start: Full Stack) {
    (* HTTP API — contract-first, from openapi.yaml *)
    Start the <http-server> with <contract>.

    (* TCP socket server *)
    Start the <socket-server> with { port: 9000 }.

    (* File watcher *)
    Start the <file-monitor> with "./uploads".

    (* Keep the application running *)
    Keepalive the <application> for the <events>.

    Return an <OK: status> for the <startup>.
}

(Application-End: Success) {
    Stop the <http-server> with <application>.
    Close the <socket-server> with <application>.
    Return an <OK: status> for the <shutdown>.
}

Best Practices

Initialize Early, Fail Fast

(Application-Start: Fail Fast) {
    (* Check critical config first *)
    Read the <config> from the <file: "./config.json">.

    when <config: database> is empty {
        Log "Missing database configuration" to the <console>.
        Throw a <ConfigurationError> for the <config>.
    }

    (* Then initialize services *)
    Start the <http-server> with <contract>.
    Keepalive the <application> for the <events>.

    Return an <OK: status> for the <startup>.
}

Log Lifecycle Events

(Application-Start: Observable App) {
    Log "APPLICATION_STARTING" to the <console>.

    Start the <http-server> with <contract>.

    Log "APPLICATION_READY" to the <console>.
    Keepalive the <application> for the <events>.
    Return an <OK: status> for the <startup>.
}

(Application-End: Success) {
    Log "APPLICATION_STOPPING" to the <console>.

    Stop the <http-server> with <application>.

    Log "APPLICATION_STOPPED" to the <console>.
    Return an <OK: status> for the <shutdown>.
}

Next Steps

HTTP Services - HTTP server and client
Sockets - TCP communication
Events - Event-driven architecture