Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 18 additions & 11 deletions src/common/mailchimp.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,18 +50,25 @@ async function deleteSubscriber (email) {
throw err
}

for (const list of lists) {
try {
await axios.post(`${baseUrl}/lists/${list.id}/members/${subscriberHash}/actions/delete-permanent`, null, { headers })
} catch (err) {
// A 404 means the subscriber was not present in that list, which is fine
if (err.response && err.response.status === 404) {
logger.info(`MailChimp subscriber not found in list ${list.id}`)
} else {
logger.error(`Failed to delete MailChimp subscriber from list ${list.id}: ${err.message}`)
throw err
const deletionResults = await Promise.allSettled(
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[⚠️ correctness]
Using Promise.allSettled is a good choice for handling multiple promises where you want to continue processing even if some fail. However, be cautious about the potential for unhandled promise rejections if any of the axios.post calls throw an error that is not a 404. Consider logging all errors within the catch block to ensure no silent failures.

lists.map(async (list) => {
try {
await axios.post(`${baseUrl}/lists/${list.id}/members/${subscriberHash}/actions/delete-permanent`, null, { headers })
} catch (err) {
// A 404 means the subscriber was not present in that list, which is fine
if (err.response && err.response.status === 404) {
logger.info(`MailChimp subscriber not found in list ${list.id}`)
} else {
logger.error(`Failed to delete MailChimp subscriber from list ${list.id}: ${err.message}`)
throw err
}
}
}
})
)

const failedDeletion = deletionResults.find((result) => result.status === 'rejected')
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[⚠️ maintainability]
The current implementation only throws the first error encountered in failedDeletion. If multiple deletions fail, you might miss other errors. Consider logging all errors or aggregating them to provide a complete picture of what went wrong.

if (failedDeletion) {
throw failedDeletion.reason
}
}

Expand Down
13 changes: 8 additions & 5 deletions src/services/MemberService.js
Original file line number Diff line number Diff line change
Expand Up @@ -657,11 +657,14 @@ async function deleteMember (currentUser, handle, data) {
await skillsPrisma.userSkill.deleteMany({ where: { userId: identityUserId } })
await updateIdentityRecords(identityUserId, deletedHandle, deletedEmail, now)

try {
await mailchimp.deleteSubscriber(member.email)
} catch (err) {
logger.error(`MailChimp deletion failed for ${member.email}: ${err.message}`)
}
// Kick off MailChimp deletion without blocking the API response.
;(async () => {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[⚠️ readability]
The use of an immediately invoked function expression (IIFE) to perform an asynchronous operation is unconventional and may lead to confusion. Consider using a named async function or a promise-based approach to improve readability and maintainability.

try {
await mailchimp.deleteSubscriber(member.email)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[❗❗ correctness]
The member.email variable is used within the asynchronous function, which may lead to unexpected behavior if member is modified elsewhere before the function executes. Consider capturing member.email in a local variable before the IIFE to ensure the correct value is used.

} catch (err) {
logger.error(`MailChimp deletion failed for ${member.email}: ${err.message}`)
}
})()

prismaHelper.convertMember(updatedMember)
await helper.postBusEvent(constants.TOPICS.MemberUpdated, updatedMember)
Expand Down
Loading