resolve-local-event-broker
Version:
The reSolve framework's event broker for applications on a local machine.
216 lines (189 loc) • 7.85 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _constants = require("../constants");
const retryRollback = new Error('Retrying rollback marker');
async function requestTimeout(pool, payload) {
const {
database: {
runQuery,
runRawQuery,
escapeStr,
escapeId
},
parseSubscription,
invokeConsumer,
invokeOperation,
getNextCursor,
serializeError
} = pool;
const {
batchId
} = payload;
const notificationsTableNameAsId = escapeId(_constants.NOTIFICATIONS_TABLE_NAME);
const subscribersTableNameAsId = escapeId(_constants.SUBSCRIBERS_TABLE_NAME);
const batchesTableNameAsId = escapeId(_constants.BATCHES_TABLE_NAME);
const affectedNotifications = await runQuery(`
SELECT ${subscribersTableNameAsId}."eventSubscriber" AS "eventSubscriber",
${subscribersTableNameAsId}."deliveryStrategy" AS "deliveryStrategy",
${subscribersTableNameAsId}."subscriptionId" AS "subscriptionId",
${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.TIMEOUT_ENTERING && !subscriptionDescription.runStatus.startsWith(_constants.NotificationStatus.TIMEOUT_XA_COMMITING) && subscriptionDescription.runStatus !== _constants.NotificationStatus.TIMEOUT_XA_ROLLBACKING) {
return;
}
if (subscriptionDescription.runStatus === _constants.NotificationStatus.PROCESSING) {
await runRawQuery(`
UPDATE ${notificationsTableNameAsId} SET
"status" = ${escapeStr(_constants.NotificationStatus.TIMEOUT_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.TIMEOUT_ENTERING)}
LIMIT 1
`);
if (result == null || result.length === 0) {
return;
}
subscriptionDescription.runStatus = _constants.NotificationStatus.TIMEOUT_ENTERING;
}
const {
eventSubscriber,
deliveryStrategy,
runStatus,
xaTransactionId,
cursor,
successEvent: prevSuccessEvent
} = subscriptionDescription;
const activeBatch = {
batchId: subscriptionDescription.batchId,
subscriptionId: subscriptionDescription.subscriptionId,
eventSubscriber: subscriptionDescription.eventSubscriber
};
if (deliveryStrategy === _constants.DeliveryStrategy.ACTIVE_XA && xaTransactionId == null || deliveryStrategy !== _constants.DeliveryStrategy.ACTIVE_XA) {
const input = {
type: _constants.PrivateOperationType.FINALIZE_BATCH,
payload: {
activeBatch,
result: {
error: serializeError(new Error(`Timeout with consuming batch`))
}
}
};
await invokeOperation(pool, _constants.LazinessStrategy.EAGER, input);
return;
}
const result = {
successEvent: null,
error: null,
cursor
};
try {
if (runStatus === _constants.NotificationStatus.TIMEOUT_ENTERING || runStatus.startsWith(_constants.NotificationStatus.TIMEOUT_XA_COMMITING)) {
let appliedEventCount = null;
if (runStatus === _constants.NotificationStatus.TIMEOUT_ENTERING) {
// eslint-disable-next-line no-bitwise
appliedEventCount = ~~(await invokeConsumer(pool, _constants.ConsumerMethod.CommitXATransaction, {
eventSubscriber,
xaTransactionId,
batchId,
countEvents: true
}));
await runRawQuery(`
UPDATE ${notificationsTableNameAsId} SET
"status" = ${escapeStr( // eslint-disable-next-line no-bitwise
`${_constants.NotificationStatus.TIMEOUT_XA_COMMITING}${~~appliedEventCount}`)}
WHERE "batchId" = ${escapeStr(batchId)};
COMMIT;
BEGIN IMMEDIATE;
`);
} else {
// eslint-disable-next-line no-bitwise
appliedEventCount = ~~runStatus.substring(_constants.NotificationStatus.TIMEOUT_XA_COMMITING.length);
}
if (appliedEventCount > 0) {
const applyingEvents = await runQuery(`
SELECT * FROM ${batchesTableNameAsId}
WHERE ${batchesTableNameAsId}."batchId" = ${escapeStr(batchId)}
ORDER BY ${batchesTableNameAsId}."eventIndex" ASC
LIMIT ${+appliedEventCount}
`);
result.successEvent = applyingEvents[appliedEventCount - 1];
const lastSuccessEventIdx = result.successEvent != null ? applyingEvents.findIndex(({
aggregateIdAndVersion
}) => aggregateIdAndVersion === `${result.successEvent.aggregateId}:${result.successEvent.aggregateVersion}`) + 1 : 0;
result.cursor = await getNextCursor(cursor, applyingEvents.slice(0, lastSuccessEventIdx));
}
const isXaCommitOk = await invokeConsumer(pool, _constants.ConsumerMethod.CommitXATransaction, {
eventSubscriber,
xaTransactionId,
batchId
});
if (!isXaCommitOk) {
result.successEvent = prevSuccessEvent;
}
} else if (runStatus === _constants.NotificationStatus.TIMEOUT_XA_ROLLBACKING) {
throw retryRollback;
} else {
throw new Error(`Inconsistent XA-state ${subscriptionDescription.runStatus}`);
}
} catch (error) {
let compositeError = new Error(error.message);
compositeError.stack = error.stack;
if (runStatus === _constants.NotificationStatus.TIMEOUT_ENTERING || runStatus.startsWith(_constants.NotificationStatus.TIMEOUT_XA_COMMITING)) {
await runRawQuery(`
UPDATE ${notificationsTableNameAsId} SET
"status" = ${escapeStr(_constants.NotificationStatus.TIMEOUT_XA_ROLLBACKING)}
WHERE "batchId" = ${escapeStr(batchId)};
COMMIT;
BEGIN IMMEDIATE;
`);
}
try {
const isXaRollbackOk = await invokeConsumer(pool, _constants.ConsumerMethod.RollbackXATransaction, {
eventSubscriber,
xaTransactionId,
batchId
});
if (!isXaRollbackOk) {
throw new Error(`Xa-transaction ${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}`;
}
result.error = serializeError(compositeError);
}
const input = {
type: _constants.PrivateOperationType.FINALIZE_BATCH,
payload: {
activeBatch,
result
}
};
await invokeOperation(pool, _constants.LazinessStrategy.EAGER, input);
}
var _default = requestTimeout;
exports.default = _default;
//# sourceMappingURL=request-timeout.js.map