Skip to main content
Glama
waldzellai

Exa Websets MCP Server

by waldzellai
polling.ts4.74 kB
/** * Polling utilities for handling asynchronous operations */ export interface PollingOptions { maxAttempts?: number; intervalMs?: number; maxWaitMs?: number; onProgress?: (attempt: number, status: any) => void; } export interface PollingResult<T> { success: boolean; data?: T; error?: string; attempts: number; duration: number; } /** * Status values that indicate an operation is complete */ export const COMPLETE_STATUSES = ['completed', 'failed', 'cancelled', 'idle'] as const; /** * Status values that indicate an operation is still running */ export const RUNNING_STATUSES = ['pending', 'running', 'processing'] as const; /** * Default polling configurations - keeping intervals reasonable */ export const POLLING_DEFAULTS = { SEARCH: { intervalMs: 2000, // Check every 2 seconds maxAttempts: 30, // Max 1 minute total maxWaitMs: 60000, // 1 minute timeout }, ENHANCEMENT: { intervalMs: 3000, // Check every 3 seconds maxAttempts: 40, // Max 2 minutes total maxWaitMs: 120000, // 2 minute timeout }, DEFAULT: { intervalMs: 2000, // Check every 2 seconds maxAttempts: 25, // Max 50 seconds total maxWaitMs: 50000, // 50 second timeout }, } as const; /** * Poll an asynchronous operation until it completes * Uses fixed intervals instead of exponential backoff for predictability */ export async function pollOperation<T>( checkFn: () => Promise<{ status: string; data?: T }>, options: PollingOptions = {} ): Promise<PollingResult<T>> { const { maxAttempts = POLLING_DEFAULTS.DEFAULT.maxAttempts, intervalMs = POLLING_DEFAULTS.DEFAULT.intervalMs, maxWaitMs = POLLING_DEFAULTS.DEFAULT.maxWaitMs, onProgress, } = options; const startTime = Date.now(); let attempts = 0; while (attempts < maxAttempts) { attempts++; try { const result = await checkFn(); // Notify progress if callback provided if (onProgress) { onProgress(attempts, result); } // Check if operation is complete if (COMPLETE_STATUSES.includes(result.status as any)) { return { success: result.status === 'completed' || result.status === 'idle', data: result.data, error: result.status === 'failed' || result.status === 'cancelled' ? `Operation ${result.status}` : undefined, attempts, duration: Date.now() - startTime, }; } // Check if we've exceeded max wait time if (Date.now() - startTime > maxWaitMs) { return { success: false, error: `Operation timed out after ${maxWaitMs}ms`, attempts, duration: Date.now() - startTime, }; } // Wait before next attempt (fixed interval, not exponential) await sleep(intervalMs); } catch (error) { return { success: false, error: error instanceof Error ? error.message : 'Unknown error', attempts, duration: Date.now() - startTime, }; } } return { success: false, error: `Max attempts (${maxAttempts}) reached`, attempts, duration: Date.now() - startTime, }; } /** * Poll with simple retry logic (not exponential) * Retries with same interval if request fails */ export async function pollWithRetry<T>( checkFn: () => Promise<{ status: string; data?: T }>, options: PollingOptions = {}, maxRetries: number = 3 ): Promise<PollingResult<T>> { let lastError: string | undefined; for (let retry = 0; retry < maxRetries; retry++) { const result = await pollOperation(checkFn, options); if (result.success || !result.error?.includes('Unknown error')) { // Success or a definitive failure (not a network error) return result; } lastError = result.error; // Wait a bit before retrying (fixed delay, not exponential) if (retry < maxRetries - 1) { await sleep(1000); // 1 second between retries } } return { success: false, error: lastError || 'All retries exhausted', attempts: maxRetries, duration: 0, }; } /** * Simple sleep function */ function sleep(ms: number): Promise<void> { return new Promise(resolve => setTimeout(resolve, ms)); } /** * Create a progress callback that logs status updates */ export function createProgressLogger(operationType: string) { return (attempt: number, status: { status: string; progress?: any }) => { const progress = status.progress ? ` (${JSON.stringify(status.progress)})` : ''; console.log(`[${operationType}] Attempt ${attempt}: ${status.status}${progress}`); }; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/waldzellai/exa-mcp-server-websets'

If you have feedback or need assistance with the MCP directory API, please join our Discord server