Skip to content

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.

  1. 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 via shutdown() before the exception is raised. No leaked connection pools, unclosed file descriptors, or dangling tasks are left behind.
  2. 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.
  3. Plugin Boot:
    • Every Plugin's on_boot() is called.
    • Plugins register their interest: endpoints with http, subscriptions with event_bus.
  4. Boot Completion:
    • Tools receive on_boot_complete(container). This allows tools to interact with other tools now that everything is wired.
  5. 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()

Released under the MIT License.