From a965c513f1c54f230995b03834a4b2deec2a3a4f Mon Sep 17 00:00:00 2001
From: Aubin <60398825+aubin-tchoi@users.noreply.github.com>
Date: Thu, 28 Nov 2024 17:16:30 +0100
Subject: [PATCH] :loud_sound: add logs to the garbage collection (#8998)

---
 .../zendesk/temporal/gc_activities.ts         | 118 ++++++++++++++++--
 connectors/src/resources/zendesk_resources.ts |   4 +-
 2 files changed, 107 insertions(+), 15 deletions(-)

diff --git a/connectors/src/connectors/zendesk/temporal/gc_activities.ts b/connectors/src/connectors/zendesk/temporal/gc_activities.ts
index 07eabfd793b5..6cb2f41e8743 100644
--- a/connectors/src/connectors/zendesk/temporal/gc_activities.ts
+++ b/connectors/src/connectors/zendesk/temporal/gc_activities.ts
@@ -13,10 +13,12 @@ import {
   createZendeskClient,
   fetchZendeskArticle,
 } from "@connectors/connectors/zendesk/lib/zendesk_api";
+import { getZendeskGarbageCollectionWorkflowId } from "@connectors/connectors/zendesk/temporal/client";
 import { ZENDESK_BATCH_SIZE } from "@connectors/connectors/zendesk/temporal/config";
 import { dataSourceConfigFromConnector } from "@connectors/lib/api/data_source_config";
 import { concurrentExecutor } from "@connectors/lib/async_utils";
 import { deleteFromDataSource } from "@connectors/lib/data_sources";
+import logger from "@connectors/logger/logger";
 import { ConnectorResource } from "@connectors/resources/connector_resource";
 import {
   ZendeskArticleResource,
@@ -80,18 +82,6 @@ export async function removeOutdatedTicketBatchActivity(
       `[Zendesk] Configuration not found, connectorId: ${connectorId}`
     );
   }
-  const ticketIds = await ZendeskTicketResource.fetchOutdatedTicketIds({
-    connectorId,
-    expirationDate: new Date(
-      Date.now() - configuration.retentionPeriodDays * 24 * 60 * 60 * 1000 // conversion from days to ms
-    ),
-    batchSize: ZENDESK_BATCH_SIZE,
-  });
-
-  if (ticketIds.length === 0) {
-    return { hasMore: false };
-  }
-
   const connector = await ConnectorResource.fetchById(connectorId);
   if (!connector) {
     throw new Error("[Zendesk] Connector not found.");
@@ -101,9 +91,26 @@ export async function removeOutdatedTicketBatchActivity(
     workspaceId: dataSourceConfig.workspaceId,
     connectorId,
     provider: "zendesk",
+    workflowId: getZendeskGarbageCollectionWorkflowId(connectorId),
     dataSourceId: dataSourceConfig.dataSourceId,
   };
 
+  const ticketIds = await ZendeskTicketResource.fetchOutdatedTicketIds({
+    connectorId,
+    expirationDate: new Date(
+      Date.now() - configuration.retentionPeriodDays * 24 * 60 * 60 * 1000 // conversion from days to ms
+    ),
+    batchSize: ZENDESK_BATCH_SIZE,
+  });
+  logger.info(
+    { ...loggerArgs, ticketCount: ticketIds.length },
+    "[Zendesk] Removing outdated tickets."
+  );
+
+  if (ticketIds.length === 0) {
+    return { hasMore: false };
+  }
+
   await concurrentExecutor(
     ticketIds,
     (ticketId) =>
@@ -148,6 +155,7 @@ export async function removeMissingArticleBatchActivity({
     workspaceId: dataSourceConfig.workspaceId,
     connectorId,
     provider: "zendesk",
+    workflowId: getZendeskGarbageCollectionWorkflowId(connectorId),
     dataSourceId: dataSourceConfig.dataSourceId,
   };
 
@@ -194,6 +202,13 @@ export async function removeForbiddenCategoriesActivity(
     throw new Error("[Zendesk] Connector not found.");
   }
   const dataSourceConfig = dataSourceConfigFromConnector(connector);
+  const loggerArgs = {
+    workspaceId: dataSourceConfig.workspaceId,
+    connectorId,
+    provider: "zendesk",
+    workflowId: getZendeskGarbageCollectionWorkflowId(connectorId),
+    dataSourceId: dataSourceConfig.dataSourceId,
+  };
 
   const batchSize = 2; // we process categories 2 by 2 since each of them typically contains ~50 articles
   const categoryIds =
@@ -201,6 +216,11 @@ export async function removeForbiddenCategoriesActivity(
       connectorId,
       batchSize,
     });
+  logger.info(
+    { ...loggerArgs, categoryCount: categoryIds.length },
+    "[Zendesk] Removing categories with no permission."
+  );
+
   for (const categoryId of categoryIds) {
     await deleteCategory({ connectorId, categoryId, dataSourceConfig });
   }
@@ -216,6 +236,13 @@ export async function removeEmptyCategoriesActivity(connectorId: number) {
     throw new Error("[Zendesk] Connector not found.");
   }
   const dataSourceConfig = dataSourceConfigFromConnector(connector);
+  const loggerArgs = {
+    workspaceId: dataSourceConfig.workspaceId,
+    connectorId,
+    provider: "zendesk",
+    workflowId: getZendeskGarbageCollectionWorkflowId(connectorId),
+    dataSourceId: dataSourceConfig.dataSourceId,
+  };
 
   const categoryIds = (
     await ZendeskCategoryResource.fetchIdsForConnector(connectorId)
@@ -235,6 +262,11 @@ export async function removeEmptyCategoriesActivity(connectorId: number) {
     },
     { concurrency: 10 }
   );
+  logger.info(
+    { ...loggerArgs, categoryCount: categoriesToDelete.size },
+    "[Zendesk] Removing empty categories."
+  );
+
   for (const categoryId of categoriesToDelete) {
     await deleteCategory({ connectorId, categoryId, dataSourceConfig });
   }
@@ -246,7 +278,26 @@ export async function removeEmptyCategoriesActivity(connectorId: number) {
 export async function deleteBrandsWithNoPermissionActivity(
   connectorId: ModelId
 ): Promise<void> {
-  await ZendeskBrandResource.deleteBrandsWithNoPermission(connectorId);
+  const connector = await ConnectorResource.fetchById(connectorId);
+  if (!connector) {
+    throw new Error("[Zendesk] Connector not found.");
+  }
+  const dataSourceConfig = dataSourceConfigFromConnector(connector);
+  const loggerArgs = {
+    workspaceId: dataSourceConfig.workspaceId,
+    connectorId,
+    provider: "zendesk",
+    workflowId: getZendeskGarbageCollectionWorkflowId(connectorId),
+    dataSourceId: dataSourceConfig.dataSourceId,
+  };
+
+  const deletedCount =
+    await ZendeskBrandResource.deleteBrandsWithNoPermission(connectorId);
+
+  logger.info(
+    { ...loggerArgs, deletedCount },
+    "[Zendesk] Deleting brands with no permission."
+  );
 }
 
 /**
@@ -264,12 +315,24 @@ export async function deleteTicketBatchActivity({
     throw new Error("[Zendesk] Connector not found.");
   }
   const dataSourceConfig = dataSourceConfigFromConnector(connector);
+  const loggerArgs = {
+    workspaceId: dataSourceConfig.workspaceId,
+    connectorId,
+    provider: "zendesk",
+    workflowId: getZendeskGarbageCollectionWorkflowId(connectorId),
+    dataSourceId: dataSourceConfig.dataSourceId,
+  };
 
   const ticketIds = await ZendeskTicketResource.fetchTicketIdsByBrandId({
     connectorId,
     brandId,
     batchSize: ZENDESK_BATCH_SIZE,
   });
+  logger.info(
+    { ...loggerArgs, brandId, ticketCount: ticketIds.length },
+    "[Zendesk] Deleting a batch of tickets."
+  );
+
   /// deleting the tickets in the data source
   await concurrentExecutor(
     ticketIds,
@@ -302,6 +365,13 @@ export async function deleteArticleBatchActivity({
     throw new Error("[Zendesk] Connector not found.");
   }
   const dataSourceConfig = dataSourceConfigFromConnector(connector);
+  const loggerArgs = {
+    workspaceId: dataSourceConfig.workspaceId,
+    connectorId,
+    provider: "zendesk",
+    workflowId: getZendeskGarbageCollectionWorkflowId(connectorId),
+    dataSourceId: dataSourceConfig.dataSourceId,
+  };
 
   /// deleting the articles in the data source
   const articleIds = await ZendeskArticleResource.fetchArticleIdsByBrandId({
@@ -309,6 +379,11 @@ export async function deleteArticleBatchActivity({
     brandId,
     batchSize: ZENDESK_BATCH_SIZE,
   });
+  logger.info(
+    { ...loggerArgs, brandId, articleCount: articleIds.length },
+    "[Zendesk] Deleting a batch of articles."
+  );
+
   await concurrentExecutor(
     articleIds,
     (articleId) =>
@@ -335,11 +410,28 @@ export async function deleteCategoryBatchActivity({
   connectorId: number;
   brandId: number;
 }): Promise<{ hasMore: boolean }> {
+  const connector = await ConnectorResource.fetchById(connectorId);
+  if (!connector) {
+    throw new Error("[Zendesk] Connector not found.");
+  }
+  const dataSourceConfig = dataSourceConfigFromConnector(connector);
+  const loggerArgs = {
+    workspaceId: dataSourceConfig.workspaceId,
+    connectorId,
+    provider: "zendesk",
+    workflowId: getZendeskGarbageCollectionWorkflowId(connectorId),
+    dataSourceId: dataSourceConfig.dataSourceId,
+  };
+
   const deletedCount = await ZendeskCategoryResource.deleteByBrandId({
     connectorId,
     brandId,
     batchSize: ZENDESK_BATCH_SIZE,
   });
+  logger.info(
+    { ...loggerArgs, brandId, deletedCount },
+    "[Zendesk] Deleting a batch of categories."
+  );
 
   return { hasMore: deletedCount === ZENDESK_BATCH_SIZE };
 }
diff --git a/connectors/src/resources/zendesk_resources.ts b/connectors/src/resources/zendesk_resources.ts
index 4329e737a1fe..8781b578e8e2 100644
--- a/connectors/src/resources/zendesk_resources.ts
+++ b/connectors/src/resources/zendesk_resources.ts
@@ -290,8 +290,8 @@ export class ZendeskBrandResource extends BaseResource<ZendeskBrand> {
   static async deleteBrandsWithNoPermission(
     connectorId: number,
     transaction?: Transaction
-  ) {
-    await ZendeskBrand.destroy({
+  ): Promise<number> {
+    return ZendeskBrand.destroy({
       where: {
         connectorId,
         helpCenterPermission: "none",