import { resolveMapRowOutcomeKey } from './map-row-outcome'; export interface RuntimeSheetBlockedRowDetail { rowKey: string | null; attemptId: string | null; attemptOwnerRunId: string | null; attemptExpiresAt: string | null; } function stringField( row: Record, ...fieldNames: string[] ): string | null { for (const fieldName of fieldNames) { const value = row[fieldName]; if (typeof value === 'string' && value.trim()) { return value; } } return null; } function runtimeSheetBlockedRowDetail( row: Record, ): RuntimeSheetBlockedRowDetail { return { rowKey: resolveMapRowOutcomeKey(row), attemptId: stringField( row, 'attemptId', '_attempt_id', '__deeplineAttemptId', ), attemptOwnerRunId: stringField( row, 'attemptOwnerRunId', '_attempt_owner_run_id', '__deeplineAttemptOwnerRunId', ), attemptExpiresAt: stringField( row, 'attemptExpiresAt', '_attempt_expires_at', '__deeplineAttemptExpiresAt', ), }; } export class RuntimeSheetRowsBlockedError extends Error { readonly tableNamespace: string; readonly rowKeys: string[]; readonly owningAttempts: string[]; readonly blockedRowDetails: RuntimeSheetBlockedRowDetail[]; constructor(input: { tableNamespace: string; blockedRows: Record[]; }) { const blockedRowDetails = input.blockedRows.map( runtimeSheetBlockedRowDetail, ); const rowKeys = blockedRowDetails .map((detail) => detail.rowKey) .filter((key): key is string => Boolean(key)) .slice(0, 20); const owningAttempts = blockedRowDetails .map((detail) => detail.attemptId) .filter((attempt): attempt is string => Boolean(attempt)); const uniqueOwningAttempts = Array.from(new Set(owningAttempts)).slice( 0, 20, ); super( `ctx.dataset("${input.tableNamespace}") is blocked by ${input.blockedRows.length} active runtime sheet row lease(s) owned by another attempt. Retry after the owning attempt finishes or the row leases expire.` + (rowKeys.length > 0 ? ` Blocked row keys: ${rowKeys.join(', ')}.` : '') + (uniqueOwningAttempts.length > 0 ? ` Owning attempts: ${uniqueOwningAttempts.join(', ')}.` : ''), ); this.name = 'RuntimeSheetRowsBlockedError'; this.tableNamespace = input.tableNamespace; this.rowKeys = rowKeys; this.owningAttempts = uniqueOwningAttempts; this.blockedRowDetails = blockedRowDetails.slice(0, 20); } }