UNPKG

@nerdware/ddb-single-table

Version:

A schema-based DynamoDB modeling tool, high-level API, and type-generator built to supercharge single-table designs!⚡

88 lines (87 loc) 5.11 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ensureTableIsActive = void 0; const client_dynamodb_1 = require("@aws-sdk/client-dynamodb"); const ts_type_safety_utils_1 = require("@nerdware/ts-type-safety-utils"); const errors_js_1 = require("../utils/errors.js"); /** * This method of the `Table` class is used to check if a DynamoDB table is active and * ready for use. * * The function checks the DDB table's status using the Table instance's `describeTable` * method. If the method returns a `ResourceNotFoundException`, the table does not exist. * If the table does not exist and `createIfNotExists` is set to `true`, the function * creates the table using the Table instance's `createTable` method — this function then * continues the process of waiting for the table to become active. * * Regardless of whether the table initially existed or not, if it is not active, the * function tries to connect to it again after `frequency` number of seconds have passed * until either the table is active, or `maxRetries` number of attempts have been made, * or `timeout` number of seconds have passed. */ const ensureTableIsActive = async function ({ timeout: timeoutSeconds = 30, frequency: frequencySeconds = 1, maxRetries = 20, createIfNotExists = false, } = {}) { // Get timeout and frequency in milliseconds for use in setTimeout calls const timeoutMilliseconds = timeoutSeconds * 1000; const frequencyMilliseconds = frequencySeconds * 1000; // Start timeout timer that throws error if not cleared within the timeframe. const timeoutTimerID = setTimeout(() => { throw new errors_js_1.DdbSingleTableError(`ensureTableIsActive has timed out after ${timeoutSeconds} seconds.`); }, timeoutMilliseconds); // Local state var to ensure CreateTable isn't called more than once. let hasCreateTableBeenCalled = false; // Try to get TableStatus, ensure it's ACTIVE. for (let i = 0; i < maxRetries; i++) { try { // DescribeTable will throw if Table doesn't exist const response = await this.describeTable(); const tableStatus = response.Table?.TableStatus; if (tableStatus === client_dynamodb_1.TableStatus.ACTIVE) { clearTimeout(timeoutTimerID); this.isTableActive = true; break; } this.logger(`Table "${this.tableName}" is not ACTIVE. Current table status: ${tableStatus ?? "UNKNOWN"}`); // Wait `frequencyMilliseconds`, then try again await new Promise((resolve) => { setTimeout(resolve, frequencyMilliseconds); }); } catch (err) { // Sanity type-check: ensure `err` is an object. if (!(0, ts_type_safety_utils_1.isError)(err) && !(0, ts_type_safety_utils_1.isPlainObject)(err)) throw err; // If err.code is "ECONNREFUSED", a connection could not be made to the provided endpoint. if (err.code === errors_js_1.DdbConnectionError.NODE_ERROR_CODES.ECONNREFUSED) throw new errors_js_1.DdbConnectionError(err); // If `err` is a "ResourceNotFoundException", Table doesn't exist — see if it should be created. if (err.name !== client_dynamodb_1.ResourceNotFoundException.name) throw err; // If Table doesn't exist AND !createIfNotExists, throw error. if (!createIfNotExists) { throw new errors_js_1.DdbSingleTableError(`Table "${this.tableName}" not found. To have the table created automatically when ` + `DynamoDB returns a "ResourceNotFoundException", set "createIfNotExists" to true.`); } // Inform user the Table doesn't exist. this.logger(`Table "${this.tableName}" not found.`); // If createTable has already been called, continue the for-loop. if (hasCreateTableBeenCalled === true) continue; // Else attempt to create the Table. this.logger(`Creating Table "${this.tableName}" ...`); // Create the table (provide `createIfNotExists` if it's a `tableConfigs` object) const response = await this.createTable((0, ts_type_safety_utils_1.isPlainObject)(createIfNotExists) ? createIfNotExists : undefined); // Get the TableStatus from the response const tableStatus = response.TableDescription?.TableStatus; // Update this bool flag so ensure CreateTable is only ever called once. hasCreateTableBeenCalled = true; this.logger(`CreateTable operation complete. Current table status: ${tableStatus ?? "UNKNOWN"}`); // TableStatus is possibly already ACTIVE if using ddb-local. if (tableStatus === client_dynamodb_1.TableStatus.ACTIVE) { clearTimeout(timeoutTimerID); this.isTableActive = true; break; } } } }; exports.ensureTableIsActive = ensureTableIsActive;