| name | apollo-performance-tuning |
| description | Optimize Apollo.io API performance.
Use when improving API response times, reducing latency,
or optimizing bulk operations.
Trigger with phrases like "apollo performance", "optimize apollo",
"apollo slow", "apollo latency", "speed up apollo".
|
| allowed-tools | Read, Write, Edit, Bash(gh:*), Bash(curl:*) |
| version | 1.0.0 |
| license | MIT |
| author | Jeremy Longshore <jeremy@intentsolutions.io> |
Apollo Performance Tuning
Overview
Optimize Apollo.io API performance through caching, connection pooling, request optimization, and efficient data handling.
Performance Benchmarks
| Operation | Target Latency | Acceptable | Poor |
|---|
| People Search | < 500ms | 500-1500ms | > 1500ms |
| Person Enrichment | < 1000ms | 1-3s | > 3s |
| Org Enrichment | < 800ms | 800ms-2s | > 2s |
| Bulk Operations | < 5s/100 | 5-15s/100 | > 15s/100 |
1. Connection Pooling
import https from 'https';
import { Agent } from 'https';
const httpsAgent = new Agent({
keepAlive: true,
keepAliveMsecs: 30000,
maxSockets: 10,
maxFreeSockets: 5,
timeout: 30000,
});
export const apolloClient = axios.create({
baseURL: 'https://api.apollo.io/v1',
httpsAgent,
timeout: 30000,
headers: {
'Connection': 'keep-alive',
},
});
2. Response Caching
import { LRUCache } from 'lru-cache';
interface CacheEntry<T> {
data: T;
timestamp: number;
}
class ApolloCache {
private cache: LRUCache<string, CacheEntry<any>>;
constructor() {
this.cache = new LRUCache({
max: 1000,
ttl: 5 * 60 * 1000,
updateAgeOnGet: true,
});
}
generateKey(operation: string, params: any): string {
return `${operation}:${JSON.stringify(params)}`;
}
get<T>(key: string): T | null {
const entry = this.cache.get(key) as CacheEntry<T> | ;
entry?. || ;
}
set<T>(: , : T, ?: ): {
..(key, { data, : .() }, { : ttlMs });
}
(: ): {
( key ..()) {
(key.(pattern)) {
..(key);
}
}
}
() {
{
: ..,
: ..,
};
}
}
apolloCache = ();
cachedRequest<T>(
: ,
: <T>,
: =
): <T> {
cached = apolloCache.<T>(key);
(cached) {
cached;
}
result = ();
apolloCache.(key, result, ttlMs);
result;
}
Cache Strategy by Endpoint
const CACHE_CONFIG = {
'organizations/enrich': 24 * 60 * 60 * 1000,
'organizations/search': 60 * 60 * 1000,
'people/search': 15 * 60 * 1000,
'people/match': 30 * 60 * 1000,
'emailer_campaigns': 5 * 60 * 1000,
'auth/health': 0,
};
export async function apolloRequest<T>(
endpoint: string,
params: any,
method: 'GET' | 'POST' = 'POST'
): Promise<T> {
const ttl = CACHE_CONFIG[endpoint] || 0;
if (ttl === 0) {
apollo.({ method, : , : params });
}
cacheKey = apolloCache.(endpoint, params);
(
cacheKey,
apollo.({ method, : , : params }),
ttl
);
}
3. Request Optimization
Minimize Payload Size
const optimizedSearch = await apollo.searchPeople({
q_organization_domains: ['stripe.com'],
per_page: 25,
person_seniorities: ['vp', 'director'],
});
const contacts = response.people.map(p => ({
id: p.id,
name: p.name,
email: p.email,
title: p.title,
}));
Parallel Requests with Concurrency Limit
import pLimit from 'p-limit';
const limit = pLimit(5);
export async function parallelEnrich(domains: string[]): Promise<Organization[]> {
const results = await Promise.all(
domains.map(domain =>
limit(() => apolloRequest('organizations/enrich', { domain }))
)
);
return results.filter(Boolean);
}
Batch Processing
export async function batchSearch(
criteria: SearchCriteria[],
batchSize: number = 10
): Promise<Person[]> {
const results: Person[] = [];
for (let i = 0; i < criteria.length; i += batchSize) {
const batch = criteria.slice(i, i + batchSize);
const batchResults = await Promise.all(
batch.map(c => apollo.searchPeople(c))
);
results.push(...batchResults.flatMap(r => r.people));
if (i + batchSize < criteria.length) {
await new Promise(r => setTimeout(r, 100));
}
}
return results;
}
4. Query Optimization
Use Specific Filters
const allPeople = await apollo.searchPeople({
q_organization_domains: ['stripe.com'],
per_page: 100,
});
const engineers = allPeople.people.filter(p =>
p.title?.toLowerCase().includes('engineer')
);
const engineers = await apollo.searchPeople({
q_organization_domains: ['stripe.com'],
person_titles: ['engineer', 'developer', 'software'],
per_page: 100,
});
Pagination Strategy
export async function efficientPagination(
searchParams: any,
maxResults: number = 1000
): Promise<Person[]> {
const results: Person[] = [];
let page = 1;
const perPage = 100;
while (results.length < maxResults) {
const response = await apollo.searchPeople({
...searchParams,
page,
per_page: perPage,
});
results.push(...response.people);
if (response.people.length < perPage) {
break;
}
if (page * perPage >= response.pagination.total_entries) {
break;
}
page++;
await new Promise(r => setTimeout(r, 50));
}
return results.slice(, maxResults);
}
5. Performance Monitoring
import { Histogram, Counter } from 'prom-client';
const requestDuration = new Histogram({
name: 'apollo_request_duration_seconds',
help: 'Duration of Apollo API requests',
labelNames: ['endpoint', 'status'],
buckets: [0.1, 0.25, 0.5, 1, 2.5, 5, 10],
});
const requestCounter = new Counter({
name: 'apollo_requests_total',
help: 'Total Apollo API requests',
labelNames: ['endpoint', 'status'],
});
const cacheHitCounter = new Counter({
name: 'apollo_cache_hits_total',
help: 'Apollo cache hits',
labelNames: ['endpoint'],
});
export function instrumentedRequest<T>(
endpoint: string,
requestFn: () => Promise<T>
): Promise<T> {
const end = requestDuration.({ endpoint });
()
.( {
({ : });
requestCounter.({ endpoint, : });
result;
})
.( {
({ : });
requestCounter.({ endpoint, : });
error;
});
}
Performance Dashboard Query
const grafanaQueries = {
avgLatency: 'histogram_quantile(0.95, rate(apollo_request_duration_seconds_bucket[5m]))',
requestRate: 'rate(apollo_requests_total[5m])',
errorRate: 'rate(apollo_requests_total{status="error"}[5m]) / rate(apollo_requests_total[5m])',
cacheHitRate: 'rate(apollo_cache_hits_total[5m]) / rate(apollo_requests_total[5m])',
};
Performance Checklist
Output
- Connection pooling configuration
- LRU cache with TTL per endpoint
- Parallel request patterns
- Query optimization techniques
- Performance monitoring setup
Error Handling
| Issue | Resolution |
|---|
| High latency | Check network, enable caching |
| Cache misses | Tune TTL, check key generation |
| Rate limits | Reduce concurrency, add delays |
| Memory issues | Limit cache size, stream results |
Resources
Next Steps
Proceed to apollo-cost-tuning for cost optimization.