@tomei/customer-base
Version:
Tomei Customer Base Package
227 lines (209 loc) • 6.08 kB
text/typescript
import { Transaction } from 'sequelize';
import cuid from '../../helpers/cuid';
import { TrigerredByEnum } from '../../enum/triggered-by.enum';
import { EventTypeEnum } from '../../enum/event-type.enum';
import { SyncLoggerRepository } from './sync-logger.repository';
import { SyncStatusEnum } from '../../enum/sync-status.enum';
import { SystemSyncPolicy } from '../system-sync-policy';
import {
IsPolicyAllowInsertEnum,
IsPolicyAllowUpdateEnum,
} from '../../enum/system-sync-policy.enum';
import { syncQueue } from '../sync-queue/sync-queue';
interface LogSyncTargetsParams {
CustomerId: string;
SourceSystemCode: string;
TargetSystemCodes: string[];
TriggeredBy: TrigerredByEnum;
EventType: EventTypeEnum;
dbTransaction: Transaction;
}
export class SyncLogger {
private static readonly _Repository = new SyncLoggerRepository();
async logSyncTargets(params: LogSyncTargetsParams): Promise<void> {
const {
CustomerId,
SourceSystemCode,
TargetSystemCodes,
TriggeredBy,
EventType,
dbTransaction,
} = params;
for (const targetSystemCode of TargetSystemCodes) {
try {
if (targetSystemCode === SourceSystemCode) continue;
const policy = await SystemSyncPolicy.get(
SourceSystemCode,
targetSystemCode,
EventType,
);
const isAllowed =
!!policy &&
!(
(EventType === EventTypeEnum.Insert &&
policy.AllowInsertYN !== IsPolicyAllowInsertEnum.Y) ||
(EventType === EventTypeEnum.Update &&
policy.AllowUpdateYN !== IsPolicyAllowUpdateEnum.Y)
);
if (!isAllowed) {
console.info('[SyncLogger.logSyncTargets] skipped by policy', {
CustomerId,
SourceSystemCode,
TargetSystemCode: targetSystemCode,
EventType,
});
continue;
}
const logEntry = {
SyncLogId: cuid(),
CustomerId,
SourceSystemCode,
TargetSystemCode: targetSystemCode,
EventType,
TrigerredBy: TriggeredBy,
Status: SyncStatusEnum.Pending,
CreatedAt: new Date(),
UpdatedAt: new Date(),
};
await SyncLogger._Repository.create(logEntry, dbTransaction);
await this.enqueueForLog(
logEntry.SyncLogId,
CustomerId,
targetSystemCode,
dbTransaction,
);
} catch (err) {
console.error('[SyncLogger.logSyncTargets] outer failure', {
CustomerId,
SourceSystemCode,
EventType,
error: (err as Error)?.message,
});
throw err;
}
}
}
private async enqueueForLog(
syncLogId: string,
customerId: string,
targetSystemCode: string,
dbTransaction?: Transaction,
): Promise<void> {
const doEnqueue = async () => {
try {
const job = await syncQueue.add('syncCustomer', {
syncLogId,
customerId,
targetSystemCode,
});
// update created CustomerSyncLog record to write back BullMQ job id
await SyncLogger._Repository.update(
{
QueueJobId: String(job.id),
LastStatus: SyncStatusEnum.Pending,
LastAttemptAt: new Date(),
},
{
where: { SyncLogId: syncLogId },
},
);
} catch (err) {
await SyncLogger._Repository.update(
{ LastErrorMessage: String(err), LastAttemptAt: new Date() },
{ where: { SyncLogId: syncLogId } },
);
console.error('[SyncLogger.logSyncTargets] enqueue failed', {
SyncLogId: syncLogId,
error: (err as Error)?.message,
});
}
};
if (dbTransaction) {
dbTransaction.afterCommit(() => {
void doEnqueue();
});
} else {
await doEnqueue();
}
}
async markSuccess(
syncLogId: string,
transaction?: Transaction,
): Promise<void> {
try {
await SyncLogger._Repository.update(
{
QueueJobId: null,
Status: SyncStatusEnum.Success,
LastStatus: SyncStatusEnum.Success,
SyncedAt: new Date(),
LastAttemptAt: new Date(),
LastErrorMessage: null,
},
{ where: { SyncLogId: syncLogId }, transaction },
);
} catch (err) {
console.error('[SyncLogger.markSuccess] failed', {
syncLogId,
error: (err as Error)?.message,
});
throw err;
}
}
async markFailure(
syncLogId: string,
error: string,
transaction?: Transaction,
): Promise<void> {
try {
const record = await SyncLogger._Repository.findByPk(
syncLogId,
transaction,
);
const currentRetryCount = record?.RetryCount ?? 0;
await SyncLogger._Repository.update(
{
QueueJobId: null,
Status: SyncStatusEnum.Failed,
LastStatus: SyncStatusEnum.Failed,
LastAttemptAt: new Date(),
LastErrorMessage: error,
RetryCount: currentRetryCount + 1,
},
{ where: { SyncLogId: syncLogId }, transaction },
);
} catch (err) {
console.error('[SyncLogger.markFailure] failed', {
syncLogId,
incomingError: error,
error: (err as Error)?.message,
});
throw err;
}
}
async markSkipped(
syncLogId: string,
reason: string,
transaction?: Transaction,
): Promise<void> {
try {
await SyncLogger._Repository.update(
{
QueueJobId: null,
Status: SyncStatusEnum.Skipped,
LastStatus: SyncStatusEnum.Skipped,
LastAttemptAt: new Date(),
LastErrorMessage: reason,
},
{ where: { SyncLogId: syncLogId }, transaction },
);
} catch (err) {
console.error('[SyncLogger.markSkipped] failed', {
syncLogId,
reason,
error: (err as Error)?.message,
});
throw err;
}
}
}