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

KV Store

KV Store — key-value storage, scoped по окружению проекта. В текущем публичном runtime contract KV доступен внутри ONREZA Functions через ctx.kv. Публичного HTTP API для KV нет.

Используйте KV для сессий, короткого cache, rate limiting counters и небольших динамических настроек, которым не нужна реляционная модель.

Surface Статус
ONREZA Functions Поддерживается через ctx.kv
Dashboard Просмотр и ручное редактирование через KV Browser
Compute Apps Пакетный SDK для Compute не является текущим стабильным публичным contract
Public HTTP API Нет

ctx.kv поддерживает шесть операций:

Метод Описание
get(key) Возвращает `Uint8Array
set(key, value, options?) Записывает string или Uint8Array
put(key, value, options?) Алиас set
incr(key, amountOrOptions?, options?) Атомарно увеличивает integer counter
delete(key) Удаляет ключ
list(options?) Возвращает { keys, cursor } по prefix/limit/cursor
export default {
async fetch(request, ctx) {
const decoder = new TextDecoder();
await ctx.kv.set("hello", "world", { ttl: 300 });
const raw = await ctx.kv.get("hello");
const value = raw ? decoder.decode(raw) : null;
return Response.json({ value });
},
};

ttl задаётся в секундах и должен быть неотрицательным integer:

  • ttl не указан — значение не истекает автоматически;
  • ttl: 0 — значение не истекает автоматически;
  • ttl: 60 — значение истечёт примерно через 60 секунд.
await ctx.kv.set("session:123", JSON.stringify({ userId: "u_123" }), {
ttl: 86400,
});

ctx.kv принимает string и Uint8Array. При чтении всегда возвращается Uint8Array | null, поэтому JSON и text декодируйте явно:

const encoder = new TextEncoder();
const decoder = new TextDecoder();
await ctx.kv.set("profile:42", JSON.stringify({ name: "Alice" }));
await ctx.kv.put("avatar:42", encoder.encode("binary-safe value"));
const raw = await ctx.kv.get("profile:42");
const profile = raw ? JSON.parse(decoder.decode(raw)) : null;
let cursor: string | undefined;
do {
const page = await ctx.kv.list({ prefix: "cache:user:", limit: 100, cursor });
for (const key of page.keys) {
await ctx.kv.delete(key);
}
cursor = page.cursor ?? undefined;
} while (cursor);

Runtime list-запросы ограничены backend cap 1000 ключей за запрос. Dashboard KV Browser показывает до 200 записей на страницу, чтобы UI оставался быстрым.

  1. Откройте проект и выберите окружение.
  2. Перейдите во вкладку KV Store.
  3. Используйте поиск по prefix, чтобы найти группу ключей.
  4. Добавляйте, редактируйте или удаляйте entries вручную.

UI полезен для диагностики и точечных правок. Для массовых операций используйте runtime code с пагинацией по ctx.kv.list().

Метрика Hobby Pro Enterprise
Storage/workspace 16 MB 10 GB 100 GB

KV usage покрывается общим usage credit. Ставки Pro: storage — 300 ₽/ГБ-мес, reads — 5 ₽ за 1M read units, writes — 250 ₽ за 1M write units. Подробнее: Лимиты и квоты.

Параметр Лимит
Размер ключа 512 bytes
Размер значения 1 MiB
Runtime list до 1000 ключей за запрос
Dashboard list до 200 записей на страницу
TTL неотрицательное число секунд; 0 = без автоистечения
const decoder = new TextDecoder();
export default {
async request(request, ctx) {
const sessionId = request.headers.get("cookie")?.match(/session=([^;]+)/)?.[1];
if (!sessionId) {
return Response.redirect(new URL("/login", request.url), 307);
}
const raw = await ctx.kv.get(`session:${sessionId}`);
if (!raw) {
return Response.redirect(new URL("/login", request.url), 307);
}
ctx.locals.user = JSON.parse(decoder.decode(raw));
return request;
},
};
const decoder = new TextDecoder();
async function getCachedJson<T>(
ctx: {
kv: {
get(key: string): Promise<Uint8Array | null>;
set(key: string, value: string, options?: { ttl?: number }): Promise<void>;
};
},
key: string,
fetcher: () => Promise<T>,
ttl = 300,
): Promise<T> {
const cached = await ctx.kv.get(key);
if (cached) {
return JSON.parse(decoder.decode(cached)) as T;
}
const value = await fetcher();
await ctx.kv.set(key, JSON.stringify(value), { ttl });
return value;
}
async function rateLimit(ctx, identifier: string, limit = 60, windowSeconds = 60) {
const key = `rate:${identifier}`;
const count = await ctx.kv.incr(key, { ttl: windowSeconds });
return {
allowed: count <= limit,
remaining: Math.max(0, limit - count),
resetIn: windowSeconds,
};
}

incr атомарен в пределах региона. Для глобальных лимитов между регионами ожидайте небольшое окно eventual consistency.

  • Используйте префиксы: session:, cache:, rate:, config:.
  • Храните JSON как string и декодируйте явно через TextDecoder.
  • Задавайте TTL для временных ключей.
  • Не храните большие файлы: value cap — 1 MiB.
  • Для строгих транзакций и сложных запросов используйте Managed PostgreSQL.

Проверьте, что функция выполняется в ONREZA Functions и окружение имеет KV binding. Для локального кода вне Functions ctx.kv недоступен.

Передан отрицательный, дробный или нечисловой TTL. Используйте integer seconds или не передавайте ttl.

limit должен быть positive integer. Используйте небольшие страницы и cursor.