UNPKG

@medusajs/index

Version:
238 lines • 13.5 kB
"use strict"; var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); }; var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { if (kind === "m") throw new TypeError("Private method is not writable"); if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; }; var _DataSynchronizer_instances, _DataSynchronizer_container, _DataSynchronizer_isReady, _DataSynchronizer_schemaObjectRepresentation, _DataSynchronizer_storageProvider, _DataSynchronizer_orchestrator, _DataSynchronizer_query_get, _DataSynchronizer_locking_get, _DataSynchronizer_indexMetadataService_get, _DataSynchronizer_indexSyncService_get, _DataSynchronizer_indexRelationService_get, _DataSynchronizer_logger_get, _DataSynchronizer_isReadyOrThrow, _DataSynchronizer_updatedStatus, _DataSynchronizer_taskRunner; Object.defineProperty(exports, "__esModule", { value: true }); exports.DataSynchronizer = void 0; const utils_1 = require("@medusajs/framework/utils"); const _utils_1 = require("../utils"); const promises_1 = require("timers/promises"); class DataSynchronizer { constructor(container) { _DataSynchronizer_instances.add(this); _DataSynchronizer_container.set(this, void 0); _DataSynchronizer_isReady.set(this, false); _DataSynchronizer_schemaObjectRepresentation.set(this, void 0); _DataSynchronizer_storageProvider.set(this, void 0); _DataSynchronizer_orchestrator.set(this, void 0); __classPrivateFieldSet(this, _DataSynchronizer_container, container, "f"); } onApplicationStart({ schemaObjectRepresentation, storageProvider, }) { __classPrivateFieldSet(this, _DataSynchronizer_storageProvider, storageProvider, "f"); __classPrivateFieldSet(this, _DataSynchronizer_schemaObjectRepresentation, schemaObjectRepresentation, "f"); __classPrivateFieldSet(this, _DataSynchronizer_isReady, true, "f"); } async syncEntities(entities, lockDuration = 60 // 1 minute ) { __classPrivateFieldGet(this, _DataSynchronizer_instances, "m", _DataSynchronizer_isReadyOrThrow).call(this); const entitiesToSync = entities.map((entity) => entity.entity); __classPrivateFieldSet(this, _DataSynchronizer_orchestrator, new _utils_1.Orchestrator(__classPrivateFieldGet(this, _DataSynchronizer_instances, "a", _DataSynchronizer_locking_get), entitiesToSync, { lockDuration, logger: __classPrivateFieldGet(this, _DataSynchronizer_instances, "a", _DataSynchronizer_logger_get), }), "f"); await __classPrivateFieldGet(this, _DataSynchronizer_orchestrator, "f").process(__classPrivateFieldGet(this, _DataSynchronizer_instances, "m", _DataSynchronizer_taskRunner).bind(this)); } async removeEntities(entities, staleOnly = false) { __classPrivateFieldGet(this, _DataSynchronizer_instances, "m", _DataSynchronizer_isReadyOrThrow).call(this); const staleCondition = staleOnly ? "staled_at IS NOT NULL" : ""; for (const entity of entities) { await __classPrivateFieldGet(this, _DataSynchronizer_container, "f").manager.execute(`WITH deleted_data AS ( DELETE FROM "index_data" WHERE "name" = ? ${staleCondition ? `AND ${staleCondition}` : ""} RETURNING id ) DELETE FROM "index_relation" WHERE ("parent_name" = ? AND "parent_id" IN (SELECT id FROM deleted_data)) OR ("child_name" = ? AND "child_id" IN (SELECT id FROM deleted_data))`, [entity, entity, entity]); } } async syncEntity({ entityName, pagination = {}, ack, }) { __classPrivateFieldGet(this, _DataSynchronizer_instances, "m", _DataSynchronizer_isReadyOrThrow).call(this); const schemaEntityObjectRepresentation = __classPrivateFieldGet(this, _DataSynchronizer_schemaObjectRepresentation, "f")[entityName]; const { alias, moduleConfig } = schemaEntityObjectRepresentation; const isLink = !!moduleConfig?.isLink; if (!alias) { __classPrivateFieldGet(this, _DataSynchronizer_instances, "a", _DataSynchronizer_logger_get).info(`[Index engine] Cannot find Entity '${entityName}' alias. Skipping.`); const acknoledgement = { lastCursor: pagination.cursor ?? null, done: true, }; await ack(acknoledgement); return acknoledgement; } const entityPrimaryKey = "id"; const moduleHasId = !!moduleConfig?.primaryKeys?.includes("id"); if (!moduleHasId) { const acknoledgement = { lastCursor: pagination.cursor ?? null, err: new Error(`Entity ${entityName} does not have a property 'id'. The 'id' must be provided and must be orderable (e.g ulid)`), }; await ack(acknoledgement); return acknoledgement; } let processed = 0; let currentCursor = pagination.cursor; const batchSize = Math.min(pagination.batchSize ?? 100, 100); const limit = pagination.limit ?? Infinity; let error = null; while (processed < limit) { const filters = {}; if (currentCursor) { filters[entityPrimaryKey] = { $gt: currentCursor }; } if (pagination.updated_at) { filters["updated_at"] = { $gt: pagination.updated_at }; } const queryResult = await __classPrivateFieldGet(this, _DataSynchronizer_instances, "a", _DataSynchronizer_query_get).graph({ entity: alias, fields: [entityPrimaryKey], filters, pagination: { order: { [entityPrimaryKey]: "asc", }, take: batchSize, }, }); if (!queryResult?.data?.length) { break; } const data = queryResult.data; const envelop = { data, name: !isLink ? `*.${utils_1.CommonEvents.CREATED}` : `*.${utils_1.CommonEvents.ATTACHED}`, }; try { await __classPrivateFieldGet(this, _DataSynchronizer_storageProvider, "f").consumeEvent(schemaEntityObjectRepresentation)(envelop); currentCursor = data[data.length - 1][entityPrimaryKey]; processed += data.length; await ack({ lastCursor: currentCursor }); } catch (err) { error = err; break; } await (0, promises_1.setTimeout)(0, undefined, { ref: false }); } let acknoledgement = { lastCursor: currentCursor, done: true, }; if (error) { acknoledgement = { lastCursor: currentCursor, err: error, }; await ack(acknoledgement); return acknoledgement; } await ack(acknoledgement); return acknoledgement; } } exports.DataSynchronizer = DataSynchronizer; _DataSynchronizer_container = new WeakMap(), _DataSynchronizer_isReady = new WeakMap(), _DataSynchronizer_schemaObjectRepresentation = new WeakMap(), _DataSynchronizer_storageProvider = new WeakMap(), _DataSynchronizer_orchestrator = new WeakMap(), _DataSynchronizer_instances = new WeakSet(), _DataSynchronizer_query_get = function _DataSynchronizer_query_get() { return __classPrivateFieldGet(this, _DataSynchronizer_container, "f")[utils_1.ContainerRegistrationKeys.QUERY]; }, _DataSynchronizer_locking_get = function _DataSynchronizer_locking_get() { return __classPrivateFieldGet(this, _DataSynchronizer_container, "f")[utils_1.Modules.LOCKING]; }, _DataSynchronizer_indexMetadataService_get = function _DataSynchronizer_indexMetadataService_get() { return __classPrivateFieldGet(this, _DataSynchronizer_container, "f").indexMetadataService; }, _DataSynchronizer_indexSyncService_get = function _DataSynchronizer_indexSyncService_get() { return __classPrivateFieldGet(this, _DataSynchronizer_container, "f").indexSyncService; }, _DataSynchronizer_indexRelationService_get = function _DataSynchronizer_indexRelationService_get() { return __classPrivateFieldGet(this, _DataSynchronizer_container, "f").indexRelationService; }, _DataSynchronizer_logger_get = function _DataSynchronizer_logger_get() { try { return __classPrivateFieldGet(this, _DataSynchronizer_container, "f").logger; } catch (err) { return console; } }, _DataSynchronizer_isReadyOrThrow = function _DataSynchronizer_isReadyOrThrow() { if (!__classPrivateFieldGet(this, _DataSynchronizer_isReady, "f")) { throw new Error("DataSynchronizer is not ready. Call onApplicationStart first."); } }, _DataSynchronizer_updatedStatus = async function _DataSynchronizer_updatedStatus(entity, status) { await __classPrivateFieldGet(this, _DataSynchronizer_instances, "a", _DataSynchronizer_indexMetadataService_get).update({ data: { status, }, selector: { entity, }, }); }, _DataSynchronizer_taskRunner = async function _DataSynchronizer_taskRunner(entity) { __classPrivateFieldGet(this, _DataSynchronizer_instances, "a", _DataSynchronizer_logger_get).info(`[Index engine] syncing entity '${entity}'`); const [[lastCursor]] = await (0, utils_1.promiseAll)([ __classPrivateFieldGet(this, _DataSynchronizer_instances, "a", _DataSynchronizer_indexSyncService_get).list({ entity, }, { select: ["last_key"], }), __classPrivateFieldGet(this, _DataSynchronizer_instances, "m", _DataSynchronizer_updatedStatus).call(this, entity, _utils_1.IndexMetadataStatus.PROCESSING), __classPrivateFieldGet(this, _DataSynchronizer_container, "f").manager.execute(`UPDATE "index_data" SET "staled_at" = NOW() WHERE "name" = ?`, [entity]), ]); let startTime = performance.now(); let chunkStartTime = startTime; const finalAcknoledgement = await this.syncEntity({ entityName: entity, pagination: { cursor: lastCursor?.last_key, }, ack: async (ack) => { const endTime = performance.now(); const chunkElapsedTime = (endTime - chunkStartTime).toFixed(2); if (ack.lastCursor) { __classPrivateFieldGet(this, _DataSynchronizer_instances, "a", _DataSynchronizer_logger_get).debug(`[Index engine] syncing entity '${entity}' updating last cursor to ${ack.lastCursor} (+${chunkElapsedTime}ms)`); await __classPrivateFieldGet(this, _DataSynchronizer_instances, "a", _DataSynchronizer_indexSyncService_get).update({ data: { last_key: ack.lastCursor, }, selector: { entity, }, }); if (!ack.done && !ack.err) { await __classPrivateFieldGet(this, _DataSynchronizer_orchestrator, "f").renewLock(entity); } } if (ack.err) { __classPrivateFieldGet(this, _DataSynchronizer_instances, "a", _DataSynchronizer_logger_get).error(`[Index engine] syncing entity '${entity}' failed with error (+${chunkElapsedTime}ms):\n${ack.err.message}`); } if (ack.done) { const elapsedTime = (endTime - startTime).toFixed(2); __classPrivateFieldGet(this, _DataSynchronizer_instances, "a", _DataSynchronizer_logger_get).info(`[Index engine] syncing entity '${entity}' done (+${elapsedTime}ms)`); } chunkStartTime = performance.now(); }, }); if (finalAcknoledgement.done) { await (0, utils_1.promiseAll)([ __classPrivateFieldGet(this, _DataSynchronizer_instances, "m", _DataSynchronizer_updatedStatus).call(this, entity, _utils_1.IndexMetadataStatus.DONE), __classPrivateFieldGet(this, _DataSynchronizer_instances, "a", _DataSynchronizer_indexSyncService_get).update({ data: { last_key: finalAcknoledgement.lastCursor, }, selector: { entity, }, }), this.removeEntities([entity], true), ]); } if (finalAcknoledgement.err) { await __classPrivateFieldGet(this, _DataSynchronizer_instances, "m", _DataSynchronizer_updatedStatus).call(this, entity, _utils_1.IndexMetadataStatus.ERROR); } }; //# sourceMappingURL=data-synchronizer.js.map