Adobe Load & Scale
Overview
Load testing and scaling strategies for Adobe API integrations. Adobe APIs are async and relatively slow (5-30s per operation), requiring different load testing approaches than typical REST APIs.
Prerequisites
- k6 load testing tool installed (
npm install -g k6orbrew install k6) - Adobe Developer Console credentials for testing (separate from production)
- Kubernetes cluster with HPA configured (for auto-scaling)
- Understanding of your Adobe API rate limits
Instructions
Step 1: k6 Load Test for Firefly API
// adobe-firefly-load.js
import http from 'k6/http';
import { check, sleep } from 'k6';
import { Rate, Trend } from 'k6/metrics';
const errorRate = new Rate('adobe_errors');
const fireflyDuration = new Trend('firefly_duration');
export const options = {
stages: [
{ duration: '1m', target: 2 }, // Warm up (Adobe APIs are slow)
{ duration: '3m', target: 5 }, // Steady state
{ duration: '2m', target: 10 }, // Stress (watch for 429s)
{ duration: '1m', target: 0 }, // Ramp down
],
thresholds: {
http_req_duration: ['p(95)<30000'], // 30s — Firefly is async/slow
adobe_errors: ['rate<0.05'], // < 5% error rate
},
};
// Pre-generate token (shared across VUs)
const TOKEN = __ENV.ADOBE_ACCESS_TOKEN;
const CLIENT_ID = __ENV.ADOBE_CLIENT_ID;
export default function () {
const response = http.post(
'https://firefly-api.adobe.io/v3/images/generate',
JSON.stringify({
prompt: `Load test image ${Date.now()}`,
n: 1,
size: { width: 512, height: 512 }, // Smallest size for speed
}),
{
headers: {
'Authorization': `Bearer ${TOKEN}`,
'x-api-key': CLIENT_ID,
'Content-Type': 'application/json',
},
timeout: '60s',
}
);
const success = check(response, {
'status is 200': (r) => r.status === 200,
'status is not 429': (r) => r.status !== 429,
});
errorRate.add(!success);
fireflyDuration.add(response.timings.duration);
if (response.status === 429) {
const retryAfter = parseInt(response.headers['Retry-After'] || '30');
console.log(`Rate limited, waiting ${retryAfter}s`);
sleep(retryAfter);
} else {
sleep(3); // Respect rate limits between requests
}
}
Step 2: k6 Load Test for PDF Services
// adobe-pdf-load.js
import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
stages: [
{ duration: '1m', target: 3 },
{ duration: '5m', target: 10 },
{ duration: '1m', target: 0 },
],
thresholds: {
http_req_duration: ['p(95)<15000'], // PDF ops are faster than Firefly
http_req_failed: ['rate<0.02'],
},
};
export default function () {
// Test your app's PDF endpoint (which calls Adobe PDF Services internally)
const response = http.post(
`${__ENV.APP_URL}/api/extract-pdf`,
http.file(open('./test-fixtures/sample-5page.pdf', 'b'), 'test.pdf'),
{ timeout: '30s' }
);
check(response, {
'extraction successful': (r) => r.status === 200,
'has text content': (r) => JSON.parse(r.body).text?.length > 0,
});
sleep(2);
}
Step 3: Run Load Tests
# 1. Generate access token for load test
export ADOBE_ACCESS_TOKEN=$(curl -s -X POST \
'https://ims-na1.adobelogin.com/ims/token/v3' \
-d "client_id=${ADOBE_CLIENT_ID}&client_secret=${ADOBE_CLIENT_SECRET}&grant_type=client_credentials&scope=${ADOBE_SCOPES}" | jq -r '.access_token')
# 2. Run Firefly load test
k6 run --env ADOBE_ACCESS_TOKEN=${ADOBE_ACCESS_TOKEN} \
--env ADOBE_CLIENT_ID=${ADOBE_CLIENT_ID} \
adobe-firefly-load.js
# 3. Run PDF Services load test
k6 run --env APP_URL=https://staging.yourapp.com \
adobe-pdf-load.js
# 4. Export results to InfluxDB for Grafana dashboards
k6 run --out influxdb=http://localhost:8086/k6 adobe-firefly-load.js
Step 4: Kubernetes Auto-Scaling
# k8s/adobe-hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: adobe-service-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: adobe-service
minReplicas: 2
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 60
# Scale on pending Adobe jobs (custom metric from Prometheus)
- type: Pods
pods:
metric:
name: adobe_pending_jobs
target:
type: AverageValue
averageValue: 5
behavior:
scaleUp:
stabilizationWindowSeconds: 60
policies:
- type: Pods
value: 2
periodSeconds: 60
scaleDown:
stabilizationWindowSeconds: 300 # Slow scale-down (Adobe jobs are long)
Step 5: Capacity Planning
// Adobe-specific capacity considerations:
// 1. Each Firefly request blocks for 5-30s — need many concurrent workers
// 2. PDF Services is faster (2-10s) but has monthly transaction limits
// 3. Photoshop API jobs are async — workers poll and block on I/O
// 4. IMS token generation is shared — cache aggressively
interface AdobeCapacityPlan {
api: string;
peakRps: number;
avgLatencyMs: number;
concurrencyNeeded: number; // peakRps * avgLatencyMs / 1000
podsNeeded: number; // concurrencyNeeded / connectionsPerPod
monthlyTransactions: number;
tierNeeded: string;
}
function planCapacity(metrics: {
peakRps: number;
avgLatencyMs: number;
connectionsPerPod: number;
}): AdobeCapacityPlan {
const concurrency = metrics.peakRps * metrics.avgLatencyMs / 1000;
const pods = Math.ceil(concurrency / metrics.connectionsPerPod);
return {
api: 'firefly',
peakRps: metrics.peakRps,
avgLatencyMs: metrics.avgLatencyMs,
concurrencyNeeded: Math.ceil(concurrency),
podsNeeded: pods,
monthlyTransactions: metrics.peakRps * 3600 * 8 * 22, // 8h/day, 22 days
tierNeeded: pods > 5 ? 'Enterprise' : 'Pro',
};
}
// Example: 2 RPS peak, 10s avg latency, 5 connections per pod
// concurrency = 2 * 10 = 20 concurrent requests
// pods = 20 / 5 = 4 pods minimum
Output
- k6 load test scripts for Firefly and PDF Services
- Kubernetes HPA with Adobe-aware scaling metrics
- Capacity planning model accounting for async API latency
- Benchmark results template for documentation
Error Handling
| Issue | Cause | Solution | |-------|-------|----------| | All requests 429 in k6 | Rate limit exceeded | Reduce VU count; add sleep | | k6 timeout | Adobe API > 60s | Increase k6 request timeout | | HPA not scaling | Custom metric not exposed | Verify Prometheus metric exists | | Token expires mid-test | Long test duration | Token valid 24h; pre-generate |
Resources
Next Steps
For reliability patterns, see adobe-reliability-patterns.