| name | documenso-performance-tuning |
| description | Optimize Documenso integration performance with caching, batching, and efficient patterns.
Use when improving response times, reducing API calls,
or optimizing bulk document operations.
Trigger with phrases like "documenso performance", "optimize documenso",
"documenso caching", "documenso batch operations".
|
| allowed-tools | Read, Write, Edit |
| version | 1.0.0 |
| license | MIT |
| author | Jeremy Longshore <jeremy@intentsolutions.io> |
Documenso Performance Tuning
Overview
Optimize Documenso integrations for speed, efficiency, and scalability.
Prerequisites
- Working Documenso integration
- Performance monitoring in place
- Redis or caching layer (recommended)
Caching Strategies
Step 1: Document Metadata Cache
import Redis from "ioredis";
const redis = new Redis(process.env.REDIS_URL);
const CACHE_TTL = 300;
interface CachedDocument {
id: string;
title: string;
status: string;
recipientCount: number;
cachedAt: string;
}
async function getDocumentCached(
documentId: string
): Promise<CachedDocument | null> {
const cacheKey = `doc:${documentId}`;
const cached = await redis.get(cacheKey);
if (cached) {
return JSON.parse(cached);
}
const client = getDocumensoClient();
const doc = await client.documents.getV0({ documentId });
const cacheData: CachedDocument = {
id: doc.id!,
title: doc.title!,
status: doc.status!,
recipientCount: doc.recipients?.length ?? 0,
cachedAt: new Date().toISOString(),
};
await redis.setex(cacheKey, CACHE_TTL, JSON.stringify(cacheData));
return cacheData;
}
async function invalidateDocumentCache(documentId: string): Promise<void> {
await redis.del(`doc:${documentId}`);
}
Step 2: Template Cache
const TEMPLATE_CACHE_TTL = 3600;
async function getTemplateCached(templateId: string) {
const cacheKey = `tmpl:${templateId}`;
const cached = await redis.get(cacheKey);
if (cached) {
return JSON.parse(cached);
}
const client = getDocumensoClient();
const template = await client.templates.getV0({ templateId });
await redis.setex(cacheKey, TEMPLATE_CACHE_TTL, JSON.stringify(template));
return template;
}
async function warmTemplateCache(templateIds: string[]): Promise<void> {
const client = getDocumensoClient();
console.log(`Warming cache for ${templateIds.length} templates...`);
for ( templateId templateIds) {
{
(templateId);
} (error) {
.();
}
}
}
Batch Operations
Step 3: Batch Document Creation
import PQueue from "p-queue";
interface DocumentInput {
title: string;
templateId: string;
recipients: Array<{ email: string; name: string }>;
}
async function batchCreateDocuments(
inputs: DocumentInput[]
): Promise<Map<string, string>> {
const results = new Map<string, string>();
const queue = new PQueue({
concurrency: 3,
interval: 1000,
intervalCap: 5,
});
const promises = inputs.map((input) =>
queue.add(async () => {
const envelope = await client.envelopes.useV0({
: input.,
: input.,
: input..( ({
: r.,
: r.,
: i,
})),
});
results.(input., envelope.!);
envelope;
})
);
.(promises);
results;
}
Step 4: Batch Recipient Updates
async function addRecipientsBatch(
documentId: string,
recipients: Array<{ email: string; name: string; role: string }>
): Promise<string[]> {
const result = await client.documentsRecipients.createManyV0({
documentId,
recipients: recipients.map((r) => ({
email: r.email,
name: r.name,
role: r.role as any,
})),
});
return result.recipientIds ?? [];
}
Connection Pooling
Step 5: HTTP Client Optimization
import { Documenso } from "@documenso/sdk-typescript";
let clientInstance: Documenso | null = null;
export function getDocumensoClient(): Documenso {
if (!clientInstance) {
clientInstance = new Documenso({
apiKey: process.env.DOCUMENSO_API_KEY ?? "",
timeoutMs: 30000,
retryConfig: {
strategy: "backoff",
backoff: {
initialInterval: 500,
maxInterval: 30000,
exponent: 1.5,
maxElapsedTime: 120000,
},
retryConnectionErrors: true,
},
});
}
return clientInstance;
}
Response Size Optimization
Step 6: Pagination for Large Lists
async function* iterateDocuments(
pageSize = 100
): AsyncGenerator<DocumentInfo[]> {
let page = 1;
let hasMore = true;
while (hasMore) {
const result = await client.documents.findV0({
page,
perPage: pageSize,
});
const docs = result.documents ?? [];
if (docs.length > 0) {
yield docs;
}
hasMore = docs.length === pageSize;
page++;
}
}
async function processAllDocuments() {
for await (const batch of iterateDocuments(100)) {
console.log(`Processing ${batch.length} documents...`);
await processBatch(batch);
}
}
Step 7: Field Selection (When Available)
async function getDocumentStatus(documentId: string) {
const doc = await client.documents.getV0({ documentId });
return {
id: doc.id,
status: doc.status,
completedAt: doc.completedAt,
};
}
Async Processing
Step 8: Background Job Queue
import Bull from "bull";
const documentQueue = new Bull("document-processing", {
redis: process.env.REDIS_URL,
});
async function createDocumentAsync(input: DocumentInput): Promise<string> {
const job = await documentQueue.add("create-document", input, {
attempts: 3,
backoff: { type: "exponential", delay: 1000 },
});
return job.id.toString();
}
documentQueue.process("create-document", async (job) => {
const { title, templateId, recipients } = job.data;
const envelope = await client.envelopes.useV0({
templateId,
title,
recipients: recipients.map((r: any, i: ) => ({
: r.,
: r.,
: i,
})),
});
{ : envelope. };
});
Performance Monitoring
Step 9: Request Timing
class PerformanceMonitor {
private timings: number[] = [];
async track<T>(operation: () => Promise<T>): Promise<T> {
const start = Date.now();
try {
return await operation();
} finally {
const duration = Date.now() - start;
this.timings.push(duration);
if (this.timings.length > 1000) {
this.timings = this.timings.slice(-1000);
}
}
}
getMetrics() {
const sorted = [...this.timings].sort((a, b) => a - b);
return {
count: this.timings.length,
p50: sorted[Math.(sorted. * )] ?? ,
: sorted[.(sorted. * )] ?? ,
: sorted[.(sorted. * )] ?? ,
:
..( a + b, ) / .. || ,
};
}
}
perfMonitor = ();
() {
perfMonitor.(
client..({ documentId })
);
}
Performance Checklist
Output
- Reduced API latency with caching
- Efficient bulk operations
- Background processing configured
- Performance metrics available
Error Handling
| Performance Issue | Cause | Solution |
|---|
| Slow responses | No caching | Add caching layer |
| Rate limits | Too many requests | Use queue/batching |
| Memory issues | Large responses | Use pagination |
| Timeout errors | Slow processing | Use background jobs |
Resources
Next Steps
For cost optimization, see documenso-cost-tuning.