@aws-lambda-powertools/batch
Version:
The batch processing package for the Powertools for AWS Lambda (TypeScript) library.
178 lines (177 loc) • 6.14 kB
JavaScript
import { BatchProcessingStore } from './BatchProcessingStore.js';
/**
* Abstract class for batch processors.
*
* This class provides a common interface for processing records in a batch.
*
* Batch processors implementing this class should provide implementations for
* a number of abstract methods that are specific to the type of processor or the
* type of records being processed.
*
* The class comes with a few helper methods and hooks that can be used to prepare
* the processor before processing records, clean up after processing records, and
* handle records that succeed or fail processing.
*/
class BasePartialProcessor {
/**
* Store for managing invocation-specific state
*/
#store = new BatchProcessingStore();
get errors() {
return this.#store.getErrors();
}
set errors(errors) {
this.#store.setErrors(errors);
}
get failureMessages() {
return this.#store.getFailureMessages();
}
set failureMessages(messages) {
this.#store.setFailureMessages(messages);
}
get handler() {
return this.#store.getHandler();
}
set handler(handler) {
this.#store.setHandler(handler);
}
get options() {
return this.#store.getOptions();
}
set options(options) {
this.#store.setOptions(options);
}
get records() {
return this.#store.getRecords();
}
set records(records) {
this.#store.setRecords(records);
}
get successMessages() {
return this.#store.getSuccessMessages();
}
set successMessages(messages) {
this.#store.setSuccessMessages(messages);
}
get batchResponse() {
return this.#store.getBatchResponse();
}
set batchResponse(response) {
this.#store.setBatchResponse(response);
}
/**
* Method to handle a record that failed processing
*
* This method should be called when a record fails processing so that
* the processor can keep track of the error and the record that failed.
*
* @param record - Record that failed processing
* @param error - Error that was thrown
*/
failureHandler(record, error) {
const entry = ['fail', error.message, record];
this.errors.push(error);
this.failureMessages.push(record);
return entry;
}
/**
* Process all records with an asynchronous handler
*
* Once called, the processor will create an array of promises to process each record
* and wait for all of them to settle before returning the results.
*
* Before and after processing, the processor will call the prepare and clean methods respectively.
*/
async process() {
this.prepare();
// Default to `true` if `processInParallel` is not specified.
const processInParallel = this.options?.processInParallel ?? true;
const processedRecords = processInParallel
? await this.#processRecordsInParallel()
: await this.#processRecordsSequentially();
this.clean();
return processedRecords;
}
/**
* Orchestrate the processing of a batch of records synchronously
* and sequentially.
*
* The method is responsible for calling the prepare method before
* processing the records and the clean method after processing the records.
*
* In the middle, the method will iterate over the records and call the
* processRecordSync method for each record.
*
* @returns List of processed records
*/
processSync() {
/**
* If this is an async processor, user should have called process instead,
* so we call the method early to throw the error early thus failing fast.
*/
if (this.constructor.name === 'BatchProcessor') {
this.processRecordSync(this.records[0]);
}
this.prepare();
const processedRecords = [];
for (const record of this.records) {
processedRecords.push(this.processRecordSync(record));
}
this.clean();
return processedRecords;
}
/**
* Set up the processor with the records and the handler
*
* This method should be called before processing the records to
* bind the records and the handler for a specific invocation to
* the processor.
*
* We use a separate method to do this rather than the constructor
* to allow for reusing the processor instance across multiple invocations
* by instantiating the processor outside the Lambda function handler.
*
* @param records - Array of records to be processed
* @param handler - CallableFunction to process each record from the batch
* @param options - Options to be used during processing (optional)
*/
register(records, handler, options) {
this.records = records;
this.handler = handler;
if (options) {
this.options = options;
}
return this;
}
/**
* Method to handle a record that succeeded processing
*
* This method should be called when a record succeeds processing so that
* the processor can keep track of the result and the record that succeeded.
*
* @param record - Record that succeeded processing
* @param result - Result from record handler
*/
successHandler(record, result) {
const entry = ['success', result, record];
this.successMessages.push(record);
return entry;
}
/**
* Processes records in parallel using `Promise.all`.
*/
#processRecordsInParallel() {
return Promise.all(this.records.map((record) => this.processRecord(record)));
}
/**
* Processes records sequentially, ensuring that each record is processed one after the other.
*/
async #processRecordsSequentially() {
const processedRecords = [];
for (const record of this.records) {
processedRecords.push(await this.processRecord(record));
}
return processedRecords;
}
}
export { BasePartialProcessor };