Staatlicher Anbieter

Der State-Provider ermöglicht es Ihnen, Daten auf der Vonage Cloud Runtime-Plattform zu speichern und abzurufen. Er unterstützt Key-Value-Speicher, Hash-Maps, geordnete Listen und Volltextsuche - alles auf Basis von Redis.

Initialisierung

Warnung: Do nicht aufrufen vcr.createSession() auf globaler/modulaler Ebene, um den Status zu initialisieren. Dadurch wird eine zufällige, flüchtige Sitzungs-ID erzeugt, unter der gespeicherte Daten für andere Replikate und andere Anfragen unsichtbar sind. Siehe Session-Scoping unten.

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)

Ein optionales Namespace-Präfix kann als zweites Argument übergeben werden, um Schlüsselkollisionen zu vermeiden:

const state = new State(session, 'user:123:');

Staatliches Scoping

Das ist wichtig: Die Zustandsdaten sind auf die zur Erstellung der Zustandsinstanz verwendete Sitzung beschränkt. Wenn Sie eine zufällige Sitzung verwenden (vcr.createSession()), ist der Zugriff auf die Daten nur mit genau dieser Sitzungs-ID möglich. Solange Sie diese ID nicht persistieren und freigeben, kann keine andere Anfrage oder Replik die Daten erreichen. Wählen Sie Ihre Sitzung immer mit Bedacht.

Umfang Wie man Zugang erhält Sichtbarkeit
Zustand der Sitzung new State(session) Isoliert für die spezifische Sitzung. Gelöscht, wenn die TTL der Sitzung abläuft.
Zustand der Instanz vcr.getInstanceState() Wird von allen Replikaten der bereitgestellten Instanz gemeinsam genutzt.
Account-Status vcr.getAccountState() Wird von allen Applikationen im Vonage Account gemeinsam genutzt.

Wann ist welcher Bereich zu verwenden?

  • Zustand der Instanz - Verwenden Sie diese Option für gemeinsam genutzte Zähler, Caches, Konfigurationen oder andere Daten, die von allen Replikaten gelesen/geschrieben werden müssen. Dies ist der korrekte Standard für die meisten gemeinsam genutzten Zustände.
  • Sitzungsstatus mit deterministischer ID - Verwendung für Daten, die auf eine bestimmte Konversation, einen Benutzer oder einen Arbeitsablauf beschränkt sind. Erstellen Sie die Sitzung mit vcr.createSessionWithId(id) unter Verwendung einer ID aus dem Anfragekontext (z. B., conversation_uuid, Absender-Telefonnummer, Benutzer-ID).
  • Account-Status - Verwendung für anwendungsübergreifende Daten wie gemeinsame Blocklisten oder Konfigurationen.
// 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();

Siehe Zustandslose Architektur für ausführliche Anleitungen zur Sitzungsplanung und zu häufigen Fallstricken.

Key-Value-Operationen

Methode Unterschrift Rückgabe Beschreibung
set set<T>(key, value) Promise<string> ("OK") Einen Wert unter einem Schlüssel speichern
get get<T>(key) Promise<T> Abrufen des Wertes für einen Schlüssel
delete delete(key) Promise<string> ("1"/"0") Löscht einen Schlüssel. Gibt "1" zurück, wenn gelöscht, "0", wenn nicht gefunden
increment increment(key, value) Promise<string> Atomares Erhöhen einer numerischen Taste um value
decrement decrement(key, value) Promise<string> Atomares Dekrementieren einer numerischen Taste um value
expire expire(key, seconds, option?) Promise<string> ("1"/"0") TTL für einen Schlüssel in Sekunden festlegen

Optionen ablaufen

Die fakultative option Parameter auf expire akzeptiert eine EXPIRE_OPTION Enum-Wert:

