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
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
- Exactly one per application
- Must be named
Application-Start - Must return a status
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:
| Variable | Description | Available In |
|---|---|---|
<shutdown: reason> | Human-readable reason | Both |
<shutdown: code> | Exit code (0 = success) | Both |
<shutdown: signal> | Signal name (SIGTERM, etc.) | Success |
<shutdown: error> | Error object | Error only |
Rules
- Both handlers are optional
- At most one of each per application
- Error handler only runs on errors
- Success handler only runs on graceful shutdown
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