Skip to content

Commit

Permalink
feat(workers): improve error management
Browse files Browse the repository at this point in the history
  • Loading branch information
PLhery committed Jun 26, 2023
1 parent 9c8a626 commit 7000c71
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 180 deletions.
60 changes: 15 additions & 45 deletions unfollow-ninja-server/src/tasks/notifyUser.ts
Expand Up @@ -6,7 +6,6 @@ import logger from '../utils/logger';
import { IUnfollowerInfo, Lang } from '../utils/types';
import Task from './task';
import metrics from '../utils/metrics';
import { NotificationEvent } from '../dao/userEventDao';
import { SUPPORTED_LANGUAGES } from '../utils/utils';
import { ApiResponseError, UsersV2Result } from 'twitter-api-v2';
import { sendRevokedEmailToUserId } from '../utils/emailSender';
Expand Down Expand Up @@ -319,50 +318,21 @@ export default class extends Task {

const userDao = this.dao.getUserDao(userId);

for (const { code, message } of [err]) {
switch (code) {
case 17: // no user matches the specified terms (users/lookup)
case 50: // user not found (friendship/show)
break;
// app-related
case 32:
throw new Error(
'Authentication problems.' + 'Please check that your consumer key & secret are correct.'
);
case 416:
throw new Error('Oops, it looks like the application has been suspended :/...');
// user-related
case 89:
case 401: // since V2? but not clear message
logger.warn('@%s revoked the token. removing them from the list...', username);
await userDao.setCategory(UserCategory.revoked);
await sendRevokedEmailToUserId(userId);
return true;
case 326:
case 64:
case 403: // since V2? but not clear message
logger.warn('@%s is suspended. removing them from the list...', username);
await userDao.setCategory(UserCategory.suspended);
return true;
case 150: // dm closed to non-followers
case 349: // user blocked?
logger.warn('@%s does not accept DMs. removing them from the list...', username);
await userDao.setCategory(UserCategory.dmclosed);
return true;
case 292:
throw new Error('Notification blocked because "it seems automated".');
// twitter errors
case 130: // over capacity
case 131: // internal error`
throw new Error('Twitter has problems at the moment, skipping this action.');
case 88: // rate limit
throw new Error('the user reached its rate-limit (notifyUser)');
default:
throw new Error(
`An unexpected twitter error occured: ${code} ${message} ${err.data.title} ${err.data.detail}`
);
}
switch (err?.data?.detail) {
case 'Unauthorized': // since V2? but not clear message
logger.warn('@%s revoked the token. Removing them from the list...', await userDao.getUsername());
await userDao.setCategory(UserCategory.revoked);
await sendRevokedEmailToUserId(userId);
return true;
case 'Forbidden': // since V2? but not clear message
logger.warn('@%s is suspended. Removing them from the list...', await userDao.getUsername());
await userDao.setCategory(UserCategory.suspended);
return true;
default:
throw new Error(
`[checkFollowers] An unexpected twitter error occured: ${err?.code} ${err?.message} ${err?.data?.title} ${err?.data?.detail}`
);
}
return false;
// return false;
}
}
67 changes: 19 additions & 48 deletions unfollow-ninja-server/src/tasks/sendDailyDM.ts
Expand Up @@ -10,6 +10,8 @@ import { NotificationEvent } from '../dao/userEventDao';
import { SUPPORTED_LANGUAGES } from '../utils/utils';
import { ApiResponseError } from 'twitter-api-v2';
import * as Sentry from '@sentry/node';
import UserDao from '../dao/userDao';
import { sendRevokedEmailToUserId } from '../utils/emailSender';

