OxL Reference

src/cluster.oxl

oxl
use self.limits.*
use self.config { App }
use self.users { Users }
use self.orders { Orders }
use self.cart { Cart }
use self.checkout { Shop, Inventory, Payments, Recs }
use self.photos { Blobs }
use self.model { AppRole }
use std.orm { Db }

// Один бинарник на все узлы; роль узла определяет, что он поднимает.
// Окружение приёмки переопределяет объявление: `--seeds static[…]` (вместо k8s), `--tls-cert/--tls-key` (вместо ACME),
// локальный JWKS `OXL_AUTH_JWKS` (вместо внешнего издателя), `OXL_SHARDS` (вместо 256 шардов).
cluster shop {
  seeds k8s(label: "app=shop")                      // как узлы находят друг друга
  auth { jwt(issuer: AUTH_ISSUER); roles from claim("roles") as AppRole }   // проверка токенов пользователей
  defaults { timeout STD_TIMEOUT; drain DRAIN_TIMEOUT }   // значения по умолчанию для всех rpc
  trace_sample 0.05                                 // доля запросов, трассируемых по умолчанию (флаг --trace-sample переопределяет)

  // api: публичные сервисы и корзины, наружу на 443 с сертификатом ACME
  role api { serves Users, Orders, Shop; hosts Cart; replicas 3..10; expose 443 tls(acme: PUBLIC_DOMAIN) }
  // storage: встроенное хранилище (журнал, топики, состояние акторов), 3 реплики каждого шарда
  role storage { journal; shards STORAGE_SHARDS; replication 3 }
  // saga: выполняет саги и задачу-лидера статистики
  role saga { runs sagas; runs leader("stats") }
  // gpu и ml: только для шагов пайплайна on gpu / on ml; узлы с нужными метками
  role gpu { needs label("gpu=true") }
  role ml { needs label("ml=true") }

  // Роль узла: переменная окружения → метка узла → автоматически по нехватке реплик
  assign by env("OXL_ROLE") else label("oxl/role") else auto
}

// Зависимости: создаются один раз на узле при старте.
// Без for role — на всех ролях; клиенты внешних систем нужны только саге (Recs — роли api).
provide Db = Db.open(App.get().dbUrl)!
provide ActorRef<Blobs> = spawn Blobs()
provide Client<Inventory> = Inventory.connect(App.get().inventoryAddr, tls: ClientTls{}) for role saga
provide Client<Payments> = Payments.connect(App.get().paymentsAddr, tls: ClientTls{}) for role saga
provide Client<Recs> = Recs.connect(App.get().recsAddr, tls: ClientTls{}) for role api

Source: examples/shop/src/cluster.oxl