Skip to main content
Glama
awsCloudControlDelete.ts7.02 kB
async function main(component: Input): Promise<Output> { const resourceId = component.properties?.si?.resourceId; if (!component.properties.resource?.payload) { return { status: "error", message: "Unable to queue a delete action on a component without a resource", }; } const delay = (time: number) => { return new Promise((res) => { setTimeout(res, time); }); }; let deleteAttempt = 0; const baseDelay = 1000; const maxDelay = 90000; let progressEvent; console.log(`Starting delete operation for resourceId: ${resourceId}, region: ${_.get(component, "properties.domain.extra.Region", "")}`); // Retry initial delete operation if rate limited while (deleteAttempt < 20) { const child = await siExec.waitUntilEnd("aws", [ "cloudcontrol", "delete-resource", "--region", _.get(component, "properties.domain.extra.Region", ""), "--type-name", _.get(component, "properties.domain.extra.AwsResourceType", ""), "--identifier", resourceId, ]); console.log(`Delete attempt ${deleteAttempt + 1}: AWS CLI exit code: ${child.exitCode}`); if (child.exitCode !== 0) { const isRateLimited = child.stderr.includes("Throttling") || child.stderr.includes("TooManyRequests") || child.stderr.includes("RequestLimitExceeded") || child.stderr.includes("ThrottlingException"); if (isRateLimited && deleteAttempt < 19) { console.log(`Delete attempt ${deleteAttempt + 1} rate limited, will retry`); } else { console.error(`Delete attempt ${deleteAttempt + 1} failed:`, child.stderr); } if (isRateLimited && deleteAttempt < 19) { deleteAttempt++; const exponentialDelay = Math.min(baseDelay * Math.pow(2, deleteAttempt - 1), maxDelay); const jitter = Math.random() * 0.3 * exponentialDelay; const finalDelay = exponentialDelay + jitter; console.log(`[DELETE] Rate limited on attempt ${deleteAttempt}, waiting ${Math.round(finalDelay)}ms before retry`); await delay(finalDelay); continue; } else { return { status: "error", message: `Unable to delete resource; AWS CLI 2 exited with non zero code: ${child.exitCode}`, }; } } else { console.log(`[DELETE] Initial delete successful on attempt ${deleteAttempt + 1}`); progressEvent = JSON.parse(child.stdout); console.log(`[DELETE] Got progress event:`, JSON.stringify(progressEvent, null, 2)); break; } } console.log(`[DELETE] Starting status polling for request token: ${_.get(progressEvent, ["ProgressEvent", "RequestToken"])}`); let finished = false; let success = false; let attempt = 0; let message = ""; let identifier = ""; while (!finished) { console.log(`[DELETE] Status poll attempt ${attempt + 1}`); const child = await siExec.waitUntilEnd("aws", [ "cloudcontrol", "get-resource-request-status", "--region", _.get(component, "properties.domain.extra.Region", ""), "--request-token", _.get(progressEvent, ["ProgressEvent", "RequestToken"]), "--no-cli-pager", ]); let shouldRetry = false; console.log(`[DELETE] Status poll ${attempt + 1}: exit code ${child.exitCode}, stderr: ${child.stderr ? 'present' : 'none'}`); // Check for rate limiting in stderr regardless of exit code const hasStderrError = child.stderr && child.stderr.trim().length > 0; const isRateLimited = hasStderrError && ( child.stderr.includes("Throttling") || child.stderr.includes("TooManyRequests") || child.stderr.includes("RequestLimitExceeded") || child.stderr.includes("ThrottlingException") ); if (child.exitCode !== 0) { if (isRateLimited && attempt < 20) { console.log(`[DELETE] Status poll ${attempt + 1} rate limited, will retry`); shouldRetry = true; } else { console.error(`[DELETE] Status poll ${attempt + 1} failed:`, child.stderr); } if (!isRateLimited || attempt >= 20) { return { status: "error", message: `Unable to delete; AWS CLI 2 exited with non zero code: ${child.exitCode}`, }; } } else { try { const currentProgressEvent = JSON.parse(child.stdout); console.log(`[DELETE] Status poll ${attempt + 1} response:`, JSON.stringify(currentProgressEvent, null, 2)); // Log stderr warnings but don't fail if we have valid JSON if (hasStderrError) { console.warn("AWS CLI stderr (non-fatal):", child.stderr); } const operationStatus = currentProgressEvent["ProgressEvent"]["OperationStatus"]; if (operationStatus == "SUCCESS") { console.log(`[DELETE] Operation SUCCESS detected!`); finished = true; success = true; identifier = currentProgressEvent["ProgressEvent"]["Identifier"]; } else if (operationStatus == "FAILED") { console.log(`[DELETE] Operation FAILED: ${currentProgressEvent["ProgressEvent"]["StatusMessage"] || currentProgressEvent["ProgressEvent"]["ErrorCode"]}`); finished = true; success = false; message = currentProgressEvent["ProgressEvent"]["StatusMessage"] || currentProgressEvent["ProgressEvent"]["ErrorCode"]; } else if (operationStatus == "CANCEL_COMPLETE") { console.log(`[DELETE] Operation CANCELLED`); finished = true; success = false; message = "Operation Canceled by API or AWS."; } } catch (parseError) { console.error("Failed to parse AWS response:", parseError); console.error("Raw stdout:", child.stdout); console.error("Raw stderr:", child.stderr); if (isRateLimited && attempt < 20) { console.log(`[DELETE] Parse error with rate limiting on attempt ${attempt + 1}, will retry after backoff`); shouldRetry = true; } else { return { status: "error", message: "Unable to parse AWS CloudControl response", }; } } } if (!finished || shouldRetry) { attempt++; const exponentialDelay = Math.min(baseDelay * Math.pow(2, attempt - 1), maxDelay); const jitter = Math.random() * 0.3 * exponentialDelay; const finalDelay = exponentialDelay + jitter; console.log(`[DELETE] Waiting ${Math.round(finalDelay)}ms before status poll attempt ${attempt + 1}`); await delay(finalDelay); } } console.log(`[DELETE] Final result: success=${success}`); if (success) { console.log(`[DELETE] Returning success`); return { payload: null, status: "ok", }; } else { console.log(`[DELETE] Returning error: ${message}`); return { message, payload: null, status: "error", }; } }

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/systeminit/si'

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