Handle asynchronous operations from MCP servers (PixelLab, ElevenLabs, etc.) with intelligent polling, timeout management, and parallel work opportunities. Use when waiting for async jobs, polling status, or managing long-running operations. Provides exponential backoff, ETA-aware waiting, and prevents premature downloads.
Instalar com Codex ou Claude Copie este prompt, cole no Codex, Claude ou outro assistente e deixe que ele revise a página da skill e instale para você.
Um comando direto ignora o prompt de revisão. Verifique a origem antes de executá-lo.
Instruções da origem · Visualização somente leitura
name
async-operation-handler
description
Handle asynchronous operations from MCP servers (PixelLab, ElevenLabs, etc.) with intelligent polling, timeout management, and parallel work opportunities. Use when waiting for async jobs, polling status, or managing long-running operations. Provides exponential backoff, ETA-aware waiting, and prevents premature downloads.
Async Operation Handler
Handle asynchronous operations efficiently with intelligent polling, timeout management, and parallel work opportunities. Reduces async operation overhead by 50-70% and saves 15-30 seconds per operation.
Overview
When working with async operations (PixelLab character generation, ElevenLabs TTS, etc.), use this skill to:
Poll with exponential backoff instead of fixed intervals
Respect API-provided ETAs when available
Handle timeouts gracefully
Use waiting time for parallel work
Prevent premature download attempts
⚠️ CRITICAL: Use Exponential Backoff, Not Fixed Intervals ⚠️
AGENTS WASTE 20-40% OF WAIT TIME BY USING FIXED INTERVALS INSTEAD OF EXPONENTIAL BACKOFF.
The Problem: Fixed intervals (e.g., 30s, 60s) waste time by polling too frequently early and not frequently enough later.
The Solution: Exponential backoff (5s → 10s → 20s → 40s → 60s) adapts to operation progress.
// PixelLab exampleconst character = awaitmcp_pixellab_get_character({ character_id });
if (character.eta_seconds) {
// Wait for ETA, but don't wait longer than current intervalconst waitTime = Math.min(character.eta_seconds * 1000, currentInterval);
awaitsleep(waitTime);
}
ETA-Based Scheduling
Schedule status checks at strategic points based on ETA:
Instead of polling at fixed intervals, schedule checks at percentage milestones of the ETA:
asyncfunctionpollWithETAScheduling(checkStatus: () => Promise<StatusResponse>,
initialETA: number): Promise<StatusResponse> {
const milestones = [
initialETA * 0.10, // Check at 10% of ETA
initialETA * 0.50, // Check at 50% of ETA
initialETA * 0.75, // Check at 75% of ETA
];
let currentMilestone = 0;
const startTime = Date.now();
while (true) {
const elapsed = (Date.now() - startTime) / 1000; // seconds// Check if we've reached the next milestoneif (currentMilestone < milestones.length && elapsed >= milestones[currentMilestone]) {
const status = awaitcheckStatus();
// Update ETA if providedif (status.eta_seconds) {
// Recalculate milestones based on new ETAconst remainingTime = status.eta_seconds;
milestones.splice(0, currentMilestone + 1);
milestones.push(
elapsed + remainingTime * 0.10,
elapsed + remainingTime * 0.50,
elapsed + remainingTime * 0.75
);
currentMilestone = 0;
}
if (status.status === 'completed') {
return status;
}
if (status.status === 'failed') {
thrownewError(`Operation failed: ${status.error || 'Unknown error'}`);
}
currentMilestone++;
}
// If past all milestones, poll more frequently until completeif (currentMilestone >= milestones.length) {
const status = awaitcheckStatus();
if (status.status === 'completed') {
return status;
}
if (status.status === 'failed') {
thrownewError(`Operation failed: ${status.error || 'Unknown error'}`);
}
// Poll every 20 seconds after milestonesawaitsleep(20000);
} else {
// Wait until next milestoneconst nextMilestone = milestones[currentMilestone];
const waitTime = Math.max(1000, (nextMilestone - elapsed) * 1000);
awaitsleep(waitTime);
}
}
}
Example Timeline (ETA: 176 seconds):
0s: Poll → Not ready, ETA: 176s
18s: Poll at 10% (17.6s) → Not ready, ETA: 158s (updated)
88s: Poll at 50% (88s) → Not ready, ETA: 88s (updated)
132s: Poll at 75% (132s) → Not ready, ETA: 44s (updated)
176s: Poll → Ready!
Total: 176s (optimal - no wasted polls)
Benefits:
Reduces API calls by 60-70% compared to fixed intervals
Adapts to changing ETAs dynamically
Checks at strategic points (10%, 50%, 75%) before final completion
More efficient than exponential backoff for operations with reliable ETAs
When to Use ETA-Based Scheduling:
Operations provide reliable ETA information (PixelLab, ElevenLabs)
ETA is reasonably accurate (within 20% variance)
Operation duration is predictable
When to Use Exponential Backoff Instead:
ETA information is unreliable or unavailable
Operation duration is highly variable
Need more frequent early checks for debugging
Pre-Download Validation
ALWAYS verify status === "completed" before download:
// ❌ WRONG: Download immediatelyconst character = awaitcreate_character({ description: "wizard" });
const url = character.download_url; // May be null or locked// ✅ CORRECT: Wait for completionlet character = awaitcreate_character({ description: "wizard" });
while (character.status !== 'completed') {
awaitsleep(5000);
character = awaitget_character({ character_id: character.character_id });
}
// Now safe to downloadconst url = character.download_url;
Problem: Downloading immediately without checking status
// ❌ WRONG: Downloading immediatelyconst character = awaitcreate_character({ description: "wizard" });
download(character.download_url); // May be null or locked!
Why This Is Wrong:
Download URL may be null
File may be locked (HTTP 423)
Operation may not be complete
Correct Solution:
// ✅ CORRECT: Wait for completion firstlet character = awaitcreate_character({ description: "wizard" });
while (character.status !== 'completed') {
awaitsleep(interval);
character = awaitget_character({ character_id: character.character_id });
interval = Math.min(interval * 2, 60000);
}
// Now safe to downloaddownload(character.download_url);
❌ Mistake 4: Wait Idly
Problem: Just waiting without doing parallel work
// ❌ WRONG: Just waitingawaitpollAsyncOperation(checkStatus);
// No parallel work done
Why This Is Wrong:
Wastes time that could be used for preparation
No benefit from waiting time
Correct Solution:
// ✅ CORRECT: Do parallel workconst [result, integrationCode] = awaitPromise.all([
pollAsyncOperation(checkStatus),
prepareIntegrationCode() // Prepare while waiting
]);
❌ Mistake 5: Ignoring API-Provided ETAs
Problem: Not using API-provided ETAs when available
// ❌ WRONG: Ignoring ETAconst character = awaitget_character({ character_id });
awaitsleep(30000); // Fixed wait, ignoring ETA
Why This Is Wrong:
API provides accurate ETA
We wait longer than necessary
Wastes time
Correct Solution:
// ✅ CORRECT: Respect ETAconst character = awaitget_character({ character_id });
if (character.eta_seconds) {
awaitsleep(Math.min(character.eta_seconds * 1000, currentInterval));
}
Common Pitfalls
❌ Don't: Poll Too Frequently
// WRONG: Polling every 1-2 secondswhile (status !== 'completed') {
awaitsleep(1000); // Too frequent!
status = awaitcheckStatus();
}
❌ Don't: Download Before Completion
// WRONG: Downloading immediatelyconst character = awaitcreate_character({ description: "wizard" });
download(character.download_url); // May be null or locked!
❌ Don't: Wait Idly
// WRONG: Just waitingawaitpollAsyncOperation(checkStatus);
// No parallel work done// CORRECT: Do parallel workconst [result, integrationCode] = awaitPromise.all([
pollAsyncOperation(checkStatus),
prepareIntegrationCode()
]);
Best Practices
Always use exponential backoff for long operations
Respect API-provided ETAs when available
Verify completion before download (status === "completed")
Use waiting time for parallel work (code preparation, documentation)
Set appropriate timeouts based on operation type
Log progress and ETAs for transparency
Handle HTTP 423 (Locked) errors gracefully
Never poll more frequently than every 5 seconds
Integration with Other Skills
game-asset-pipeline: Uses this skill for asset generation polling
asset-integration-workflow: Uses this skill for async asset operations
pixellab-mcp: MCP server that benefits from this polling pattern