Источники конфига
ConfigSource — абстракция над местом, откуда загружается конфигурация. В Phase 1 главный источник — YamlFileSource (файлы на диске), но API рассчитан на расширение. Phase 2+ предусматривает адаптеры для централизованных хранилищ конфигов:
| Источник | Пример | Статус |
|---|---|---|
YamlFileSource | app-config.yaml на диске | Phase 1 (default) |
JsonFileSource | app-config.json на диске | Phase 1 |
InMemorySource (Python/TS) / DictSource (Go) | Dict, собранный программно — для тестов | Phase 1 |
env-интерполяция ${VAR} | Чтение окружения на этапе обработки raw-текста | Phase 1 (встроен, не отдельный source) |
EtcdSource | Ключи в etcd под префиксом | Phase 2 (план) |
ConsulSource | KV store в Consul | Phase 2 (план) |
VaultSource | Секреты в HashiCorp Vault | Phase 2 (план) |
HttpSource | REST endpoint с JSON-ответом | Phase 2 (план) |
SqlSource | Таблица в БД с конфигом, меняющимся в рантайме | Phase 2 (план) |
KubernetesSource | ConfigMap + Secret в Kubernetes | Phase 2 (план) |
Интерфейс
Любой source реализует минимальный контракт:
id: string # уникальный идентификатор источника (например, "yaml:/app/config.yaml")
load(): ConfigTree # одноразовая загрузка (обязательно)
watch?(callback): Subscription # подписка на изменения (опционально)
close?(): void # освобождение ресурсов (опционально)
load() возвращает ConfigTree — дерево значений, которое загрузчик затем мерджит с другими источниками и применяет env-интерполяцию.
watch(callback) — опциональный. Если источник поддерживает watch (файл: через fsnotify; etcd: через gRPC-stream; Kubernetes: через informer), то загрузчик передаёт callback для уведомления об изменениях. Если источник не поддерживает — метод не реализован, подписки на изменения регистрируются, но активируются с active = false.
Базовый сценарий — YamlFileSource
Для большинства dagstack-приложений Config.load(path) — высокоуровневая обёртка над Config.loadFrom([YamlFileSource(path), ...]). Она автоматически обнаруживает и подключает три слоя:
app-config.yaml— base (коммитится).app-config.local.yaml— переопределения разработчика (gitignored).app-config.${DAGSTACK_ENV}.yaml— специфичные для окружения (коммитятся).
Детали слоирования — на странице Слои.
Явное перечисление источников
Когда нужен нестандартный порядок (например, в тестах) или смешение типов источников, используйте Config.loadFrom:
- Python
- TypeScript
- Go
from dagstack.config import Config, YamlFileSource, InMemorySource
config = Config.load_from([
YamlFileSource("app-config.yaml"),
InMemorySource({"database": {"pool_size": 5}}), # test-override
])
import { Config, YamlFileSource, InMemorySource } from "@dagstack/config";
const config = await Config.loadFrom([
new YamlFileSource("app-config.yaml"),
new InMemorySource({ database: { pool_size: 5 } }),
]);
cfg, err := config.LoadFrom(context.Background(), []config.Source{
config.NewYamlFileSource("app-config.yaml"),
config.NewDictSource(config.Tree{"database": map[string]any{"pool_size": 5}}),
})
:::note Имя in-memory источника
В Python и TypeScript источник называется InMemorySource, в Go — DictSource. Это историческое расхождение между биндингами; семантика идентична (in-memory tree, без интерполяции по умолчанию).
:::
Порядок аргументов = порядок приоритета. Первый источник — наименьший приоритет, последний — наибольший (переопределяет предыдущие).
Подстановка env-переменных
Env-переменные — не отдельный ConfigSource, а этап обработки значений в загруженном ConfigTree. Строковые значения вида ${VAR} или ${VAR:-default} интерполируются сразу после source.load(), до merge с другими источниками.
Детали — на странице Подстановка env-переменных.
Watch-семантика и hot-reload
Когда приложение подписывается на изменения своей секции через config.onSectionChange(path, callback), загрузчик регистрирует наблюдателя на каждом источнике, поддерживающем watch:
source.watch(on_source_change)регистрируется во всех источниках.- Любое изменение в источнике → загрузчик заново собирает дерево.
- Новая версия валидируется (если подписанные секции имеют schema).
- Если валидация прошла — подписчики получают новые значения.
- Если валидация не прошла — вся операция перезагрузки откатывается; подписчики не уведомляются (атомарный откат).
Если ни один источник не поддерживает watch — все подписки регистрируются с active = false. Это — не ошибка: приложение может успешно запускаться без hot-reload.
Подробнее — на странице Hot-reload (watch).
Свой собственный ConfigSource
v1.0 контракт фиксирует сигнатуры, но не формат на диске. Если вам нужен кастомный источник (например, ZooKeeper), реализуйте интерфейс и передайте экземпляр в Config.loadFrom:
- Python
- TypeScript
- Go
from dagstack.config import ConfigSource, ConfigTree, Subscription
class ZookeeperSource(ConfigSource):
id = "zookeeper://zk.example.com/my-app"
def __init__(self, host: str, prefix: str):
self._client = zk_connect(host)
self._prefix = prefix
def load(self) -> ConfigTree:
raw = self._client.get_recursive(self._prefix)
return ConfigTree.from_dict(raw)
def watch(self, callback) -> Subscription:
# callback(event) когда дерево меняется
...
def close(self) -> None:
self._client.close()
import type { ConfigSource, ConfigTree, Subscription } from "@dagstack/config";
export class ZookeeperSource implements ConfigSource {
readonly id: string;
constructor(private host: string, private prefix: string) {
this.id = `zookeeper://${host}/${prefix}`;
}
async load(): Promise<ConfigTree> { /* ... */ }
watch(callback: () => void): Subscription { /* ... */ }
close(): void { /* ... */ }
}
type ZookeeperSource struct {
host string
prefix string
}
func (s *ZookeeperSource) ID() string { return fmt.Sprintf("zookeeper://%s/%s", s.host, s.prefix) }
func (s *ZookeeperSource) Load() (config.Tree, error) { /* ... */ }
func (s *ZookeeperSource) Watch(cb func()) (config.Subscription, error) { /* ... */ }
func (s *ZookeeperSource) Close() error { /* ... */ }
См. также
- Слои конфигурации — как YamlFileSource автоматически складывает три файла.
- Подстановка env-переменных — этап после
source.load(). - Hot-reload (watch) — как источники уведомляют о своих изменениях.
- ADR-0001: YAML configuration — нормативный контракт ConfigSource и загрузчика.