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 HTTP server *)
Start the <http-server> on port <config: server port>.
(* Start file watcher for uploads *)
Watch the <directory: "./uploads"> as <upload-watcher>.
(* Keep the application running *)
Keepalive the <application> for the <events>.
Log "Platform ready" to the <console>.
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>.
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> on port 8080.
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> on port 8080.
Keepalive the <application> for the <events>.
Return an <OK: status> for the <startup>.
}
(Application-End: Success) {
Stop the <http-server>.
Return an <OK: status> for the <shutdown>.
}
File Watcher
(Application-Start: File Processor) {
Watch the <directory: "./inbox"> as <file-watcher>.
Keepalive the <application> for the <events>.
Return an <OK: status> for the <startup>.
}
Socket Server
(Application-Start: Socket Server) {
Listen on port 9000 as <socket-server>.
Keepalive the <application> for the <events>.
Return an <OK: status> for the <startup>.
}
Multiple Services
(Application-Start: Full Stack) {
(* HTTP API *)
Start the <http-server> on port 8080.
(* WebSocket server *)
Listen on port 8081 as <websocket-server>.
(* File watcher *)
Watch the <directory: "./uploads"> as <upload-watcher>.
(* Keep the application running *)
Keepalive the <application> for the <events>.
Return an <OK: status> for the <startup>.
}
(Application-End: Success) {
(* Stop in reverse order *)
Stop the <upload-watcher>.
Close the <websocket-server>.
Stop the <http-server>.
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 <missing: database>.
}
(* Then initialize services *)
Start the <http-server> on port <config: port>.
Return an <OK: status> for the <startup>.
}
Log Lifecycle Events
(Application-Start: Observable App) {
Log "APPLICATION_STARTING" to the <console>.
Start the <http-server> on port 8080.
Log "APPLICATION_READY" to the <console>.
Return an <OK: status> for the <startup>.
}
(Application-End: Success) {
Log "APPLICATION_STOPPING" to the <console>.
Stop the <http-server>.
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