download_cancel
Cancel active Optimizely DXP downloads immediately. Stop specific downloads by ID or halt all active transfers to manage deployment resources effectively.
Instructions
❌ Cancel active download(s) immediately. INSTANT: <1s. Call with downloadId to cancel specific download, or call without parameters to cancel all active downloads. Database downloads cannot be cancelled (Azure streaming limitation). Returns count of successfully cancelled downloads. Use download_list() to verify cancellation. Optional: downloadId. Returns cancelled count.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| downloadId | No | Download ID to cancel. Omit to cancel all active downloads |
Implementation Reference
- Main handler function for the "download_cancel" MCP tool. Parses args to determine if cancelling specific downloadId or all downloads, delegates to private helper methods, handles errors.static async handleDownloadCancel(args?: DownloadCancelArgs): Promise<any> { const { downloadId } = args || {}; try { // Cancel specific download if (downloadId) { return await this._cancelSingleDownload(downloadId); } // Cancel all downloads return await this._cancelAllDownloads(); } catch (error: any) { OutputLogger.error(`Cancel download error: ${error}`); return ResponseBuilder.internalError('Failed to cancel download(s)', error.message); } }
- TypeScript interface defining the input parameters for the download_cancel tool.interface DownloadCancelArgs { downloadId?: string; }
- Private helper that cancels a single download. Checks if database download first (cannot cancel), then cancels log download using DownloadManager, returns formatted response.static async _cancelSingleDownload(downloadId: string): Promise<any> { // Check if it's a database download // DXP-178 FIX: Need .default for ES module default export const DatabaseSimpleTools = require('./database-simple-tools').default; // DXP-178 FIX: Use .backgroundDownloads.get() instead of non-existent .getDownloadStatus() const dbDownload = DatabaseSimpleTools.backgroundDownloads.get(downloadId); if (dbDownload) { return ResponseBuilder.error( `❌ **Cannot Cancel Database Download**\n\n` + `Database downloads use Azure Blob streaming and cannot be interrupted. ` + `The download will complete in the background.\n\n` + `**Download ID**: ${downloadId}\n` + `**Progress**: ${dbDownload.percent || 0}%\n\n` + `**Monitor progress:** \`download_status({ downloadId: "${downloadId}" })\`` ); } // Check if it's a log download const logDownload = downloadManager.getDownload(downloadId); if (!logDownload) { return ResponseBuilder.error( `Download ${downloadId} not found.\n\n` + `**View active downloads:** \`download_list({ status: "active" })\`` ); } // Cancel the log download const result: CancelResult = downloadManager.cancelDownload(downloadId); if (result.success) { const download = result.download; const elapsed = Math.floor((Date.now() - download.startTime) / 60000); const structuredData = { cancelled: [downloadId], skipped: [], failed: [] }; const message = `❌ **Download Cancelled**\n\n` + `**Download**: ${download.containerName} logs\n` + `**Runtime**: ${elapsed} minutes\n` + `**Progress**: ${download.progress}%\n\n` + `Partially downloaded files have been preserved.`; return ResponseBuilder.successWithStructuredData(structuredData, message); } else { return ResponseBuilder.error(`Failed to cancel: ${result.error}`); } }
- Private helper that cancels all active log downloads using DownloadManager.cancelAllDownloads(), identifies un-cancellable database downloads, formats comprehensive response with structured data.static async _cancelAllDownloads(): Promise<any> { const logResults: CancelResult[] = downloadManager.cancelAllDownloads(); // Find database downloads that can't be cancelled // DXP-178 FIX: Need .default for ES module default export const DatabaseSimpleTools = require('./database-simple-tools').default; const dbDownloads: SkippedDownload[] = []; for (const [id, download] of DatabaseSimpleTools.backgroundDownloads.entries()) { if (download.status === 'in_progress' || download.status === 'pending') { dbDownloads.push({ downloadId: id, type: 'database', reason: 'Database downloads cannot be cancelled' }); } } const cancelled = logResults.filter(r => r.success).map(r => r.download!.key); const failed: FailedCancel[] = logResults.filter(r => !r.success).map(r => ({ downloadId: r.download?.key || 'unknown', reason: r.error || 'Unknown error' })); if (cancelled.length === 0 && dbDownloads.length === 0 && failed.length === 0) { return ResponseBuilder.success('📭 No active downloads to cancel.'); } let message = `❌ **Cancel All Downloads**\n\n`; if (cancelled.length > 0) { message += `**Cancelled log downloads** (${cancelled.length}):\n`; for (const id of cancelled) { message += `• ${id}\n`; } message += `\n`; } if (dbDownloads.length > 0) { message += `**Database downloads continuing** (${dbDownloads.length}):\n`; message += `These downloads cannot be cancelled and will complete in background.\n`; for (const db of dbDownloads) { message += `• ${db.downloadId}\n`; } message += `\n`; } if (failed.length > 0) { message += `**Failed to cancel** (${failed.length}):\n`; for (const f of failed) { message += `• ${f.downloadId}: ${f.reason}\n`; } message += `\n`; } const structuredData = { cancelled: cancelled, skipped: dbDownloads, failed: failed }; return ResponseBuilder.successWithStructuredData(structuredData, message); }
- lib/download-manager.ts:330-363 (helper)Core implementation in DownloadManager that performs the actual cancellation: kills child process with SIGTERM/SIGKILL, updates status, moves to history, emits event.cancelDownload(key: string): CancelResult { const download = this.activeDownloads.get(key); if (!download) { return { success: false, error: `Download ${key} not found` }; } try { if (download.childProcess && !download.childProcess.killed) { download.childProcess.kill('SIGTERM'); // Force kill after 5 seconds if still running setTimeout(() => { if (download.childProcess && !download.childProcess.killed) { download.childProcess.kill('SIGKILL'); } }, 5000); } download.status = 'cancelled'; download.endTime = Date.now(); // Move to history this.downloadHistory.push(download); this.activeDownloads.delete(key); this.emit('downloadCancelled', download); OutputLogger.info(`❌ Cancelled download: ${key}`); return { success: true, download }; } catch (error) { OutputLogger.error(`Failed to cancel download ${key}: ${error}`); return { success: false, error: (error as Error).message }; } }