UNPKG

@azure/cosmos

Version:
187 lines (186 loc) 7.56 kB
var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var Batcher_exports = {}; __export(Batcher_exports, { Batcher: () => Batcher }); module.exports = __toCommonJS(Batcher_exports); var import_constants = require("../common/constants.js"); var import_statusCodes = require("../common/statusCodes.js"); var import_DiagnosticNodeInternal = require("../diagnostics/DiagnosticNodeInternal.js"); var import__ = require("../index.js"); var import_batch = require("../utils/batch.js"); var import_time = require("../utils/time.js"); class Batcher { batchOperationsList; currentSize; toBeDispatched; executor; retrier; diagnosticLevel; encryptionEnabled; encryptionProcessor; clientConfigDiagnostics; limiter; processedOperationCountRef; constructor(limiter, executor, retrier, diagnosticLevel, encryptionEnabled, clientConfig, encryptionProcessor, processedOperationCountRef) { this.limiter = limiter; this.batchOperationsList = []; this.executor = executor; this.retrier = retrier; this.diagnosticLevel = diagnosticLevel; this.encryptionEnabled = encryptionEnabled; this.encryptionProcessor = encryptionProcessor; this.clientConfigDiagnostics = clientConfig; this.currentSize = 0; this.toBeDispatched = false; this.processedOperationCountRef = processedOperationCountRef; } /** * Attempts to add an operation to the current batch. * Returns false if the batch is full or already dispatched. */ tryAdd(operation) { if (this.toBeDispatched) { return false; } if (!operation) { throw new import__.ErrorResponse("Operation is not defined"); } if (!operation.operationContext) { throw new import__.ErrorResponse("Operation context is not defined"); } if (this.batchOperationsList.length === import_constants.Constants.MaxBulkOperationsCount) { return false; } const currentOperationSize = (0, import_batch.calculateObjectSizeInBytes)(operation.operationInput); if (this.batchOperationsList.length > 0 && this.currentSize + currentOperationSize > import_constants.Constants.DefaultMaxBulkRequestBodySizeInBytes) { return false; } this.currentSize += currentOperationSize; this.batchOperationsList.push(operation); return true; } isEmpty() { return this.batchOperationsList.length === 0; } /** * Dispatches the current batch of operations. * Handles retries for failed operations and updates the ordered response. */ async dispatch(partitionMetric) { this.toBeDispatched = true; const startTime = (0, import_time.getCurrentTimestampInMs)(); const diagnosticNode = new import_DiagnosticNodeInternal.DiagnosticNodeInternal( this.diagnosticLevel, import_DiagnosticNodeInternal.DiagnosticNodeType.BATCH_REQUEST, null ); try { const response = await this.executor(this.batchOperationsList, diagnosticNode); const hasThrottles = 1; const noThrottle = 0; const numThrottle = response?.results?.some( (result) => "code" in result && result.code === import_statusCodes.StatusCodes.TooManyRequests ) ? hasThrottles : noThrottle; const splitOrMerge = response?.results?.some( (result) => "code" in result && result.code === import_statusCodes.StatusCodes.Gone ) ? true : false; if (splitOrMerge) { await this.limiter.pauseAndClear(import_statusCodes.StatusCodes.Gone, diagnosticNode); } partitionMetric.add( this.batchOperationsList.length, (0, import_time.getCurrentTimestampInMs)() - startTime, numThrottle ); for (let i = 0; i < response.operations.length; i++) { const operation = response.operations[i]; const bulkOperationResult = response.results[i]; if (bulkOperationResult instanceof import__.ErrorResponse) { const shouldRetry = await operation.operationContext.retryPolicy.shouldRetry( bulkOperationResult, operation.operationContext.diagnosticNode ); if (shouldRetry) { await this.retrier(operation, operation.operationContext.diagnosticNode); continue; } } try { if (this.encryptionEnabled && bulkOperationResult.resourceBody) { operation.operationContext.diagnosticNode.beginEncryptionDiagnostics( import_constants.Constants.Encryption.DiagnosticsDecryptOperation ); const { body: decryptedBody, propertiesDecryptedCount } = await this.encryptionProcessor.decrypt(bulkOperationResult.resourceBody); bulkOperationResult.resourceBody = decryptedBody; operation.operationContext.diagnosticNode.endEncryptionDiagnostics( import_constants.Constants.Encryption.DiagnosticsDecryptOperation, propertiesDecryptedCount ); } } catch (error) { if (operation.operationInput.operationType !== "Read") { const decryptionError = new import__.ErrorResponse( `Item ${operation.operationInput.operationType} operation was successful but response decryption failed: + ${error.message}` ); decryptionError.code = import_statusCodes.StatusCodes.ServiceUnavailable; throw decryptionError; } } operation.operationContext.addDiagnosticChild(diagnosticNode); bulkOperationResult.diagnostics = operation.operationContext.diagnosticNode.toDiagnostic( this.clientConfigDiagnostics ); const bulkItemResponse = { operationInput: operation.unencryptedOperationInput }; if (bulkOperationResult instanceof import__.ErrorResponse) { bulkItemResponse.error = bulkOperationResult; } else { bulkItemResponse.response = bulkOperationResult; } operation.operationContext.complete(bulkItemResponse); this.processedOperationCountRef.count++; } } catch (error) { for (const operation of this.batchOperationsList) { const response = { operationInput: operation.operationInput, error: Object.assign(new import__.ErrorResponse(error.message), { code: import_statusCodes.StatusCodes.InternalServerError, diagnostics: operation.operationContext.diagnosticNode.toDiagnostic( this.clientConfigDiagnostics ) }) }; operation.operationContext.fail(response); this.processedOperationCountRef.count++; } } finally { this.batchOperationsList = []; } } getOperations() { return this.batchOperationsList; } } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { Batcher });