From c010665ea9590dfc363f30937b3cedbb11e9a03b Mon Sep 17 00:00:00 2001 From: Dave Date: Thu, 18 Dec 2025 18:26:02 -0500 Subject: [PATCH] feature/IO-3402-Import-Add-Notifiers - Fix --- hasura/metadata/tables.yaml | 3 +++ server/graphql-client/queries.js | 9 ++++++++ server/notifications/autoAddWatchers.js | 29 +++++++++++++------------ 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/hasura/metadata/tables.yaml b/hasura/metadata/tables.yaml index 77084c96c..9900fa00b 100644 --- a/hasura/metadata/tables.yaml +++ b/hasura/metadata/tables.yaml @@ -1156,8 +1156,11 @@ enable_manual: false update: columns: + - imexshopid + - timezone - shopname - notification_followers + - state - md_order_statuses retry_conf: interval_sec: 10 diff --git a/server/graphql-client/queries.js b/server/graphql-client/queries.js index e3b3b0977..b51c73c49 100644 --- a/server/graphql-client/queries.js +++ b/server/graphql-client/queries.js @@ -2926,6 +2926,15 @@ exports.GET_BODYSHOP_BY_ID = ` } `; +exports.GET_BODYSHOP_WATCHERS_BY_ID = ` + query GET_BODYSHOP_BY_ID($id: uuid!) { + bodyshops_by_pk(id: $id) { + id + notification_followers + } + } +`; + exports.GET_DOCUMENTS_BY_JOB = ` query GET_DOCUMENTS_BY_JOB($jobId: uuid!) { jobs_by_pk(id: $jobId) { diff --git a/server/notifications/autoAddWatchers.js b/server/notifications/autoAddWatchers.js index 704ca2550..803c44984 100644 --- a/server/notifications/autoAddWatchers.js +++ b/server/notifications/autoAddWatchers.js @@ -4,11 +4,14 @@ * This module handles automatically adding watchers to new jobs based on the notifications_autoadd * boolean field in the associations table and the notification_followers JSON field in the bodyshops table. * It ensures users are not added twice and logs the process. + * + * NOTE: Bodyshop notification_followers is fetched directly from the DB (Hasura) to avoid stale Redis cache. */ const { client: gqlClient } = require("../graphql-client/graphql-client"); const { isEmpty } = require("lodash"); const { + GET_BODYSHOP_WATCHERS_BY_ID, GET_JOB_WATCHERS_MINIMAL, GET_NOTIFICATION_WATCHERS, INSERT_JOB_WATCHERS @@ -26,10 +29,7 @@ const FILTER_SELF_FROM_WATCHERS = process.env?.FILTER_SELF_FROM_WATCHERS !== "fa */ const autoAddWatchers = async (req) => { const { event, trigger } = req.body; - const { - logger, - sessionUtils: { getBodyshopFromRedis } - } = req; + const { logger } = req; // Validate that this is an INSERT event, bail if (trigger?.name !== "notifications_jobs_autoadd" || event.op !== "INSERT" || event.data.old) { @@ -48,20 +48,20 @@ const autoAddWatchers = async (req) => { const hasuraUserId = event?.session_variables?.["x-hasura-user-id"]; try { - // Fetch bodyshop data from Redis - const bodyshopData = await getBodyshopFromRedis(shopId); - let notificationFollowers = bodyshopData?.notification_followers; + // Fetch bodyshop data directly from DB (avoid Redis staleness) + const bodyshopResponse = await gqlClient.request(GET_BODYSHOP_WATCHERS_BY_ID, { id: shopId }); + const bodyshopData = bodyshopResponse?.bodyshops_by_pk; - // Bail if notification_followers is missing or not an array - if (!notificationFollowers || !Array.isArray(notificationFollowers)) { - return; - } + const notificationFollowersRaw = bodyshopData?.notification_followers; + const notificationFollowers = Array.isArray(notificationFollowersRaw) + ? [...new Set(notificationFollowersRaw.filter((id) => id))] // de-dupe + remove falsy + : []; // Execute queries in parallel const [notificationData, existingWatchersData] = await Promise.all([ gqlClient.request(GET_NOTIFICATION_WATCHERS, { shopId, - employeeIds: notificationFollowers.filter((id) => id) + employeeIds: notificationFollowers }), gqlClient.request(GET_JOB_WATCHERS_MINIMAL, { jobid: jobId }) ]); @@ -73,7 +73,7 @@ const autoAddWatchers = async (req) => { associationId: assoc.id })) || []; - // Get users from notification_followers + // Get users from notification_followers (employee IDs -> employee emails) const followerEmails = notificationData?.employees ?.filter((e) => e.user_email) @@ -84,7 +84,7 @@ const autoAddWatchers = async (req) => { // Combine and deduplicate emails (use email as the unique key) const usersToAdd = [...autoAddUsers, ...followerEmails].reduce((acc, user) => { - if (!acc.some((u) => u.email === user.email)) { + if (user?.email && !acc.some((u) => u.email === user.email)) { acc.push(user); } return acc; @@ -123,6 +123,7 @@ const autoAddWatchers = async (req) => { message: error?.message, stack: error?.stack, jobId, + shopId, roNumber }); throw error; // Re-throw to ensure the error is logged in the handler