resolve-local-event-broker
Version:
The reSolve framework's event broker for applications on a local machine.
193 lines (169 loc) • 7.64 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _constants = require("../constants");
const retryRollback = new Error('Retrying rollback marker');
const acknowledgeBatch = async (pool, payload) => {
const {
database: {
runRawQuery,
runQuery,
escapeStr,
escapeId
},
parseSubscription,
getNextCursor,
invokeConsumer,
invokeOperation,
serializeError
} = pool;
const {
batchId,
result
} = payload;
const notificationsTableNameAsId = escapeId(_constants.NOTIFICATIONS_TABLE_NAME);
const subscribersTableNameAsId = escapeId(_constants.SUBSCRIBERS_TABLE_NAME);
const batchesTableNameAsId = escapeId(_constants.BATCHES_TABLE_NAME);
const [applyingEvents, affectedNotifications] = await Promise.all([runQuery(`
SELECT * FROM ${batchesTableNameAsId}
WHERE ${batchesTableNameAsId}."batchId" = ${escapeStr(batchId)}
ORDER BY ${batchesTableNameAsId}."eventIndex" ASC
`), runQuery(`
SELECT ${subscribersTableNameAsId}."subscriptionId" AS "subscriptionId",
${subscribersTableNameAsId}."eventSubscriber" AS "eventSubscriber",
${subscribersTableNameAsId}."deliveryStrategy" AS "deliveryStrategy",
${subscribersTableNameAsId}."successEvent" AS "successEvent",
${subscribersTableNameAsId}."cursor" AS "cursor",
${notificationsTableNameAsId}."status" AS "runStatus",
${notificationsTableNameAsId}."xaTransactionId" AS "xaTransactionId",
${notificationsTableNameAsId}."batchId" AS "batchId"
FROM ${notificationsTableNameAsId} LEFT JOIN ${subscribersTableNameAsId}
ON ${subscribersTableNameAsId}."subscriptionId" =
${notificationsTableNameAsId}."subscriptionId"
WHERE ${notificationsTableNameAsId}."batchId" = ${escapeStr(batchId)}
LIMIT 1
`)]);
if (affectedNotifications == null || affectedNotifications.length === 0) {
return;
}
const subscriptionDescription = parseSubscription(affectedNotifications[0]);
if (subscriptionDescription.runStatus !== _constants.NotificationStatus.PROCESSING && subscriptionDescription.runStatus !== _constants.NotificationStatus.ACKNOWLEDGE_ENTERING && subscriptionDescription.runStatus !== _constants.NotificationStatus.ACKNOWLEDGE_XA_COMMITING && subscriptionDescription.runStatus !== _constants.NotificationStatus.ACKNOWLEDGE_XA_ROLLBACKING) {
return;
}
if (subscriptionDescription.runStatus === _constants.NotificationStatus.PROCESSING) {
await runRawQuery(`
UPDATE ${notificationsTableNameAsId} SET
"status" = ${escapeStr(_constants.NotificationStatus.ACKNOWLEDGE_ENTERING)}
WHERE ${notificationsTableNameAsId}."batchId" = ${escapeStr(batchId)}
AND ${notificationsTableNameAsId}."status" = ${escapeStr(_constants.NotificationStatus.PROCESSING)};
COMMIT;
BEGIN IMMEDIATE;
`);
const result = await runQuery(`
SELECT ${notificationsTableNameAsId}."status" AS "runStatus"
FROM ${notificationsTableNameAsId}
WHERE ${notificationsTableNameAsId}."batchId" = ${escapeStr(batchId)}
AND ${notificationsTableNameAsId}."status" = ${escapeStr(_constants.NotificationStatus.ACKNOWLEDGE_ENTERING)}
LIMIT 1
`);
if (result == null || result.length === 0) {
return;
}
subscriptionDescription.runStatus = _constants.NotificationStatus.ACKNOWLEDGE_ENTERING;
}
const activeBatch = {
eventSubscriber: subscriptionDescription.eventSubscriber,
subscriptionId: subscriptionDescription.subscriptionId,
batchId
};
try {
let isXaCommitOk = true;
const {
successEvent,
failedEvent,
error
} = result;
const lastSuccessEventIdx = successEvent != null ? applyingEvents.findIndex(({
aggregateIdAndVersion
}) => aggregateIdAndVersion === `${successEvent.aggregateId}:${successEvent.aggregateVersion}`) + 1 : 0;
const nextCursor = await getNextCursor(subscriptionDescription.cursor, applyingEvents.slice(0, lastSuccessEventIdx));
if (subscriptionDescription.deliveryStrategy === _constants.DeliveryStrategy.ACTIVE_XA && subscriptionDescription.xaTransactionId != null) {
if (subscriptionDescription.runStatus === _constants.NotificationStatus.ACKNOWLEDGE_ENTERING || subscriptionDescription.runStatus === _constants.NotificationStatus.ACKNOWLEDGE_XA_COMMITING) {
if (subscriptionDescription.runStatus === _constants.NotificationStatus.ACKNOWLEDGE_ENTERING) {
await runRawQuery(`
UPDATE ${notificationsTableNameAsId} SET
"status" = ${escapeStr(_constants.NotificationStatus.ACKNOWLEDGE_XA_COMMITING)}
WHERE "batchId" = ${escapeStr(batchId)};
COMMIT;
BEGIN IMMEDIATE;
`);
}
isXaCommitOk = await invokeConsumer(pool, _constants.ConsumerMethod.CommitXATransaction, {
eventSubscriber: subscriptionDescription.eventSubscriber,
xaTransactionId: subscriptionDescription.xaTransactionId,
batchId
});
} else if (subscriptionDescription.runStatus === _constants.NotificationStatus.ACKNOWLEDGE_XA_ROLLBACKING) {
throw retryRollback;
} else {
throw new Error(`Inconsistent XA-state ${subscriptionDescription.runStatus}`);
}
}
const input = {
type: _constants.PrivateOperationType.FINALIZE_BATCH,
payload: {
activeBatch,
result: {
cursor: nextCursor,
successEvent: isXaCommitOk ? successEvent : subscriptionDescription.successEvent,
failedEvent,
error: serializeError(error)
}
}
};
await invokeOperation(pool, _constants.LazinessStrategy.EAGER, input);
} catch (error) {
let compositeError = error;
if (subscriptionDescription.deliveryStrategy === _constants.DeliveryStrategy.ACTIVE_XA && subscriptionDescription.xaTransactionId != null) {
compositeError = new Error(error.message);
compositeError.stack = error.stack;
if (subscriptionDescription.runStatus === _constants.NotificationStatus.ACKNOWLEDGE_ENTERING || subscriptionDescription.runStatus === _constants.NotificationStatus.ACKNOWLEDGE_XA_COMMITING) {
await runRawQuery(`
UPDATE ${notificationsTableNameAsId} SET
"status" = ${escapeStr(_constants.NotificationStatus.ACKNOWLEDGE_XA_ROLLBACKING)}
WHERE "batchId" = ${escapeStr(batchId)};
COMMIT;
BEGIN IMMEDIATE;
`);
}
try {
const isXaRollbackOk = await invokeConsumer(pool, _constants.ConsumerMethod.RollbackXATransaction, {
eventSubscriber: subscriptionDescription.eventSubscriber,
xaTransactionId: subscriptionDescription.xaTransactionId,
batchId
});
if (!isXaRollbackOk) {
throw new Error(`Xa-transaction ${subscriptionDescription.xaTransactionId} early marked to rollback, but was auto-committed`);
}
} catch (rollbackError) {
compositeError.message = `${compositeError.message}\n${rollbackError.message}`;
compositeError.stack = `${compositeError.stack}\n${rollbackError.stack}`;
}
}
const input = {
type: _constants.PrivateOperationType.FINALIZE_BATCH,
payload: {
activeBatch,
result: {
error: serializeError(compositeError)
}
}
};
await invokeOperation(pool, _constants.LazinessStrategy.EAGER, input);
}
};
var _default = acknowledgeBatch;
exports.default = _default;
//# sourceMappingURL=acknowledge-batch.js.map