Skip to content

Directories and bootstrap caching

The application resolves directories and can persist bootstrap metadata in files. Both belong to a particular installation: they do not turn services, scopes or process data into distributed state.

Directory(app: IApplication) -> None

orionis.foundation.directory.Directory implements IDirectory and captures a copy of a configured application’s path map. Before configuration is created, app.path() raises RuntimeError; construct Directory after that stage. Its methods are synchronous and return Path. They do not create folders or read business files.

You can receive the concrete class through DI or construct Directory(app) when you already have an IApplication. There is no automatic IDirectory binding here that you should assume when requesting the contract.

from orionis.foundation.directory import Directory
from orionis.http import JSONResponse
class LocationsController:
async def __call__(self, directory: Directory) -> JSONResponse:
return JSONResponse({"views": str(directory.resourcesViews())})

A route invoking this controller lets the container construct Directory with the same application. Use Storage for file operations instead of scattering physical paths throughout business code.

Every method below has signature name() -> Path, with no additional arguments. They access the captured map; a missing key in an incomplete map raises KeyError. Defaults are resolved relative to basePath.

Methodapp.path keyDefault path
root()root.
app()appapp
appConsole()app_consoleapp/console
appConsoleCommands()app_console_commandsapp/console/commands
appConsoleListeners()app_console_listenersapp/console/listeners
appExceptions()app_exceptionsapp/exceptions
appHttp()app_httpapp/http
appHttpControllers()app_http_controllersapp/http/controllers
appHttpMiddleware()app_http_middlewareapp/http/middleware
appHttpSchemas()app_http_schemasapp/http/schemas
appHttpSchemasRules()app_http_schemas_rulesapp/http/schemas/rules
appModels()app_modelsapp/models
appMcp()app_mcpapp/mcp
appMcpServers()app_mcp_serversapp/mcp/servers
appMcpTools()app_mcp_toolsapp/mcp/tools
appMcpResources()app_mcp_resourcesapp/mcp/resources
appMcpPrompts()app_mcp_promptsapp/mcp/prompts
appRealtime()app_realtimeapp/realtime
appRealtimeSockets()app_realtime_socketsapp/realtime/sockets
appRealtimeHubs()app_realtime_hubsapp/realtime/hubs
appProviders()app_providersapp/providers
appNotifications()app_notificationsapp/notifications
appServices()app_servicesapp/services
appFacades()app_facadesapp/facades
appJobs()app_jobsapp/jobs
appContracts()app_contractsapp/contracts
bootstrap()bootstrapbootstrap
config()configconfig
database()databasedatabase
databaseFactories()database_factoriesdatabase/factories
databaseMigrations()database_migrationsdatabase/migrations
databaseSchemas()database_schemasdatabase/schemas
databaseSeeders()database_seedersdatabase/seeders
resources()resourcesresources
resourcesCss()resources_cssresources/css
resourcesJs()resources_jsresources/js
resourcesLang()resources_langresources/lang
resourcesViews()resources_viewsresources/views
routes()routesroutes
storage()storagestorage
storageApp()storage_appstorage/app
storageAppPrivate()storage_app_privatestorage/app/private
storageAppPublic()storage_app_publicstorage/app/public
storageFramework()storage_frameworkstorage/framework
storageLogs()storage_logsstorage/logs
tests()teststests

root() always returns basePath. The corresponding IDirectory methods express the same contract. app.path() exposes the complete frozen registry; app.path("key") returns the path, or None when absent.

Configure changes through withConfigPaths() before creating the application, using the keys in the table. A relative string uses the project root; a relative Path uses the working directory. Each key has an independent default: changing app does not automatically relocate app_models. Each call rebuilds the entire registry; see Bootstrap options.

# bootstrap/app.py, before app.create().
app.compile(
path="storage/framework/bootstrap",
invalidation_paths=["app", "bootstrap", "config", "routes", ".env"],
)

compile(path=None, invalidation_paths=None) -> None enables persistence. Without an explicit path it uses storage/framework/cache. The generated bootstrap selects storage/framework/bootstrap and also monitors other project directories. Files are created when each component needs to persist its information:

Extensionless JSON fileScope
configResolved configuration and metadata for directories, providers, routes, middleware, kernels, scheduler and handler.
commandsReactor command registry and arguments.
routesCompiled HTTP route registry.

It does not store live service objects, open connections, event loops, asyncio locks, authenticated users or scoped instances. It is also separate from the business cache managed by the Cache facade.

The file contains format, generation and source-hash metadata alongside serialized data. Writing uses a sibling temporary file and replaces the destination. That replacement prevents a partially written file, but is not a distributed lock coordinating every process regenerating content. Environment: JSON persistence details types, credentials, invalidation, corrupt files and why there is no env.json.

A config hit during compile() restores and freezes bootstrap before subsequent registrations. The with... methods reuse that snapshot. Lifespan callbacks are registered per process and are not saved in these files; providers register their services again in every container.

LevelApplication memoryCompiled files
Request or commandHas its own scope; shares its process’s application.There is no cache created per request or command.
Several workers on one serverEach process retains its own Application, bindings, singletons and locks.They can reuse files when resolving the same directory on the same filesystem.
Servers or containers with separate disksThey do not share memory.They generate independent caches even when the path string is identical.
Several Fargate tasks with local storageEach process and task retains its own state.A task does not automatically use another task’s local files.
A volume explicitly mounted in commonIt does not turn containers into one application.Only files actually inside the mounted volume are shared.

In Fargate, ephemeral storage belongs to the task; Linux containers in one task can share it when their volumes and mounts are configured accordingly. It is not a service-wide global disk. See task ephemeral storage.

Persistent shared storage such as EFS requires explicit deployment configuration. That infrastructure capability does not make Orionis automatically coordinate its cache across tasks. The difference between ephemeral and persistent storage is described under ECS storage options.

The consequence for Orionis follows from its use of local paths: plan for regeneration when replacing a task and do not rely on another installation’s file existing. The snapshot contains absolute paths and component references; mixing releases or different configurations in one directory can restore incorrect data. The fingerprint monitors files, not a server identifier or an AWS task.

flowchart TD
    accTitle: Worker memory and disk cache
    A[Installation or task A] --> B[Worker A1: own Application and singletons]
    A --> C[Worker A2: own Application and singletons]
    B --> D[Compiled directory A]
    C --> D
    E[Another task with a separate disk] --> F[Worker B: own memory]
    F --> G[Compiled directory B]

The hash considers monitored files’ paths, mtime and size. Directories contribute *.py files; .env must be declared as a file and exist when compile() is called. Changes exclusively to system variables do not alter that fingerprint. Configuration in already running processes is not rebuilt.

To force reconstruction in the affected installation, run either alternative:

Terminal window
orionis optimize:clear
python -B reactor optimize:clear

The command removes compiled artifacts as well as bytecode and project build directories: see its complete scope. A CLI on another filesystem does not clear a remote task’s disk. Restart the workers that need to load changes; deleting a file does not remove already constructed singletons or rerun an existing application’s configuration.

optimize validates Python sources in memory; it does not warm every cache. To understand initial creation and startup with a valid snapshot, see Lifecycle.