Сервисы и rpc
service объявляет контракт — набор rpc-методов; impl его реализует. Вызов Users.get(1) не знает, где живёт реализация:
в этом же процессе или на другом узле кластера. Результат вызова всегда включает NetError (§6.5): сеть может подвести,
даже если сейчас вызов идёт в процессе. Доступ к методам закрыт по умолчанию — @public открывает наружу, @internal для
вызовов между сервисами (§13.4).
@error data NotFound { what: str }
service Users {
@public rpc get(id: u64) -> str | NotFound
@public rpc count() -> i32
}
impl Users {
rpc get(id) { // типы параметров берутся из контракта
if id == 1 { "ann" } else { fail NotFound{ what: "user {id}" } }
}
rpc count() { 2 }
}
fn show(r: str | NotFound | NetError) io {
match r {
str s => print("ok {s}")
NotFound e => print("not found: {e.what}")
NetError e => print("net error")
}
}
fn main() io, net {
show(Users.get(1))
show(Users.get(7))
match Users.count() {
i32 n => print("{n} users")
NetError e => print("net error")
}
}ok ann not found: user 7 2 users
Атрибуты rpc#
Поведение метода задаётся атрибутами рядом с контрактом: @timeout(5s) (дедлайн по умолчанию), @idempotent (повтор с тем же ключом возвращает сохранённый ответ), @readonly,
@retry(n, backoff: b) (только вместе с @idempotent или @readonly), @public / @internal / @allow(...); дедлайн вызывающего передаётся дальше по цепочке вызовов (§10.2,
§8.6). Внутри обработчика доступен контекст ctx: вызывающий (ctx.caller), дедлайн, traceId, meta.
service Info {
@timeout(5s)
@public rpc whoami() -> str
}
impl Info {
rpc whoami() {
let anon = ctx.caller is .Anonymous
let live = ctx.deadline > now() && ctx.deadline <= now() + 5s
"anonymous={anon} deadline-ok={live}"
}
}
fn main() io, net, time {
match Info.whoami() {
str s => print(s)
NetError e => print("net error")
}
}anonymous=true deadline-ok=true
Клиент к внешнему адресу#
Users.connect("host:port", tls: ClientTls{}) возвращает Client<Users> — те же методы, но к конкретному адресу
(например, к сервису вне кластера). Сервисы gRPC подключаются через import proto (§16.3), а клиентов на других
языках создаёт oxl gen. Контракты проверяются на совместимость файлом oxl.schema.lock (§9.2,
III.2): ломающее изменение схемы — ошибка компиляции (schema-break).