mirror of
https://github.com/lingble/twenty.git
synced 2025-11-01 05:07:56 +00:00
Refactor sync sub status and throttle (#5734)
- Rename syncSubStatus to syncStage - Rename ongoingSyncStartedAt to syncStageStartedAt - Remove throttlePauseUntil from db and compute it with syncStageStartedAt and throttleFailureCount
This commit is contained in:
@@ -6903,9 +6903,9 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
|
|||||||
options: null,
|
options: null,
|
||||||
id: '24147b01-4394-4aee-92a4-5f6b5073704f',
|
id: '24147b01-4394-4aee-92a4-5f6b5073704f',
|
||||||
type: 'DATE_TIME',
|
type: 'DATE_TIME',
|
||||||
name: 'ongoingSyncStartedAt',
|
name: 'syncStageStartedAt',
|
||||||
label: 'Ongoing sync started at',
|
label: 'Sync stage started at',
|
||||||
description: 'Ongoing sync started at',
|
description: 'Sync stage started at',
|
||||||
icon: 'IconHistory',
|
icon: 'IconHistory',
|
||||||
isCustom: false,
|
isCustom: false,
|
||||||
isActive: true,
|
isActive: true,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { EntityManager } from 'typeorm';
|
import { EntityManager } from 'typeorm';
|
||||||
|
|
||||||
import { DEV_SEED_CONNECTED_ACCOUNT_IDS } from 'src/database/typeorm-seeds/workspace/connected-account';
|
import { DEV_SEED_CONNECTED_ACCOUNT_IDS } from 'src/database/typeorm-seeds/workspace/connected-account';
|
||||||
import { MessageChannelSyncSubStatus } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity';
|
import { MessageChannelSyncStage } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity';
|
||||||
|
|
||||||
const tableName = 'messageChannel';
|
const tableName = 'messageChannel';
|
||||||
|
|
||||||
@@ -28,7 +28,7 @@ export const seedMessageChannel = async (
|
|||||||
'connectedAccountId',
|
'connectedAccountId',
|
||||||
'handle',
|
'handle',
|
||||||
'visibility',
|
'visibility',
|
||||||
'syncSubStatus',
|
'syncStage',
|
||||||
])
|
])
|
||||||
.orIgnore()
|
.orIgnore()
|
||||||
.values([
|
.values([
|
||||||
@@ -42,8 +42,7 @@ export const seedMessageChannel = async (
|
|||||||
connectedAccountId: DEV_SEED_CONNECTED_ACCOUNT_IDS.TIM,
|
connectedAccountId: DEV_SEED_CONNECTED_ACCOUNT_IDS.TIM,
|
||||||
handle: 'tim@apple.dev',
|
handle: 'tim@apple.dev',
|
||||||
visibility: 'share_everything',
|
visibility: 'share_everything',
|
||||||
syncSubStatus:
|
syncStage: MessageChannelSyncStage.FULL_MESSAGE_LIST_FETCH_PENDING,
|
||||||
MessageChannelSyncSubStatus.FULL_MESSAGE_LIST_FETCH_PENDING,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: DEV_SEED_MESSAGE_CHANNEL_IDS.JONY,
|
id: DEV_SEED_MESSAGE_CHANNEL_IDS.JONY,
|
||||||
@@ -55,8 +54,7 @@ export const seedMessageChannel = async (
|
|||||||
connectedAccountId: DEV_SEED_CONNECTED_ACCOUNT_IDS.JONY,
|
connectedAccountId: DEV_SEED_CONNECTED_ACCOUNT_IDS.JONY,
|
||||||
handle: 'jony.ive@apple.dev',
|
handle: 'jony.ive@apple.dev',
|
||||||
visibility: 'share_everything',
|
visibility: 'share_everything',
|
||||||
syncSubStatus:
|
syncStage: MessageChannelSyncStage.FULL_MESSAGE_LIST_FETCH_PENDING,
|
||||||
MessageChannelSyncSubStatus.FULL_MESSAGE_LIST_FETCH_PENDING,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: DEV_SEED_MESSAGE_CHANNEL_IDS.PHIL,
|
id: DEV_SEED_MESSAGE_CHANNEL_IDS.PHIL,
|
||||||
@@ -68,8 +66,7 @@ export const seedMessageChannel = async (
|
|||||||
connectedAccountId: DEV_SEED_CONNECTED_ACCOUNT_IDS.PHIL,
|
connectedAccountId: DEV_SEED_CONNECTED_ACCOUNT_IDS.PHIL,
|
||||||
handle: 'phil.schiler@apple.dev',
|
handle: 'phil.schiler@apple.dev',
|
||||||
visibility: 'share_everything',
|
visibility: 'share_everything',
|
||||||
syncSubStatus:
|
syncStage: MessageChannelSyncStage.FULL_MESSAGE_LIST_FETCH_PENDING,
|
||||||
MessageChannelSyncSubStatus.FULL_MESSAGE_LIST_FETCH_PENDING,
|
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
.execute();
|
.execute();
|
||||||
|
|||||||
@@ -70,7 +70,6 @@ export const CALENDAR_CHANNEL_STANDARD_FIELD_IDS = {
|
|||||||
isSyncEnabled: '20202020-fe19-4818-8854-21f7b1b43395',
|
isSyncEnabled: '20202020-fe19-4818-8854-21f7b1b43395',
|
||||||
syncCursor: '20202020-bac2-4852-a5cb-7a7898992b70',
|
syncCursor: '20202020-bac2-4852-a5cb-7a7898992b70',
|
||||||
calendarChannelEventAssociations: '20202020-afb0-4a9f-979f-2d5087d71d09',
|
calendarChannelEventAssociations: '20202020-afb0-4a9f-979f-2d5087d71d09',
|
||||||
throttlePauseUntil: '20202020-16e8-40ca-be79-a3af4787af2c',
|
|
||||||
throttleFailureCount: '20202020-525c-4b76-b9bd-0dd57fd11d61',
|
throttleFailureCount: '20202020-525c-4b76-b9bd-0dd57fd11d61',
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -208,9 +207,8 @@ export const MESSAGE_CHANNEL_STANDARD_FIELD_IDS = {
|
|||||||
syncCursor: '20202020-79d1-41cf-b738-bcf5ed61e256',
|
syncCursor: '20202020-79d1-41cf-b738-bcf5ed61e256',
|
||||||
syncedAt: '20202020-263d-4c6b-ad51-137ada56f7d4',
|
syncedAt: '20202020-263d-4c6b-ad51-137ada56f7d4',
|
||||||
syncStatus: '20202020-56a1-4f7e-9880-a8493bb899cc',
|
syncStatus: '20202020-56a1-4f7e-9880-a8493bb899cc',
|
||||||
syncSubStatus: '20202020-7979-4b08-89fe-99cb5e698767',
|
syncStage: '20202020-7979-4b08-89fe-99cb5e698767',
|
||||||
ongoingSyncStartedAt: '20202020-8c61-4a42-ae63-73c1c3c52e06',
|
syncStageStartedAt: '20202020-8c61-4a42-ae63-73c1c3c52e06',
|
||||||
throttlePauseUntil: '20202020-a8cb-475b-868c-b83538614df4',
|
|
||||||
throttleFailureCount: '20202020-0291-42be-9ad0-d578a51684ab',
|
throttleFailureCount: '20202020-0291-42be-9ad0-d578a51684ab',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is
|
|||||||
import { WorkspaceIsNotAuditLogged } from 'src/engine/twenty-orm/decorators/workspace-is-not-audit-logged.decorator';
|
import { WorkspaceIsNotAuditLogged } from 'src/engine/twenty-orm/decorators/workspace-is-not-audit-logged.decorator';
|
||||||
import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field.decorator';
|
import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field.decorator';
|
||||||
import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator';
|
import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator';
|
||||||
import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator';
|
|
||||||
|
|
||||||
export enum CalendarChannelVisibility {
|
export enum CalendarChannelVisibility {
|
||||||
METADATA = 'METADATA',
|
METADATA = 'METADATA',
|
||||||
@@ -97,16 +96,6 @@ export class CalendarChannelWorkspaceEntity extends BaseWorkspaceEntity {
|
|||||||
})
|
})
|
||||||
syncCursor: string;
|
syncCursor: string;
|
||||||
|
|
||||||
@WorkspaceField({
|
|
||||||
standardId: CALENDAR_CHANNEL_STANDARD_FIELD_IDS.throttlePauseUntil,
|
|
||||||
type: FieldMetadataType.DATE_TIME,
|
|
||||||
label: 'Throttle Pause Until',
|
|
||||||
description: 'Throttle Pause Until',
|
|
||||||
icon: 'IconPlayerPause',
|
|
||||||
})
|
|
||||||
@WorkspaceIsNullable()
|
|
||||||
throttlePauseUntil: Date;
|
|
||||||
|
|
||||||
@WorkspaceField({
|
@WorkspaceField({
|
||||||
standardId: CALENDAR_CHANNEL_STANDARD_FIELD_IDS.throttleFailureCount,
|
standardId: CALENDAR_CHANNEL_STANDARD_FIELD_IDS.throttleFailureCount,
|
||||||
type: FieldMetadataType.NUMBER,
|
type: FieldMetadataType.NUMBER,
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metada
|
|||||||
import {
|
import {
|
||||||
MessageChannelWorkspaceEntity,
|
MessageChannelWorkspaceEntity,
|
||||||
MessageChannelSyncStatus,
|
MessageChannelSyncStatus,
|
||||||
MessageChannelSyncSubStatus,
|
MessageChannelSyncStage,
|
||||||
} from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity';
|
} from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@@ -51,7 +51,7 @@ export class MessageChannelRepository {
|
|||||||
this.workspaceDataSourceService.getSchemaName(workspaceId);
|
this.workspaceDataSourceService.getSchemaName(workspaceId);
|
||||||
|
|
||||||
await this.workspaceDataSourceService.executeRawQuery(
|
await this.workspaceDataSourceService.executeRawQuery(
|
||||||
`UPDATE ${dataSourceSchema}."messageChannel" SET "syncStatus" = NULL, "syncCursor" = '', "ongoingSyncStartedAt" = NULL
|
`UPDATE ${dataSourceSchema}."messageChannel" SET "syncStatus" = NULL, "syncCursor" = '', "syncStageStartedAt" = NULL
|
||||||
WHERE "connectedAccountId" = $1`,
|
WHERE "connectedAccountId" = $1`,
|
||||||
[connectedAccountId],
|
[connectedAccountId],
|
||||||
workspaceId,
|
workspaceId,
|
||||||
@@ -169,18 +169,11 @@ export class MessageChannelRepository {
|
|||||||
this.workspaceDataSourceService.getSchemaName(workspaceId);
|
this.workspaceDataSourceService.getSchemaName(workspaceId);
|
||||||
|
|
||||||
const needsToUpdateSyncedAt =
|
const needsToUpdateSyncedAt =
|
||||||
syncStatus === MessageChannelSyncStatus.SUCCEEDED;
|
syncStatus === MessageChannelSyncStatus.COMPLETED;
|
||||||
|
|
||||||
const needsToUpdateOngoingSyncStartedAt =
|
|
||||||
syncStatus === MessageChannelSyncStatus.ONGOING;
|
|
||||||
|
|
||||||
await this.workspaceDataSourceService.executeRawQuery(
|
await this.workspaceDataSourceService.executeRawQuery(
|
||||||
`UPDATE ${dataSourceSchema}."messageChannel" SET "syncStatus" = $1 ${
|
`UPDATE ${dataSourceSchema}."messageChannel" SET "syncStatus" = $1 ${
|
||||||
needsToUpdateSyncedAt ? `, "syncedAt" = NOW()` : ''
|
needsToUpdateSyncedAt ? `, "syncedAt" = NOW()` : ''
|
||||||
} ${
|
|
||||||
needsToUpdateOngoingSyncStartedAt
|
|
||||||
? `, "ongoingSyncStartedAt" = NOW()`
|
|
||||||
: `, "ongoingSyncStartedAt" = NULL`
|
|
||||||
} WHERE "id" = $2`,
|
} WHERE "id" = $2`,
|
||||||
[syncStatus, id],
|
[syncStatus, id],
|
||||||
workspaceId,
|
workspaceId,
|
||||||
@@ -188,9 +181,31 @@ export class MessageChannelRepository {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async updateSyncSubStatus(
|
public async updateSyncStage(
|
||||||
|
id: string,
|
||||||
|
syncStage: MessageChannelSyncStage,
|
||||||
|
workspaceId: string,
|
||||||
|
transactionManager?: EntityManager,
|
||||||
|
): Promise<void> {
|
||||||
|
const dataSourceSchema =
|
||||||
|
this.workspaceDataSourceService.getSchemaName(workspaceId);
|
||||||
|
|
||||||
|
const needsToUpdateSyncStageStartedAt =
|
||||||
|
syncStage === MessageChannelSyncStage.MESSAGES_IMPORT_ONGOING ||
|
||||||
|
syncStage === MessageChannelSyncStage.MESSAGE_LIST_FETCH_ONGOING;
|
||||||
|
|
||||||
|
await this.workspaceDataSourceService.executeRawQuery(
|
||||||
|
`UPDATE ${dataSourceSchema}."messageChannel" SET "syncStage" = $1 ${
|
||||||
|
needsToUpdateSyncStageStartedAt ? `, "syncStageStartedAt" = NOW()` : ''
|
||||||
|
} WHERE "id" = $2`,
|
||||||
|
[syncStage, id],
|
||||||
|
workspaceId,
|
||||||
|
transactionManager,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async resetSyncStageStartedAt(
|
||||||
id: string,
|
id: string,
|
||||||
syncSubStatus: MessageChannelSyncSubStatus,
|
|
||||||
workspaceId: string,
|
workspaceId: string,
|
||||||
transactionManager?: EntityManager,
|
transactionManager?: EntityManager,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
@@ -198,8 +213,8 @@ export class MessageChannelRepository {
|
|||||||
this.workspaceDataSourceService.getSchemaName(workspaceId);
|
this.workspaceDataSourceService.getSchemaName(workspaceId);
|
||||||
|
|
||||||
await this.workspaceDataSourceService.executeRawQuery(
|
await this.workspaceDataSourceService.executeRawQuery(
|
||||||
`UPDATE ${dataSourceSchema}."messageChannel" SET "syncSubStatus" = $1 WHERE "id" = $2`,
|
`UPDATE ${dataSourceSchema}."messageChannel" SET "syncStageStartedAt" = NULL WHERE "id" = $1`,
|
||||||
[syncSubStatus, id],
|
[id],
|
||||||
workspaceId,
|
workspaceId,
|
||||||
transactionManager,
|
transactionManager,
|
||||||
);
|
);
|
||||||
@@ -241,9 +256,8 @@ export class MessageChannelRepository {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async updateThrottlePauseUntilAndIncrementThrottleFailureCount(
|
public async incrementThrottleFailureCount(
|
||||||
id: string,
|
id: string,
|
||||||
throttleDurationMs: number,
|
|
||||||
workspaceId: string,
|
workspaceId: string,
|
||||||
transactionManager?: EntityManager,
|
transactionManager?: EntityManager,
|
||||||
) {
|
) {
|
||||||
@@ -251,15 +265,15 @@ export class MessageChannelRepository {
|
|||||||
this.workspaceDataSourceService.getSchemaName(workspaceId);
|
this.workspaceDataSourceService.getSchemaName(workspaceId);
|
||||||
|
|
||||||
await this.workspaceDataSourceService.executeRawQuery(
|
await this.workspaceDataSourceService.executeRawQuery(
|
||||||
`UPDATE ${dataSourceSchema}."messageChannel" SET "throttlePauseUntil" = NOW() + ($1 || ' milliseconds')::interval, "throttleFailureCount" = "throttleFailureCount" + 1
|
`UPDATE ${dataSourceSchema}."messageChannel" SET "throttleFailureCount" = "throttleFailureCount" + 1
|
||||||
WHERE "id" = $2`,
|
WHERE "id" = $1`,
|
||||||
[throttleDurationMs, id],
|
[id],
|
||||||
workspaceId,
|
workspaceId,
|
||||||
transactionManager,
|
transactionManager,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async resetThrottlePauseUntilAndThrottleFailureCount(
|
public async resetThrottleFailureCount(
|
||||||
id: string,
|
id: string,
|
||||||
workspaceId: string,
|
workspaceId: string,
|
||||||
transactionManager?: EntityManager,
|
transactionManager?: EntityManager,
|
||||||
@@ -268,7 +282,7 @@ export class MessageChannelRepository {
|
|||||||
this.workspaceDataSourceService.getSchemaName(workspaceId);
|
this.workspaceDataSourceService.getSchemaName(workspaceId);
|
||||||
|
|
||||||
await this.workspaceDataSourceService.executeRawQuery(
|
await this.workspaceDataSourceService.executeRawQuery(
|
||||||
`UPDATE ${dataSourceSchema}."messageChannel" SET "throttlePauseUntil" = NULL, "throttleFailureCount" = 0
|
`UPDATE ${dataSourceSchema}."messageChannel" SET "throttleFailureCount" = 0
|
||||||
WHERE "id" = $1`,
|
WHERE "id" = $1`,
|
||||||
[id],
|
[id],
|
||||||
workspaceId,
|
workspaceId,
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repos
|
|||||||
import { MessageChannelRepository } from 'src/modules/messaging/common/repositories/message-channel.repository';
|
import { MessageChannelRepository } from 'src/modules/messaging/common/repositories/message-channel.repository';
|
||||||
import {
|
import {
|
||||||
MessageChannelWorkspaceEntity,
|
MessageChannelWorkspaceEntity,
|
||||||
MessageChannelSyncSubStatus,
|
MessageChannelSyncStage,
|
||||||
MessageChannelSyncStatus,
|
MessageChannelSyncStatus,
|
||||||
} from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity';
|
} from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity';
|
||||||
|
|
||||||
@@ -24,9 +24,9 @@ export class MessagingChannelSyncStatusService {
|
|||||||
messageChannelId: string,
|
messageChannelId: string,
|
||||||
workspaceId: string,
|
workspaceId: string,
|
||||||
) {
|
) {
|
||||||
await this.messageChannelRepository.updateSyncSubStatus(
|
await this.messageChannelRepository.updateSyncStage(
|
||||||
messageChannelId,
|
messageChannelId,
|
||||||
MessageChannelSyncSubStatus.FULL_MESSAGE_LIST_FETCH_PENDING,
|
MessageChannelSyncStage.FULL_MESSAGE_LIST_FETCH_PENDING,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -35,9 +35,9 @@ export class MessagingChannelSyncStatusService {
|
|||||||
messageChannelId: string,
|
messageChannelId: string,
|
||||||
workspaceId: string,
|
workspaceId: string,
|
||||||
) {
|
) {
|
||||||
await this.messageChannelRepository.updateSyncSubStatus(
|
await this.messageChannelRepository.updateSyncStage(
|
||||||
messageChannelId,
|
messageChannelId,
|
||||||
MessageChannelSyncSubStatus.PARTIAL_MESSAGE_LIST_FETCH_PENDING,
|
MessageChannelSyncStage.PARTIAL_MESSAGE_LIST_FETCH_PENDING,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -46,9 +46,9 @@ export class MessagingChannelSyncStatusService {
|
|||||||
messageChannelId: string,
|
messageChannelId: string,
|
||||||
workspaceId: string,
|
workspaceId: string,
|
||||||
) {
|
) {
|
||||||
await this.messageChannelRepository.updateSyncSubStatus(
|
await this.messageChannelRepository.updateSyncStage(
|
||||||
messageChannelId,
|
messageChannelId,
|
||||||
MessageChannelSyncSubStatus.MESSAGES_IMPORT_PENDING,
|
MessageChannelSyncStage.MESSAGES_IMPORT_PENDING,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -68,6 +68,16 @@ export class MessagingChannelSyncStatusService {
|
|||||||
workspaceId,
|
workspaceId,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
await this.messageChannelRepository.resetSyncStageStartedAt(
|
||||||
|
messageChannelId,
|
||||||
|
workspaceId,
|
||||||
|
);
|
||||||
|
|
||||||
|
await this.messageChannelRepository.resetThrottleFailureCount(
|
||||||
|
messageChannelId,
|
||||||
|
workspaceId,
|
||||||
|
);
|
||||||
|
|
||||||
await this.scheduleFullMessageListFetch(messageChannelId, workspaceId);
|
await this.scheduleFullMessageListFetch(messageChannelId, workspaceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,9 +85,9 @@ export class MessagingChannelSyncStatusService {
|
|||||||
messageChannelId: string,
|
messageChannelId: string,
|
||||||
workspaceId: string,
|
workspaceId: string,
|
||||||
) {
|
) {
|
||||||
await this.messageChannelRepository.updateSyncSubStatus(
|
await this.messageChannelRepository.updateSyncStage(
|
||||||
messageChannelId,
|
messageChannelId,
|
||||||
MessageChannelSyncSubStatus.MESSAGE_LIST_FETCH_ONGOING,
|
MessageChannelSyncStage.MESSAGE_LIST_FETCH_ONGOING,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -105,9 +115,9 @@ export class MessagingChannelSyncStatusService {
|
|||||||
messageChannelId: string,
|
messageChannelId: string,
|
||||||
workspaceId: string,
|
workspaceId: string,
|
||||||
) {
|
) {
|
||||||
await this.messageChannelRepository.updateSyncSubStatus(
|
await this.messageChannelRepository.updateSyncStage(
|
||||||
messageChannelId,
|
messageChannelId,
|
||||||
MessageChannelSyncSubStatus.MESSAGES_IMPORT_ONGOING,
|
MessageChannelSyncStage.MESSAGES_IMPORT_ONGOING,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -120,9 +130,9 @@ export class MessagingChannelSyncStatusService {
|
|||||||
`messages-to-import:${workspaceId}:gmail:${messageChannelId}`,
|
`messages-to-import:${workspaceId}:gmail:${messageChannelId}`,
|
||||||
);
|
);
|
||||||
|
|
||||||
await this.messageChannelRepository.updateSyncSubStatus(
|
await this.messageChannelRepository.updateSyncStage(
|
||||||
messageChannelId,
|
messageChannelId,
|
||||||
MessageChannelSyncSubStatus.FAILED,
|
MessageChannelSyncStage.FAILED,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -141,9 +151,9 @@ export class MessagingChannelSyncStatusService {
|
|||||||
`messages-to-import:${workspaceId}:gmail:${messageChannelId}`,
|
`messages-to-import:${workspaceId}:gmail:${messageChannelId}`,
|
||||||
);
|
);
|
||||||
|
|
||||||
await this.messageChannelRepository.updateSyncSubStatus(
|
await this.messageChannelRepository.updateSyncStage(
|
||||||
messageChannelId,
|
messageChannelId,
|
||||||
MessageChannelSyncSubStatus.FAILED,
|
MessageChannelSyncStage.FAILED,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import { MessagingTelemetryService } from 'src/modules/messaging/common/services
|
|||||||
import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity';
|
import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity';
|
||||||
import { MessagingChannelSyncStatusService } from 'src/modules/messaging/common/services/messaging-channel-sync-status.service';
|
import { MessagingChannelSyncStatusService } from 'src/modules/messaging/common/services/messaging-channel-sync-status.service';
|
||||||
import { MessageChannelRepository } from 'src/modules/messaging/common/repositories/message-channel.repository';
|
import { MessageChannelRepository } from 'src/modules/messaging/common/repositories/message-channel.repository';
|
||||||
import { MESSAGING_THROTTLE_DURATION } from 'src/modules/messaging/common/constants/messaging-throttle-duration';
|
|
||||||
import { MESSAGING_THROTTLE_MAX_ATTEMPTS } from 'src/modules/messaging/common/constants/messaging-throttle-max-attempts';
|
import { MESSAGING_THROTTLE_MAX_ATTEMPTS } from 'src/modules/messaging/common/constants/messaging-throttle-max-attempts';
|
||||||
|
|
||||||
type SyncStep =
|
type SyncStep =
|
||||||
@@ -212,13 +211,8 @@ export class MessagingErrorHandlingService {
|
|||||||
messageChannel: ObjectRecord<MessageChannelWorkspaceEntity>,
|
messageChannel: ObjectRecord<MessageChannelWorkspaceEntity>,
|
||||||
workspaceId: string,
|
workspaceId: string,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const throttleDuration =
|
await this.messageChannelRepository.incrementThrottleFailureCount(
|
||||||
MESSAGING_THROTTLE_DURATION *
|
|
||||||
Math.pow(2, messageChannel.throttleFailureCount);
|
|
||||||
|
|
||||||
await this.messageChannelRepository.updateThrottlePauseUntilAndIncrementThrottleFailureCount(
|
|
||||||
messageChannel.id,
|
messageChannel.id,
|
||||||
throttleDuration,
|
|
||||||
workspaceId,
|
workspaceId,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -227,7 +221,7 @@ export class MessagingErrorHandlingService {
|
|||||||
workspaceId,
|
workspaceId,
|
||||||
connectedAccountId: messageChannel.connectedAccountId,
|
connectedAccountId: messageChannel.connectedAccountId,
|
||||||
messageChannelId: messageChannel.id,
|
messageChannelId: messageChannel.id,
|
||||||
message: `Throttling for ${throttleDuration}ms`,
|
message: `Increment throttle failure count to ${messageChannel.throttleFailureCount}`,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ export enum MessageChannelSyncStatus {
|
|||||||
FAILED_UNKNOWN = 'FAILED_UNKNOWN',
|
FAILED_UNKNOWN = 'FAILED_UNKNOWN',
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum MessageChannelSyncSubStatus {
|
export enum MessageChannelSyncStage {
|
||||||
FULL_MESSAGE_LIST_FETCH_PENDING = 'FULL_MESSAGE_LIST_FETCH_PENDING',
|
FULL_MESSAGE_LIST_FETCH_PENDING = 'FULL_MESSAGE_LIST_FETCH_PENDING',
|
||||||
PARTIAL_MESSAGE_LIST_FETCH_PENDING = 'PARTIAL_MESSAGE_LIST_FETCH_PENDING',
|
PARTIAL_MESSAGE_LIST_FETCH_PENDING = 'PARTIAL_MESSAGE_LIST_FETCH_PENDING',
|
||||||
MESSAGE_LIST_FETCH_ONGOING = 'MESSAGE_LIST_FETCH_ONGOING',
|
MESSAGE_LIST_FETCH_ONGOING = 'MESSAGE_LIST_FETCH_ONGOING',
|
||||||
@@ -227,72 +227,62 @@ export class MessageChannelWorkspaceEntity extends BaseWorkspaceEntity {
|
|||||||
syncStatus: MessageChannelSyncStatus;
|
syncStatus: MessageChannelSyncStatus;
|
||||||
|
|
||||||
@WorkspaceField({
|
@WorkspaceField({
|
||||||
standardId: MESSAGE_CHANNEL_STANDARD_FIELD_IDS.syncSubStatus,
|
standardId: MESSAGE_CHANNEL_STANDARD_FIELD_IDS.syncStage,
|
||||||
type: FieldMetadataType.SELECT,
|
type: FieldMetadataType.SELECT,
|
||||||
label: 'Sync sub status',
|
label: 'Sync stage',
|
||||||
description: 'Sync sub status',
|
description: 'Sync stage',
|
||||||
icon: 'IconStatusChange',
|
icon: 'IconStatusChange',
|
||||||
options: [
|
options: [
|
||||||
{
|
{
|
||||||
value: MessageChannelSyncSubStatus.FULL_MESSAGE_LIST_FETCH_PENDING,
|
value: MessageChannelSyncStage.FULL_MESSAGE_LIST_FETCH_PENDING,
|
||||||
label: 'Full messages list fetch pending',
|
label: 'Full messages list fetch pending',
|
||||||
position: 0,
|
position: 0,
|
||||||
color: 'blue',
|
color: 'blue',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: MessageChannelSyncSubStatus.PARTIAL_MESSAGE_LIST_FETCH_PENDING,
|
value: MessageChannelSyncStage.PARTIAL_MESSAGE_LIST_FETCH_PENDING,
|
||||||
label: 'Partial messages list fetch pending',
|
label: 'Partial messages list fetch pending',
|
||||||
position: 1,
|
position: 1,
|
||||||
color: 'blue',
|
color: 'blue',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: MessageChannelSyncSubStatus.MESSAGE_LIST_FETCH_ONGOING,
|
value: MessageChannelSyncStage.MESSAGE_LIST_FETCH_ONGOING,
|
||||||
label: 'Messages list fetch ongoing',
|
label: 'Messages list fetch ongoing',
|
||||||
position: 2,
|
position: 2,
|
||||||
color: 'orange',
|
color: 'orange',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: MessageChannelSyncSubStatus.MESSAGES_IMPORT_PENDING,
|
value: MessageChannelSyncStage.MESSAGES_IMPORT_PENDING,
|
||||||
label: 'Messages import pending',
|
label: 'Messages import pending',
|
||||||
position: 3,
|
position: 3,
|
||||||
color: 'blue',
|
color: 'blue',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: MessageChannelSyncSubStatus.MESSAGES_IMPORT_ONGOING,
|
value: MessageChannelSyncStage.MESSAGES_IMPORT_ONGOING,
|
||||||
label: 'Messages import ongoing',
|
label: 'Messages import ongoing',
|
||||||
position: 4,
|
position: 4,
|
||||||
color: 'orange',
|
color: 'orange',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: MessageChannelSyncSubStatus.FAILED,
|
value: MessageChannelSyncStage.FAILED,
|
||||||
label: 'Failed',
|
label: 'Failed',
|
||||||
position: 5,
|
position: 5,
|
||||||
color: 'red',
|
color: 'red',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
defaultValue: `'${MessageChannelSyncSubStatus.FULL_MESSAGE_LIST_FETCH_PENDING}'`,
|
defaultValue: `'${MessageChannelSyncStage.FULL_MESSAGE_LIST_FETCH_PENDING}'`,
|
||||||
})
|
})
|
||||||
syncSubStatus: MessageChannelSyncSubStatus;
|
syncStage: MessageChannelSyncStage;
|
||||||
|
|
||||||
@WorkspaceField({
|
@WorkspaceField({
|
||||||
standardId: MESSAGE_CHANNEL_STANDARD_FIELD_IDS.ongoingSyncStartedAt,
|
standardId: MESSAGE_CHANNEL_STANDARD_FIELD_IDS.syncStageStartedAt,
|
||||||
type: FieldMetadataType.DATE_TIME,
|
type: FieldMetadataType.DATE_TIME,
|
||||||
label: 'Ongoing sync started at',
|
label: 'Sync stage started at',
|
||||||
description: 'Ongoing sync started at',
|
description: 'Sync stage started at',
|
||||||
icon: 'IconHistory',
|
icon: 'IconHistory',
|
||||||
})
|
})
|
||||||
@WorkspaceIsNullable()
|
@WorkspaceIsNullable()
|
||||||
ongoingSyncStartedAt: string;
|
syncStageStartedAt: string;
|
||||||
|
|
||||||
@WorkspaceField({
|
|
||||||
standardId: MESSAGE_CHANNEL_STANDARD_FIELD_IDS.throttlePauseUntil,
|
|
||||||
type: FieldMetadataType.DATE_TIME,
|
|
||||||
label: 'Throttle Pause Until',
|
|
||||||
description: 'Throttle Pause Until',
|
|
||||||
icon: 'IconPlayerPause',
|
|
||||||
})
|
|
||||||
@WorkspaceIsNullable()
|
|
||||||
throttlePauseUntil: Date;
|
|
||||||
|
|
||||||
@WorkspaceField({
|
@WorkspaceField({
|
||||||
standardId: MESSAGE_CHANNEL_STANDARD_FIELD_IDS.throttleFailureCount,
|
standardId: MESSAGE_CHANNEL_STANDARD_FIELD_IDS.throttleFailureCount,
|
||||||
|
|||||||
@@ -77,7 +77,12 @@ export class MessagingGmailFullMessageListFetchService {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.messageChannelRepository.resetThrottlePauseUntilAndThrottleFailureCount(
|
await this.messageChannelRepository.resetThrottleFailureCount(
|
||||||
|
messageChannel.id,
|
||||||
|
workspaceId,
|
||||||
|
);
|
||||||
|
|
||||||
|
await this.messageChannelRepository.resetSyncStageStartedAt(
|
||||||
messageChannel.id,
|
messageChannel.id,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { BlocklistRepository } from 'src/modules/connected-account/repositories/
|
|||||||
import { MessagingTelemetryService } from 'src/modules/messaging/common/services/messaging-telemetry.service';
|
import { MessagingTelemetryService } from 'src/modules/messaging/common/services/messaging-telemetry.service';
|
||||||
import {
|
import {
|
||||||
MessageChannelWorkspaceEntity,
|
MessageChannelWorkspaceEntity,
|
||||||
MessageChannelSyncSubStatus,
|
MessageChannelSyncStage,
|
||||||
} from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity';
|
} from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity';
|
||||||
import { createQueriesFromMessageIds } from 'src/modules/messaging/message-import-manager/utils/create-queries-from-message-ids.util';
|
import { createQueriesFromMessageIds } from 'src/modules/messaging/message-import-manager/utils/create-queries-from-message-ids.util';
|
||||||
import { filterEmails } from 'src/modules/messaging/message-import-manager/utils/filter-emails.util';
|
import { filterEmails } from 'src/modules/messaging/message-import-manager/utils/filter-emails.util';
|
||||||
@@ -50,8 +50,8 @@ export class MessagingGmailMessagesImportService {
|
|||||||
workspaceId: string,
|
workspaceId: string,
|
||||||
) {
|
) {
|
||||||
if (
|
if (
|
||||||
messageChannel.syncSubStatus !==
|
messageChannel.syncStage !==
|
||||||
MessageChannelSyncSubStatus.MESSAGES_IMPORT_PENDING
|
MessageChannelSyncStage.MESSAGES_IMPORT_PENDING
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -137,7 +137,12 @@ export class MessagingGmailMessagesImportService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.messageChannelRepository.resetThrottlePauseUntilAndThrottleFailureCount(
|
await this.messageChannelRepository.resetThrottleFailureCount(
|
||||||
|
messageChannel.id,
|
||||||
|
workspaceId,
|
||||||
|
);
|
||||||
|
|
||||||
|
await this.messageChannelRepository.resetSyncStageStartedAt(
|
||||||
messageChannel.id,
|
messageChannel.id,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -74,7 +74,12 @@ export class MessagingGmailPartialMessageListFetchService {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.messageChannelRepository.resetThrottlePauseUntilAndThrottleFailureCount(
|
await this.messageChannelRepository.resetThrottleFailureCount(
|
||||||
|
messageChannel.id,
|
||||||
|
workspaceId,
|
||||||
|
);
|
||||||
|
|
||||||
|
await this.messageChannelRepository.resetSyncStageStartedAt(
|
||||||
messageChannel.id,
|
messageChannel.id,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import { MESSAGING_THROTTLE_DURATION } from 'src/modules/messaging/common/constants/messaging-throttle-duration';
|
||||||
|
|
||||||
|
export const isThrottled = (
|
||||||
|
syncStageStartedAt: string | null,
|
||||||
|
throttleFailureCount: number,
|
||||||
|
): boolean => {
|
||||||
|
if (!syncStageStartedAt) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
computeThrottlePauseUntil(syncStageStartedAt, throttleFailureCount) >
|
||||||
|
new Date()
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const computeThrottlePauseUntil = (
|
||||||
|
syncStageStartedAt: string,
|
||||||
|
throttleFailureCount: number,
|
||||||
|
): Date => {
|
||||||
|
return new Date(
|
||||||
|
new Date(syncStageStartedAt).getTime() +
|
||||||
|
MESSAGING_THROTTLE_DURATION * Math.pow(2, throttleFailureCount - 1),
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -8,11 +8,12 @@ import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/s
|
|||||||
import { MessageChannelRepository } from 'src/modules/messaging/common/repositories/message-channel.repository';
|
import { MessageChannelRepository } from 'src/modules/messaging/common/repositories/message-channel.repository';
|
||||||
import { MessagingTelemetryService } from 'src/modules/messaging/common/services/messaging-telemetry.service';
|
import { MessagingTelemetryService } from 'src/modules/messaging/common/services/messaging-telemetry.service';
|
||||||
import {
|
import {
|
||||||
MessageChannelSyncSubStatus,
|
MessageChannelSyncStage,
|
||||||
MessageChannelWorkspaceEntity,
|
MessageChannelWorkspaceEntity,
|
||||||
} from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity';
|
} from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity';
|
||||||
import { MessagingGmailFullMessageListFetchService } from 'src/modules/messaging/message-import-manager/drivers/gmail/services/messaging-gmail-full-message-list-fetch.service';
|
import { MessagingGmailFullMessageListFetchService } from 'src/modules/messaging/message-import-manager/drivers/gmail/services/messaging-gmail-full-message-list-fetch.service';
|
||||||
import { MessagingGmailPartialMessageListFetchService } from 'src/modules/messaging/message-import-manager/drivers/gmail/services/messaging-gmail-partial-message-list-fetch.service';
|
import { MessagingGmailPartialMessageListFetchService } from 'src/modules/messaging/message-import-manager/drivers/gmail/services/messaging-gmail-partial-message-list-fetch.service';
|
||||||
|
import { isThrottled } from 'src/modules/messaging/message-import-manager/drivers/gmail/utils/is-throttled';
|
||||||
|
|
||||||
export type MessagingMessageListFetchJobData = {
|
export type MessagingMessageListFetchJobData = {
|
||||||
workspaceId: string;
|
workspaceId: string;
|
||||||
@@ -76,14 +77,16 @@ export class MessagingMessageListFetchJob
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
messageChannel.throttlePauseUntil &&
|
isThrottled(
|
||||||
messageChannel.throttlePauseUntil > new Date()
|
messageChannel.syncStageStartedAt,
|
||||||
|
messageChannel.throttleFailureCount,
|
||||||
|
)
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (messageChannel.syncSubStatus) {
|
switch (messageChannel.syncStage) {
|
||||||
case MessageChannelSyncSubStatus.PARTIAL_MESSAGE_LIST_FETCH_PENDING:
|
case MessageChannelSyncStage.PARTIAL_MESSAGE_LIST_FETCH_PENDING:
|
||||||
this.logger.log(
|
this.logger.log(
|
||||||
`Fetching partial message list for workspace ${workspaceId} and account ${connectedAccount.id}`,
|
`Fetching partial message list for workspace ${workspaceId} and account ${connectedAccount.id}`,
|
||||||
);
|
);
|
||||||
@@ -110,7 +113,7 @@ export class MessagingMessageListFetchJob
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MessageChannelSyncSubStatus.FULL_MESSAGE_LIST_FETCH_PENDING:
|
case MessageChannelSyncStage.FULL_MESSAGE_LIST_FETCH_PENDING:
|
||||||
this.logger.log(
|
this.logger.log(
|
||||||
`Fetching full message list for workspace ${workspaceId} and account ${connectedAccount.id}`,
|
`Fetching full message list for workspace ${workspaceId} and account ${connectedAccount.id}`,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { MessageChannelRepository } from 'src/modules/messaging/common/repositor
|
|||||||
import { MessagingTelemetryService } from 'src/modules/messaging/common/services/messaging-telemetry.service';
|
import { MessagingTelemetryService } from 'src/modules/messaging/common/services/messaging-telemetry.service';
|
||||||
import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity';
|
import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity';
|
||||||
import { MessagingGmailMessagesImportService } from 'src/modules/messaging/message-import-manager/drivers/gmail/services/messaging-gmail-messages-import.service';
|
import { MessagingGmailMessagesImportService } from 'src/modules/messaging/message-import-manager/drivers/gmail/services/messaging-gmail-messages-import.service';
|
||||||
|
import { isThrottled } from 'src/modules/messaging/message-import-manager/drivers/gmail/utils/is-throttled';
|
||||||
|
|
||||||
export type MessagingMessagesImportJobData = {
|
export type MessagingMessagesImportJobData = {
|
||||||
workspaceId: string;
|
workspaceId: string;
|
||||||
@@ -46,8 +47,10 @@ export class MessagingMessagesImportJob
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (
|
if (
|
||||||
messageChannel.throttlePauseUntil &&
|
isThrottled(
|
||||||
messageChannel.throttlePauseUntil > new Date()
|
messageChannel.syncStageStartedAt,
|
||||||
|
messageChannel.throttleFailureCount,
|
||||||
|
)
|
||||||
) {
|
) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user