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:
bosiraphael
2024-06-04 16:52:57 +02:00
committed by GitHub
parent ce1469cf0c
commit 234e062232
14 changed files with 148 additions and 110 deletions

View File

@@ -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,

View File

@@ -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();

View File

@@ -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',
}; };

View File

@@ -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,

View File

@@ -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,

View File

@@ -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,
); );

View File

@@ -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}`,
}); });
} }
} }

View File

@@ -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,

View File

@@ -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,
); );

View File

@@ -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,
); );

View File

@@ -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,
); );

View File

@@ -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),
);
};

View File

@@ -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}`,
); );

View File

@@ -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;
} }