i18n.configure({
locales: SUPPORTED_LANGUAGES,
Expand Down Expand Up @@ -201,59 +203,28 @@ export default class extends Task {

// throw an error if it's a twitter problem
// return true if we can't continue to process the user
private async manageTwitterErrors(err: unknown, username: string, userId: string): Promise<boolean> {
private async manageTwitterErrors(err: unknown, username: string, userId: string): Promise<void> {
if (!(err instanceof ApiResponseError)) {
throw err;
}

// const userDao = this.dao.getUserDao(userId);
let error;
for (const { code, message } of [err]) {
switch (code) {
/* case 17: // no user matches the specified terms (users/lookup)
case 50: // user not found (friendship/show)
break;
// app-related
case 32:
throw new Error(
'Authentication problems.' + 'Please check that your consumer key & secret are correct.'
);
case 416:
throw new Error('Oops, it looks like the application has been suspended :/...');
// user-related
case 89:
case 401: // since V2? but not clear message
logger.warn('@%s revoked the token. removing them from the list...', username);
await userDao.setCategory(UserCategory.revoked);
await sendRevokedEmailToUserId(userId);
return true;
case 326:
case 64:
case 403: // since V2? but not clear message
logger.warn('@%s is suspended. removing them from the list...', username);
await userDao.setCategory(UserCategory.suspended);
return true;
case 150: // dm closed to non-followers
case 349: // user blocked?
logger.warn('@%s does not accept DMs. removing them from the list...', username);
await userDao.setCategory(UserCategory.dmclosed);
return true;
case 292:
throw new Error('Notification blocked because "it seems automated".');
// twitter errors
case 130: // over capacity
case 131: // internal error`
throw new Error('Twitter has problems at the moment, skipping this action.');
case 88: // rate limit
throw new Error('the user reached its rate-limit (notifyUser)');*/
default:
error = new Error(
`An unexpected twitter error occured: @${username}/${userId} - ${code} ${message} ${err.data.title} ${err.data.detail}`
);
logger.error(error);
Sentry.captureException(error);
}
switch (err?.data?.detail) {
/*case 'Unauthorized': // since V2? but not clear message
logger.warn('@%s revoked the token. Removing them from the list...', await userDao.getUsername());
await userDao.setCategory(UserCategory.revoked);
await sendRevokedEmailToUserId(userId);
break;
case 'Forbidden': // since V2? but not clear message
logger.warn('@%s is suspended. Removing them from the list...', await userDao.getUsername());
await userDao.setCategory(UserCategory.suspended);
break;*/
default:
error = new Error(
`[checkFollowers] An unexpected twitter error occured @${username}/${userId}: ${err?.code} ${err?.message} ${err?.data?.title} ${err?.data?.detail}`
);
logger.error(error);
Sentry.captureException(error);
}
return false;
}
}
65 changes: 16 additions & 49 deletions unfollow-ninja-server/src/tasks/sendWelcomeMessage.ts
Expand Up @@ -7,6 +7,7 @@ import { NotificationEvent } from '../dao/userEventDao';
import { SUPPORTED_LANGUAGES } from '../utils/utils';
import { ApiResponseError } from 'twitter-api-v2';
import { sendRevokedEmailToUserId } from '../utils/emailSender';
import UserDao from '../dao/userDao';

i18n.configure({
locales: SUPPORTED_LANGUAGES,
Expand Down Expand Up @@ -56,55 +57,21 @@ export default class extends Task {
.catch((err) => this.manageTwitterErrors(err, username, userId)); */
}

private async manageTwitterErrors(err: unknown, username: string, userId: string): Promise<void> {
if (!(err instanceof ApiResponseError)) {
throw err;
}

const userDao = this.dao.getUserDao(userId);

for (const { code, message } of [err]) {
switch (code) {
// app-related
case 32:
throw new Error(
'Authentication problems.' + 'Please check that your consumer key & secret are correct.'
);
case 416:
throw new Error('Oops, it looks like the application has been suspended :/...');
// user-related
case 89:
case 401: // since V2? but not clear message
logger.warn('@%s revoked the token. removing them from the list...', username);
await userDao.setCategory(UserCategory.revoked);
await sendRevokedEmailToUserId(userId);
break;
case 326:
case 64:
case 403: // since V2? but not clear message
logger.warn('@%s is suspended. removing them from the list...', username);
await userDao.setCategory(UserCategory.suspended);
break;
// twitter errors
case 130: // over capacity
case 131: // internal error`
case 88: // rate limit
// retry in 15 minutes
await this.queue.add(
'sendWelcomeMessage',
{
id: Date.now(), // otherwise some seem stuck??
userId,
username,
},
{ delay: 15 * 60 * 1000 }
);
break;
default:
throw new Error(
`An unexpected twitter error occured: ${code} ${message} ${err.data.title} ${err.data.detail}`
);
}
private async manageTwitterErrors(err: ApiResponseError, userDao: UserDao, userId: string): Promise<void> {
switch (err?.data?.detail) {
case 'Unauthorized': // since V2? but not clear message
logger.warn('@%s revoked the token. Removing them from the list...', await userDao.getUsername());
await userDao.setCategory(UserCategory.revoked);
await sendRevokedEmailToUserId(userId);
break;
case 'Forbidden': // since V2? but not clear message
logger.warn('@%s is suspended. Removing them from the list...', await userDao.getUsername());
await userDao.setCategory(UserCategory.suspended);
break;
default:
throw new Error(
`[checkFollowers] An unexpected twitter error occured: ${err?.code} ${err?.message} ${err?.data?.title} ${err?.data?.detail}`
);
}
}
}
52 changes: 14 additions & 38 deletions unfollow-ninja-server/src/workers/checkAllFollowers.ts
Expand Up @@ -286,43 +286,19 @@ async function detectUnfollows(userId: string, followers: string[], formerFollow

// Manage or rethrow twitter errors
async function manageTwitterErrors(err: ApiResponseError, userDao: UserDao, userId: string): Promise<void> {
for (const { code, message } of [err]) {
switch (code) {
// app-related
case 32:
throw new Error(`[checkFollowers] Authentication problems. Please check that your consumer key.`);
case 416:
throw new Error(`[checkFollowers] Oops, it looks like the application has been suspended :/...`);
// user-related
case 89:
case 401: // since V2? but not clear message
logger.warn('@%s revoked the token. Removing them from the list...', await userDao.getUsername());
await userDao.setCategory(UserCategory.revoked);
await sendRevokedEmailToUserId(userId);
break;
case 326:
case 64:
case 403: // since V2? but not clear message
logger.warn('@%s is suspended. Removing them from the list...', await userDao.getUsername());
await userDao.setCategory(UserCategory.suspended);
break;
case 34: // 404 - the user closed his account?
logger.warn(
"@%s this account doesn't exist. Removing them from the list...",
await userDao.getUsername()
);
await userDao.setCategory(UserCategory.accountClosed);
break;
// twitter errors
case 130: // over capacity
case 131: // internal error
throw new Error(`[checkFollowers] internal Twitter error`);
case 88: // rate limit
throw new Error(`[checkFollowers] the user reached its rate-limit.`);
default:
throw new Error(
`[checkFollowers] An unexpected twitter error occured: ${code} ${message} ${err.data.title} ${err.data.detail}`
);
}
switch (err?.data?.detail) {
case 'Unauthorized': // since V2? but not clear message
logger.warn('@%s revoked the token. Removing them from the list...', await userDao.getUsername());
await userDao.setCategory(UserCategory.revoked);
await sendRevokedEmailToUserId(userId);
break;
case 'Forbidden': // since V2? but not clear message
logger.warn('@%s is suspended. Removing them from the list...', await userDao.getUsername());
await userDao.setCategory(UserCategory.suspended);
break;
default:
throw new Error(
`[checkFollowers] An unexpected twitter error occured: ${err?.code} ${err?.message} ${err?.data?.title} ${err?.data?.detail}`
);
}
}

0 comments on commit 7000c71

Please sign in to comment.