Proveedor estatal
El proveedor State te permite almacenar y recuperar datos en la plataforma Vonage Cloud Runtime. Admite almacenamiento clave-valor, mapas de hash, listas ordenadas y búsqueda de texto completo, todo ello con el respaldo de Redis.
Inicialización
Advertencia: Visite no llamada vcr.createSession() en el ámbito global/módulo para inicializar State. Esto crea un identificador de sesión aleatorio y efímero; los datos almacenados en él serán invisibles para otras réplicas y otras solicitudes. Véase Alcance de la sesión abajo.
Node.js:
import { vcr, State } from '@vonage/vcr-sdk';
// WRONG — random session, data siloed to this replica
// const session = vcr.createSession();
// const state = new State(session);
// CORRECT — shared state across all replicas
const state = vcr.getInstanceState();
// CORRECT — per-conversation state with a deterministic ID
app.post('/onCall', async (req, res) => {
const session = vcr.createSessionWithId(req.body.conversation_uuid);
const state = new State(session);
// ...
});
Python:
from vonage_cloud_runtime.vcr import VCR
from vonage_cloud_runtime.providers.state.state import State
vcr = VCR()
# WRONG — random session, data siloed to this replica
# session = vcr.createSession()
# state = State(session)
# CORRECT — shared state across all replicas
state = vcr.getInstanceState()
# CORRECT — per-conversation state with a deterministic ID
session = vcr.createSessionWithId(conversation_uuid)
state = State(session)
Se puede pasar un prefijo de espacio de nombres opcional como segundo argumento para evitar colisiones de claves:
const state = new State(session, 'user:123:');
Ámbito estatal
Importante: Los datos de estado se asignan a la sesión utilizada para crear la instancia de estado. Si utiliza una sesión aleatoria (vcr.createSession()), solo se puede acceder a los datos con ese ID de sesión concreto. A menos que guardes y compartas ese ID, ninguna otra solicitud ni réplica podrá acceder a los datos. Elige siempre tu sesión con cuidado.
| Ámbito de aplicación | Cómo acceder | Visibilidad |
|---|---|---|
| Estado de la sesión | new State(session) |
Limitado a la sesión concreta. Se elimina cuando expira el TTL de la sesión. |
| Estado de la instancia | vcr.getInstanceState() |
Compartido por todas las réplicas de la instancia desplegada. |
| Estado de la cuenta | vcr.getAccountState() |
Compartido en todas las aplicaciones de la cuenta de Vonage. |
Cuándo utilizar cada ámbito:
- Estado de la instancia - Utilícelo para contadores compartidos, cachés, configuración o cualquier dato que todas las réplicas necesiten leer/escribir. Este es el valor predeterminado correcto para la mayoría de los estados compartidos.
- Estado de la sesión con identificador determinista — Se utiliza para datos relacionados con una conversación, un usuario o un flujo de trabajo concretos. Crea la sesión con
vcr.createSessionWithId(id)utilizando un identificador del contexto de la solicitud (por ejemplo,conversation_uuid, número de teléfono del remitente, ID de usuario). - Estado de la cuenta — Se utiliza para datos comunes a varias aplicaciones, como listas de bloqueo compartidas o configuraciones.
// Session state — per-conversation, using a deterministic ID from a callback
const session = vcr.createSessionWithId(req.body.conversation_uuid);
const conversationState = new State(session);
// Instance state — shared across all replicas
const instanceState = vcr.getInstanceState();
// Account state — shared across all applications
const accountState = vcr.getAccountState();
Véase Arquitectura sin Estado para obtener información detallada sobre el alcance de las sesiones y los errores más comunes.
Operaciones clave-valor
| Método | Firma | Devuelve | Descripción |
|---|---|---|---|
set |
set<T>(key, value) |
Promise<string> ("OK") |
Almacenar un valor asociado a una clave |
get |
get<T>(key) |
Promise<T> |
Recuperar el valor de una clave |
delete |
delete(key) |
Promise<string> ("1"/"0") |
Borra una tecla. Devuelve "1" si se ha borrado, "0" si no se ha encontrado |
increment |
increment(key, value) |
Promise<string> |
Incrementar atómicamente una tecla numérica en value |
decrement |
decrement(key, value) |
Promise<string> |
Disminuir atómicamente una tecla numérica en value |
expire |
expire(key, seconds, option?) |
Promise<string> ("1"/"0") |
Establecer el TTL de una clave en segundos |
Opciones de expiración
La opción option parámetro en expire acepta un EXPIRE_OPTION valor de la enumeración:
| Opción | Descripción |
|---|---|
NX |
Establecer caducidad sólo si la clave no tiene caducidad existente |
XX |
Fijar caducidad sólo si la clave ya tiene caducidad |
GT |
Establecer la fecha de caducidad solo si la nueva fecha es posterior a la actual |
LT |
Fijar caducidad sólo si la nueva caducidad es inferior a la actual |
import { vcr, State, EXPIRE_OPTION } from '@vonage/vcr-sdk';
const state = vcr.getInstanceState();
await state.set('counter', 0);
const value = await state.get('counter'); // 0
await state.increment('counter', 5); // "5"
await state.decrement('counter', 2); // "3"
await state.expire('counter', 3600); // expires in 1 hour
await state.expire('counter', 600, EXPIRE_OPTION.LT); // only if < current TTL
await state.delete('counter'); // "1"
Operaciones HashMap
Operar sobre los campos de una tabla hash con nombre.
| Método | Firma | Devuelve | Descripción |
|---|---|---|---|
mapSet |
mapSet(table, keyValuePairs) |
Promise<string> |
Establecer uno o varios pares clave-valor en una tabla hash |
mapGetValue |
mapGetValue(table, key) |
Promise<string> |
Obtener el valor de un campo concreto |
mapGetMultiple |
mapGetMultiple(table, keys) |
Promise<string[]> |
Obtener varios valores de campo por clave |
mapGetAll |
mapGetAll(table) |
Promise<Record<string, string>> |
Obtener todos los campos y valores |
mapGetValues |
mapGetValues(table) |
Promise<string[]> |
Obtener todos los valores (sin claves) |
mapDelete |
mapDelete(table, keys) |
Promise<string> |
Borrar uno o varios campos |
mapExists |
mapExists(table, key) |
Promise<string> ("1"/"0") |
Comprobar si existe un campo |
mapIncrement |
mapIncrement(table, key, value) |
Promise<string> |
Incrementar atómicamente el valor de un campo |
mapLength |
mapLength(table) |
Promise<string> |
Obtener el número de campos de la tabla |
mapScan |
mapScan(table, cursor, pattern?, count?) |
Promise<[string, string[]]> |
Recorrer campos con un cursor |
// Store a user profile as a hash map
await state.mapSet('user:123', {
name: 'Alice',
email: 'alice@example.com',
loginCount: '0',
});
const name = await state.mapGetValue('user:123', 'name'); // "Alice"
const profile = await state.mapGetAll('user:123'); // { name, email, loginCount }
const values = await state.mapGetValues('user:123'); // ["Alice", "alice@example.com", "0"]
const [email, login] = await state.mapGetMultiple('user:123', ['email', 'loginCount']);
await state.mapIncrement('user:123', 'loginCount', 1); // "1"
const exists = await state.mapExists('user:123', 'name'); // "1"
const length = await state.mapLength('user:123'); // "3"
await state.mapDelete('user:123', ['email']);
Exploración de una tabla hash
mapScan itera sobre los campos utilizando un cursor. Comienza en "0" y continuar hasta que el cursor devuelto sea "0" otra vez:
let cursor = '0';
do {
const [nextCursor, fields] = await state.mapScan('user:123', cursor, 'name*', 10);
cursor = nextCursor;
console.log(fields); // alternating [field, value, field, value, ...]
} while (cursor !== '0');
Operaciones con listas
Almacenamiento de listas ordenadas basado en listas de Redis.
| Método | Firma | Devuelve | Descripción |
|---|---|---|---|
listAppend |
listAppend<T>(list, value) |
Promise<string> |
Añadir un valor al final de la lista |
listPrepend |
listPrepend<T>(list, value) |
Promise<string> |
Añadir un valor al principio de la lista |
listEndPop |
listEndPop<T>(list, count?) |
Promise<T[]> |
Eliminar y devolver valores del final (por defecto: 1) |
listStartPop |
listStartPop<T>(list, count?) |
Promise<T[]> |
Eliminar y devolver valores desde el principio (por defecto: 1) |
listRemove |
listRemove<T>(list, value, count?) |
Promise<string> |
Eliminar apariciones de un valor. Positivo countdesde la cabeza; negativo: desde la cola; 0: todos |
listTrim |
listTrim(list, startPos, endPos) |
Promise<string> ("OK") |
Recorta la lista al rango especificado |
listInsert |
listInsert<T>(list, before, pivot, value) |
Promise<string> |
Inserta un valor antes de (true) o después (false) un valor de pivote |
listIndex |
listIndex<T>(list, position) |
Promise<T> |
Obtener el valor en una posición determinada |
listSet |
listSet<T>(list, position, value) |
Promise<string> ("OK") |
Fijar el valor en una posición |
listLength |
listLength(list) |
Promise<string> |
Obtener el número de elementos de la lista |
listRange |
listRange<T>(list, startPos?, endPos?) |
Promise<T[]> |
Obtener un rango de valores (por defecto: lista completa) |
// Build an activity log
await state.listAppend('activity', { action: 'login', ts: Date.now() });
await state.listAppend('activity', { action: 'purchase', ts: Date.now() });
await state.listPrepend('activity', { action: 'signup', ts: Date.now() });
const length = await state.listLength('activity'); // "3"
const all = await state.listRange('activity'); // all items
const last10 = await state.listRange('activity', -10, -1); // last 10 items
// Keep only the most recent 100 entries
await state.listTrim('activity', -100, -1);
// Remove and process items
const [item] = await state.listStartPop('activity');
const [last] = await state.listEndPop('activity');
// Insert before a known value
await state.listInsert('activity', true, { action: 'login' }, { action: 'pre-login' });
// Get and update by position
const first = await state.listIndex('activity', 0);
await state.listSet('activity', 0, { action: 'updated', ts: Date.now() });
// Remove all occurrences of a specific value
await state.listRemove('activity', { action: 'login' }, 0);
Búsqueda de texto completo
Crear índices en los que se puedan realizar búsquedas sobre los datos de los mapas hash almacenados en State.
| Método | Firma | Devuelve | Descripción |
|---|---|---|---|
createIndex |
createIndex(name, options) |
Promise<string> |
Crear un índice de búsqueda |
search |
search(index, query, options?) |
Promise<string> |
Buscar en un índice |
dropIndex |
dropIndex(index, deleteDocs?) |
Promise<boolean> |
Borrar un índice. Pasar true para eliminar también los documentos indexados |
Creación de un índice
await state.createIndex('users-index', {
on: 'HASH',
prefix: {
count: 1,
prefixes: ['user:'],
},
schema: [
{ fieldName: 'name', type: 'TEXT', sortable: true },
{ fieldName: 'email', type: 'TEXT' },
{ fieldName: 'loginCount', type: 'NUMERIC', sortable: true },
],
});
Buscar en
// Full-text search
const results = await state.search('users-index', '@name:Alice');
// With options
const results = await state.search('users-index', '@name:Alice', {
limit: { offset: 0, num: 10 },
sortBy: { field: 'loginCount', order: 'DESC' },
withScores: true,
});
Eliminar un índice
// Drop index only (keep the underlying data)
await state.dropIndex('users-index');
// Drop index and delete all indexed documents
await state.dropIndex('users-index', true);