# Working with the Cache Every Sinch Function has access to a shared key-value cache. In development it uses in-memory storage. In production, the cache is persistent across restarts and shared across all instances of your function. ## Interface | Operation | Node.js | C# | | --- | --- | --- | | Write | `cache.set(key, value, ttl?)` | `cache.Set(key, value, ttl?)` | | Read | `cache.get(key)` | `cache.Get(key)` | | Check existence | `cache.has(key)` | `cache.Exists(key)` | | Delete | `cache.delete(key)` | `cache.Delete(key)` | | Extend TTL | `cache.extend(key, seconds)` | — | | List keys | `cache.keys(pattern?)` | `cache.GetKeys()` | | Batch read | `cache.getMany(keys)` | — | Default TTL: **3600 seconds** (1 hour). ## Accessing the cache Node.js ```typescript import type { FunctionContext, FunctionRequest } from '@sinch/functions-runtime'; export async function myHandler(context: FunctionContext, request: FunctionRequest) { const cache = context.cache; await cache.set('greeting', 'Hello!'); const value = await cache.get('greeting'); // 'Hello!' } ``` C# ```csharp public class FunctionController : SinchController { public async Task MyEndpoint() { var cache = Context.Cache; await cache.Set("greeting", "Hello!"); var value = await cache.Get("greeting"); return Ok(value); } } ``` ## TTL (time to live) Node.js ```typescript await cache.set('short-lived', 'value', 60); // 60 seconds await cache.set('persistent', 'value', 86400 * 30); // 30 days await cache.extend('session:abc123', 300); // extend by 5 minutes ``` C# ```csharp await cache.Set("short-lived", "value", ttlSeconds: 60); await cache.Set("persistent", "value", ttlSeconds: 86400 * 30); ``` ## Storing objects Values are JSON-serialized automatically. Node.js ```typescript interface UserProfile { name: string; plan: string; createdAt: string; } await cache.set( 'user:123', { name: 'Alice', plan: 'pro', createdAt: new Date().toISOString(), }, 3600 ); const profile = await cache.get('user:123'); ``` C# ```csharp public record UserProfile(string Name, string Plan, DateTime CreatedAt); await cache.Set("user:123", new UserProfile("Alice", "pro", DateTime.UtcNow), ttlSeconds: 3600); var profile = await cache.Get("user:123"); ``` ## Common patterns ### Session storage Store caller state across voice callbacks using the call ID as key. Node.js ```typescript // In ICE handler await context.cache.set( `session:${event.callId}`, { callerNumber: event.cli, startTime: Date.now(), }, 600 ); // In PIE handler const session = await context.cache.get<{ callerNumber: string; startTime: number }>( `session:${event.callId}` ); ``` C# ```csharp // In ICE handler await Context.Cache.Set($"session:{callbackData.CallId}", new { CallerNumber = callbackData.Cli, StartTime = DateTime.UtcNow }, ttlSeconds: 600); // In PIE handler var session = await Context.Cache.Get($"session:{callbackData.CallId}"); ``` ### Rate limiting Node.js ```typescript async function isRateLimited( cache: IFunctionCache, caller: string, maxPerHour = 10 ): Promise { const key = `rate:${caller}`; const current = await cache.get(key); if (current === null) { await cache.set(key, 1, 3600); return false; } if (current >= maxPerHour) return true; await cache.set(key, current + 1, 3600); return false; } ``` C# ```csharp private async Task IsRateLimited(string caller, int maxPerHour = 10) { var key = $"rate:{caller}"; var current = await Context.Cache.Get(key); if (current == null) { await Context.Cache.Set(key, "1", ttlSeconds: 3600); return false; } var count = int.Parse(current); if (count >= maxPerHour) return true; await Context.Cache.Set(key, (count + 1).ToString(), ttlSeconds: 3600); return false; } ``` ### Caller lookup cache Node.js ```typescript async function getCustomer(cache: IFunctionCache, phone: string) { const cacheKey = `customer:${phone}`; const cached = await cache.get(cacheKey); if (cached) return cached; const customer = await fetchCustomerFromApi(phone); if (customer) await cache.set(cacheKey, customer, 300); return customer; } ``` C# ```csharp private async Task GetCustomer(string phone) { var cacheKey = $"customer:{phone}"; var cached = await Context.Cache.Get(cacheKey); if (cached != null) return cached; var customer = await FetchCustomerFromApi(phone); if (customer != null) await Context.Cache.Set(cacheKey, customer, ttlSeconds: 300); return customer; } ``` ## Development vs production | Aspect | Development | Production | | --- | --- | --- | | Backend | In-memory | Persistent store | | Persistence | Lost on restart | Survives restarts | | Sharing | Single process only | Shared across all instances | | TTL enforcement | Approximate | Exact | The `IFunctionCache` interface is identical in both environments. No code changes needed when deploying.