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