Перейти к основному содержимому

Стандартные ресурсы

Plugin-system v1.0 фиксирует пять стандартных ресурсов, доступных в PluginContext.resources. Каждый — протокол (Protocol в Python, interface в TS/Go); конкретные реализации — в рамках соответствующего binding-пакета.

Концептуальный обзор — на странице Ресурсы (Resources DI). Здесь — точные сигнатуры и доступные реализации.

clock

Инъектируемый источник времени. Обязателен для плагинов с idempotency_mode = "output_hash" (инвариант 8).

Интерфейс

from typing import Protocol
from datetime import datetime


class Clock(Protocol):
def now(self) -> datetime:
"""Current time. Takes no arguments."""

def monotonic_ns(self) -> int:
"""Monotonic counter in nanoseconds, used to measure intervals."""

Реализации

ИмяГдеПоведение
SystemClockproductionВозвращает реальное время системы.
FrozenClock(now)тестыВозвращает фиксированное время, не меняется (если не вызван advance()).

rng

Инъектируемый источник случайности. Обязателен для плагинов с idempotency_mode = "output_hash".

Интерфейс

class Rng(Protocol):
def next_float(self) -> float:
"""[0.0, 1.0)"""

def next_int(self, low: int, high: int) -> int:
"""[low, high]"""

def uuid4(self) -> str:
"""A random UUID v4."""

def choice(self, items: list) -> any:
"""A random element of the list."""

Реализации

ИмяГдеПоведение
RandomRngproductionИсточник — OS (os.urandom в Python, crypto.randomBytes в Node, crypto/rand в Go).
DeterministicRng(seed)тестыSeeded PRNG (например, PCG). Воспроизводимый поток.

http_client

Инъектируемый HTTP-клиент, предконфигурированный хостом (CA-bundle, TLS, таймауты, retry-политика).

Интерфейс

class HttpClient(Protocol):
async def get(self, url: str, *, headers: dict = None) -> HttpResponse: ...
async def post(self, url: str, *, json: dict = None, headers: dict = None) -> HttpResponse: ...
async def put(self, url: str, *, json: dict = None, headers: dict = None) -> HttpResponse: ...
async def delete(self, url: str, *, headers: dict = None) -> HttpResponse: ...

class HttpResponse(Protocol):
status_code: int
headers: dict[str, str]
def json(self) -> any: ...
def text(self) -> str: ...

Реализации

ИмяГдеПоведение
HttpClient (production)productionОбёртка над нативным HTTP-клиентом языка (httpx.AsyncClient в Python, fetch в TS, net/http.Client в Go) с host-конфигом.

:::info Reference test implementation в Phase 2 В 0.1.x готовая тестовая реализация HttpClient ещё не входит в публичный API ни одного биндинга. Тесты подключают свою реализацию, удовлетворяющую протоколу HttpClient (тривиальный класс с предопределёнными ответами). Стандартный набор тестовых фейков для HttpClient появится в Phase 2. :::

blob_store

Абстрактное хранилище блобов (байтовых объектов).

Интерфейс

class BlobStore(Protocol):
async def put(self, key: str, data: bytes, *, content_type: str = None) -> None: ...
async def get(self, key: str) -> bytes: ...
async def delete(self, key: str) -> None: ...
async def list(self, prefix: str = "") -> list[str]: ...
async def exists(self, key: str) -> bool: ...

Реализации

ИмяГдеПоведение
FileBlobStore(root)dev / in-processХранит файлы в локальной папке.
S3BlobStore(bucket, client)production (Phase 1+)S3-совместимый backend.
InMemoryBlobStoreтестыdict[str, bytes] в памяти, cleanup на teardown.

tmpdir

Временная директория с автоочисткой.

Интерфейс

from pathlib import Path
from typing import Protocol


class TempDir(Protocol):
path: Path
def create_file(self, name: str, *, suffix: str = "") -> Path: ...
def create_subdir(self, name: str) -> Path: ...

Реализации

ИмяГдеПоведение
SystemTempDirproductionСоздаёт директорию в os.tempdir(), удаляет на teardown.
InMemoryTempDirтестыВиртуальная ФС в памяти (например, через pyfakefs).

Кастомные ресурсы

Приложение регистрирует любые собственные ресурсы через ResourceRegistry:

resources.register("postgres", await create_pg_pool())
resources.register("tenant_registry", TenantRegistryImpl(...))
resources.register("rate_limiter", RateLimiter(...))

Плагин объявляет их в манифесте (resources.required / resources.optional), получает через ctx.resources.postgres, ctx.resources.tenant_registry и т.д.

Имена кастомных ресурсов — на усмотрение приложения; соглашение — snake_case.

Lifecycle

  1. Application startup: host создаёт ResourceRegistry, заполняет стандартными и кастомными ресурсами.
  2. discover(): ресурсы передаются в реестр через параметр resources=.
  3. setup() каждого плагина: плагин читает нужные ресурсы из ctx.resources.*.
  4. Работа приложения: плагин использует ресурсы в хуках.
  5. teardown() каждого плагина: плагин может освободить всё, что создал поверх ресурсов (но не сами ресурсы — они принадлежат хосту).
  6. Application shutdown: host закрывает ресурсы (БД-пулы, HTTP-клиенты) уже после всех teardown()-вызовов.

Требования к реализациям ресурсов

  • Thread-safe / goroutine-safe. Ресурсы — синглтоны на host, доступны нескольким плагинам одновременно.
  • Протокольно типизированы. Интерфейс обязан быть формально специфицирован.
  • Идемпотентно закрываемы. Повторный close не бросает.

См. также