Option Beschreibung
NX Ablauf nur einstellen, wenn der Schlüssel noch nicht abgelaufen ist
XX Ablaufdatum nur setzen, wenn der Schlüssel bereits ein Ablaufdatum hat
GT Ablauf nur einstellen, wenn der neue Ablauf größer ist als der aktuelle
LT Ablauf nur einstellen, wenn der neue Ablauf kürzer ist als der aktuelle
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"

HashMap-Operationen

Operiert auf Feldern innerhalb einer benannten Hashtabelle.

Methode Unterschrift Rückgabe Beschreibung
mapSet mapSet(table, keyValuePairs) Promise<string> Ein oder mehrere Schlüssel-Wert-Paare in einer Hash-Tabelle festlegen
mapGetValue mapGetValue(table, key) Promise<string> Abrufen eines einzelnen Feldwertes
mapGetMultiple mapGetMultiple(table, keys) Promise<string[]> Mehrere Feldwerte nach Schlüssel abrufen
mapGetAll mapGetAll(table) Promise<Record<string, string>> Alle Felder und Werte abrufen
mapGetValues mapGetValues(table) Promise<string[]> Alle Werte abrufen (ohne Schlüssel)
mapDelete mapDelete(table, keys) Promise<string> Ein oder mehrere Felder löschen
mapExists mapExists(table, key) Promise<string> ("1"/"0") Prüfen, ob ein Feld existiert
mapIncrement mapIncrement(table, key, value) Promise<string> Atomares Inkrementieren eines Feldwertes
mapLength mapLength(table) Promise<string> Anzahl der Felder in der Tabelle ermitteln
mapScan mapScan(table, cursor, pattern?, count?) Promise<[string, string[]]> Iterieren von Feldern mit einem 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']);

Scannen einer Hash-Tabelle

mapScan iteriert über Felder mit Hilfe eines Cursors. Start bei "0" und fahren fort, bis der zurückgegebene Cursor "0" wieder:

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');

Liste Operationen

Geordneter Listenspeicher, der durch Redis-Listen unterstützt wird.

Methode Unterschrift Rückgabe Beschreibung
listAppend listAppend<T>(list, value) Promise<string> Hinzufügen eines Wertes am Ende der Liste
listPrepend listPrepend<T>(list, value) Promise<string> Einen Wert an den Anfang der Liste setzen
listEndPop listEndPop<T>(list, count?) Promise<T[]> Werte vom Ende entfernen und zurückgeben (Standard: 1)
listStartPop listStartPop<T>(list, count?) Promise<T[]> Werte von Anfang an entfernen und zurückgeben (Standard: 1)
listRemove listRemove<T>(list, value, count?) Promise<string> Vorkommen eines Wertes entfernen. Positiv count: vom Kopf; negativ: vom Schwanz; 0: alle
listTrim listTrim(list, startPos, endPos) Promise<string> ("OK") Trimmen der Liste auf den angegebenen Bereich
listInsert listInsert<T>(list, before, pivot, value) Promise<string> Fügen Sie einen Wert vor (true) oder nach (false) einen Pivot-Wert
listIndex listIndex<T>(list, position) Promise<T> Abrufen des Wertes an einer Position
listSet listSet<T>(list, position, value) Promise<string> ("OK") Setzen des Wertes an einer Position
listLength listLength(list) Promise<string> Anzahl der Elemente in der Liste ermitteln
listRange listRange<T>(list, startPos?, endPos?) Promise<T[]> Einen Bereich von Werten abrufen (Standard: gesamte Liste)
// 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);

Volltextsuche

Erstellung durchsuchbarer Indizes über die in State gespeicherten Hash-Map-Daten.

Methode Unterschrift Rückgabe Beschreibung
createIndex createIndex(name, options) Promise<string> Einen Suchindex erstellen
search search(index, query, options?) Promise<string> Suche in einem Index
dropIndex dropIndex(index, deleteDocs?) Promise<boolean> Einen Index löschen. Übergeben Sie true um auch die indizierten Dokumente zu löschen

Erstellen eines Indexes

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 },
  ],
});

Suche auf

// 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,
});

Verwerfen eines Index

// 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);