ETM Connector Runbook (iter-1)
Operational playbook for the Phase 1-a ETM ingestion module. Covers the pre-flight egress check, session cache invalidation, and the iter-1 rate-bucket defaults.
EgressPolicy.FixedIPRequired=true
The real ETM API whitelists inbound IPs. Before starting supplier-sync in prod, verify the pod egresses through an IP registered with ETM operations. Iter-1 does not enforce this automatically; Phase 5 adds an admission gate that blocks startup on misconfig.
Manual pre-flight check
kubectl exec -it supplier-sync-<pod> -- curl -s https://api.ipify.org
# must return the whitelisted IPIf the IP drifts, open a ticket with ETM ops before restarting the pod (a 403-burst from non-whitelisted IPs cascades into AuthRejected counts and eventually trips the MarkFailing circuit — ADR-0024 §4).
Session cache
Redis key tracium:etm:session:<credential_ref> with TTL equal to the SUPPLIER_ETM_SESSION_TTL env (default 2h). Clear manually if an ETM session is stuck:
redis-cli -n 0 DEL tracium:etm:session:etm-systemThe SessionManager transparently falls back to an in-memory cache when Redis is unavailable; dev stacks do not require Redis to exercise the ETM loop.
Rate buckets
Iter-1 defaults (override via RATELIMIT_* env):
AuthBucket: 1 req / 120s (RATELIMIT_AUTH_RPS=0.008333,RATELIMIT_AUTH_BURST=1). Used onPOST /user/loginonly.DataBucket[goods|price|remains|async_poll]: 1 req/s shared across classes in iter-1. Phase 2 splits into per-class buckets once per-endpoint configs move into the DB-backed supplier profile.
See platform/ratebuckets/README.md for the token-bucket semantics and Redis key layout.
Environment variables
| Variable | Default | Purpose |
|---|---|---|
SUPPLIER_ETM_BASE_URL | (empty — module disabled) | ETM API root: http://mock-etm:9000, https://itest2.etm.ru/api/v1, or https://ipro.etm.ru/api/v1 |
SUPPLIER_ETM_LOGIN | — | Account login |
SUPPLIER_ETM_PASSWORD | — | Account password |
SUPPLIER_ETM_SESSION_TTL | 2h | Session cache TTL |
SUPPLIER_ETM_SEED_FILE | backend/config/etm-seed.yaml | Iter-1 seed enumerator YAML |
Empty SUPPLIER_ETM_BASE_URL disables the entire ETM module — ingestion/infra/etm/di.go providers return nil and the orchestrator fails loudly on first use (operator misconfig).
Special SKUs (mock-ETM)
deploy/docker/resources/mock-etm/ ships deterministic fixtures for the docker-compose test profile:
ABC123— happy path, returns full goods/price/remains fixtures.NOTFOUND— 404 on every endpoint; exercises the ErrNotFound branch.RATELIMITED— 429 withRetry-After: 60on/price; exercises ErrRateLimited.type=etm&session-id=mock-session— required on data-plane calls (other values → 403 for SessionExpired coverage).
Bring up the mock:
cd deploy/docker
docker compose --profile test up -d mock-etmManual smoke against ETM test/prod
Provider-contract suite includes a gated live-smoke. Default target is itest2; override TRACIUM_ETM_BASE_URL when prod parity is required.
cd backend
TRACIUM_ETM_REAL=1 \
TRACIUM_ETM_BASE_URL=https://itest2.etm.ru/api/v1 \
TRACIUM_ETM_LOGIN=<login> \
TRACIUM_ETM_PASSWORD=<password> \
TRACIUM_ETM_SAMPLE_SKU=9536092 \
go test -tags=provider_contract ./test/provider-contract -run TestETMContract_RealServiceSmoke -count=1