Lifecycle & Dependency Injection
Understanding how MicroCoreOS boots and wires dependencies is key to mastering the architecture.
🚀 The Boot Sequence
The Kernel manages a strict lifecycle to ensure all resources are ready before the first request arrives.
- Tool Setup:
- Every Tool's
setup()method is called. - This is where tools allocate resources (DB connections, HTTP server instances, redis clients).
- Fail-Safe Cleanup Guarantee: If any tool fails or is cancelled during
setup(), the tool itself and all previously initialized tools release their acquired resources immediately viashutdown()before the exception is raised. No leaked connection pools, unclosed file descriptors, or dangling tasks are left behind.
- Every Tool's
- Plugin Initialization (DI phase):
- Plugins are discovered in
domains/*/plugins/. - The Kernel inspects the
__init__signature of each plugin. - It resolves and injects the requested Tools by name.
- Plugins are discovered in
- Plugin Boot:
- Every Plugin's
on_boot()is called. - Plugins register their interest: endpoints with
http, subscriptions withevent_bus.
- Every Plugin's
- Boot Completion:
- Tools receive
on_boot_complete(container). This allows tools to interact with other tools now that everything is wired.
- Tools receive
- System Online:
- The HTTP server starts, and the system begins processing events.
💉 Dependency Injection
DI in MicroCoreOS is declarative and name-based.
python
class MyPlugin(BasePlugin):
def __init__(self, db, auth, logger): # I want these tools
self.db = db
self.auth = auth
self.logger = logger- Transparent: No complex configuration or decorators. Just name the tool in your constructor.
- Kernel-Managed: The container handles the singleton lifecycle of tools and delivers them to your plugins.
🧪 Testing with DI
Because dependencies are passed via the constructor, testing a plugin in isolation is trivial using mocks:
python
from unittest.mock import AsyncMock, MagicMock
async def test_my_plugin():
# 1. Prepare mocks
mock_db = AsyncMock()
# 2. Instantiate plugin with mocks (no kernel needed)
plugin = MyPlugin(db=mock_db, auth=MagicMock(), logger=MagicMock())
# 3. Call and Assert
await plugin.execute({"id": 1})
mock_db.query_one.assert_called_once()