Services

Services supply the shared, run-scoped capabilities and data that components, the policy, and the engine itself draw on. Where a component computes a value, a service provides a resource: the decoded records and dataset statistics, the process state such as device, seed, and rank, the backing record store, the batched data loaders, and the metric computations. Components request the services they need by name.

Each service is configured under its own key in the services section. The built-in services are independent subsystems, each documented on its own page:

services:
  state:   { ... }
  data:    { ... }
  record:  { ... }
  decode:  { ... }
  metrics: { ... }

How it Works

A service is a plugin keyed by its section name. A service may declare dependencies on other services; the engine builds the configured services, verifies that every declared dependency is present, and attaches them in dependency order so that each service can rely on those it depends upon. A dependency cycle is reported as a configuration error.

Registering a new service

The services section accepts user-defined services in addition to the built-in set. A service is a subclass of Service that declares a name and version and is registered with ServiceFactory; it may list other services it needs in the deps class attribute so the engine attaches them first.

from typing import Any, ClassVar

from icegraph.engine.services.service import Service
from icegraph.engine.services.factory import ServiceFactory

from .config import MyServiceConfig

class MyService(Service[MyServiceConfig]):
    name: ClassVar[str] = "my-service"
    version: ClassVar[int] = 1
    deps = ("state",)

    @classmethod
    def validate_config(cls, config: dict[str, Any]) -> MyServiceConfig:
        return MyServiceConfig(**config)

    def build(self) -> None:
        ...

ServiceFactory.register(MyService)

Once registered, other services or components reach it through services.require("my-service").