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