10.1 Сервисы
@v(2) pub(api) service Users {
@readonly @cache(ttl: USER_CACHE_TTL)
rpc get(id: UserId) -> User | NotFound
@idempotent(key: r => r.requestId) @retry(STD_RETRIES)
rpc create(requestId: RequestId, name: Name, email: Email?) -> User
@resumable
rpc watch(id: UserId) -> stream<UserEvent>
}
impl Users {
dep db: Db
rpc get(id) { db.find(User, id) ?? fail NotFound{ what: "user" } }
rpc create(requestId, name, email) { … }
rpc watch(id) { UserEvents.subscribe(key: id) }
}serviceобъявляет контракт: наборrpcс именованными параметрами и типом результата. Параметры образуют сообщение запроса, результат — сообщение ответа (теги по §9.2).- В программе ДОЛЖНА быть ровно одна
implдля каждого сервиса, если он не объявленextern service(клиент к внешнему сервису, §16.3). - В
implтипы параметров и результата МОГУТ опускаться — берутся изservice. Эффекты обработчика не ограничены. - Зависимости обработчика объявляются
dep имя: Тип(§12.7). - Ошибки результата передаются как типизированные детали ошибки gRPC. Код статуса — из
@grpc_status(code)на типе ошибки, по умолчаниюFAILED_PRECONDITION.NetError↔ статусы:Timeout—DEADLINE_EXCEEDED,Unavailable—UNAVAILABLE,Cancelled—CANCELLED,AccessDenied—PERMISSION_DENIED/UNAUTHENTICATED,ProtocolError— остальные.
Вызов:
| Форма | Маршрутизация |
|---|---|
Users.get(id) | через кластер (§12.3): локально, если узел обслуживает Users, иначе по сети |
Users.at(node).get(id) | на конкретный узел кластера |
Users.connect(addr, tls: opts) | клиент к внешнему адресу; возвращает Client<Users> |
Контекст ctx доступен в обработчике и пробрасывается в исходящие вызовы: ctx.caller: Principal, ctx.deadline, ctx.traceId, ctx.meta: Map<str, str>, ctx.node.
Связанные диагностики
duplicate-impl, impl-signature-mismatch, missing-impl, missing-rpc-impl, unknown-rpc
См. также
Исходник: docs/spec/oxl-standard.md