Skip to content

Commit e027c0d

Browse files
authored
add reacher throttle requests (#2014)
1 parent e9dd49f commit e027c0d

File tree

8 files changed

+597
-16
lines changed

8 files changed

+597
-16
lines changed

.env.master.dev

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ LOAD_BALANCE_VERIFIERS = false # true to load balance between multiple email ver
7272

7373
# Reacher: https://help.reacher.email/
7474
REACHER_HOST = https://stoplight.io/mocks/reacher/backend/68673 # ( REQUIRED )
75-
# REACHER_API_KEY =
75+
REACHER_API_KEY = 'test-key'
7676
# REACHER_HEADER_SECRET =
7777
# REACHER_SMTP_FROM =
7878
# REACHER_SMTP_HELLO =
@@ -87,7 +87,8 @@ REACHER_HOTMAIL_USE_HEADLESS =true
8787
# REACHER_MICROSOFT365_USE_API =
8888
REACHER_GMAIL_USE_API =true
8989
# REACHER_YAHOO_USE_API =
90-
90+
REACHER_RATE_LIMITER_REQUESTS = 60
91+
REACHER_RATE_LIMITER_INTERVAL = 60 * 1000
9192
# Mailercheck: https://developers.mailercheck.com/
9293
# MAILERCHECK_API_KEY =
9394
# Zerobounce: https://www.zerobounce.net/docs/email-validation-api-quickstart/

.env.master.prod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ REACHER_HOTMAIL_USE_HEADLESS = true
8787
# REACHER_MICROSOFT365_USE_API =
8888
REACHER_GMAIL_USE_API = true
8989
# REACHER_YAHOO_USE_API =
90+
REACHER_RATE_LIMITER_REQUESTS = 60
91+
REACHER_RATE_LIMITER_INTERVAL = 60 * 1000
9092

9193
# Mailercheck: https://developers.mailercheck.com/
9294
MAILERCHECK_API_KEY =

backend/src/config/schema.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ const schema = z.object({
8181
REACHER_MICROSOFT365_USE_API: boolean().optional().default('true'),
8282
REACHER_GMAIL_USE_API: boolean().optional().default('false'),
8383
REACHER_YAHOO_USE_API: boolean().optional().default('false'),
84+
REACHER_RATE_LIMITER_REQUESTS: number(),
85+
REACHER_RATE_LIMITER_INTERVAL: number(),
8486

8587
/* MAILERCHECK */
8688
MAILERCHECK_API_KEY: z.string().min(1).optional(),

backend/src/services/email-status/EmailStatusVerifierFactory.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ interface ReacherConfig {
2828
REACHER_MICROSOFT365_USE_API: boolean;
2929
REACHER_GMAIL_USE_API: boolean;
3030
REACHER_YAHOO_USE_API: boolean;
31+
REACHER_RATE_LIMITER_REQUESTS: number;
32+
REACHER_RATE_LIMITER_INTERVAL: number;
3133
}
3234

3335
interface MailerCheckConfig {
@@ -210,6 +212,11 @@ export default class EmailStatusVerifierFactory {
210212
password: config.REACHER_PROXY_PASSWORD
211213
}
212214
: undefined
215+
},
216+
rateLimiter: {
217+
requests: config.REACHER_RATE_LIMITER_REQUESTS,
218+
interval: config.REACHER_RATE_LIMITER_INTERVAL,
219+
spaced: false
213220
}
214221
});
215222

backend/src/services/email-status/reacher/client.ts

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import axios, { AxiosInstance } from 'axios';
22
import { Logger } from 'winston';
3+
import throttledQueue from 'throttled-queue';
34
import { logError } from '../../../utils/axios';
45

56
interface BulkSubmitResponse {
@@ -67,6 +68,12 @@ interface BulkVerificationResultsResponse {
6768
results: EmailCheckOutput[];
6869
}
6970

71+
interface RateLimiterOptions {
72+
requests: number;
73+
interval: number;
74+
spaced: boolean;
75+
}
76+
7077
interface ReacherConfig {
7178
host?: string;
7279
timeoutMs?: number;
@@ -79,6 +86,7 @@ interface ReacherConfig {
7986
gmailUseApi?: boolean;
8087
yahooUseApi?: boolean;
8188
hotmailUseHeadless?: string;
89+
rateLimiter: RateLimiterOptions;
8290
}
8391

8492
interface SMTPConfig {
@@ -97,12 +105,14 @@ interface ValidationOptions {
97105
}
98106

99107
export default class ReacherClient {
100-
private static readonly SINGLE_VERIFICATION_PATH = '/v1/check_email';
108+
static readonly SINGLE_VERIFICATION_PATH = '/v1/check_email';
101109

102-
private static readonly BULK_VERIFICATION_PATH = '/v0/bulk';
110+
static readonly BULK_VERIFICATION_PATH = '/v0/bulk';
103111

104112
private readonly api: AxiosInstance;
105113

114+
private readonly rate_limit_handler;
115+
106116
private readonly smtpConfig: {
107117
from_email?: string;
108118
hello_name?: string;
@@ -133,6 +143,12 @@ export default class ReacherClient {
133143
this.api = axios.create({
134144
baseURL: config.host
135145
});
146+
this.rate_limit_handler = throttledQueue(
147+
config.rateLimiter.requests,
148+
config.rateLimiter.interval,
149+
config.rateLimiter.spaced
150+
);
151+
136152
if (config.timeoutMs) {
137153
this.api.defaults.timeout = config.timeoutMs;
138154
}
@@ -190,17 +206,19 @@ export default class ReacherClient {
190206
validationOptions?: ValidationOptions
191207
): Promise<EmailCheckOutput> {
192208
try {
193-
const { data } = await this.api.post<EmailCheckOutput>(
194-
ReacherClient.SINGLE_VERIFICATION_PATH,
195-
{
196-
to_email: email,
197-
...this.additionalSettings,
198-
...this.smtpConfig,
199-
from_email: validationOptions
200-
? validationOptions.fromEmail
201-
: this.smtpConfig.from_email
202-
},
203-
{ signal: abortSignal }
209+
const { data } = await this.rate_limit_handler(() =>
210+
this.api.post<EmailCheckOutput>(
211+
ReacherClient.SINGLE_VERIFICATION_PATH,
212+
{
213+
to_email: email,
214+
...this.additionalSettings,
215+
...this.smtpConfig,
216+
from_email: validationOptions
217+
? validationOptions.fromEmail
218+
: this.smtpConfig.from_email
219+
},
220+
{ signal: abortSignal }
221+
)
204222
);
205223
return { ...data, input: email };
206224
} catch (error) {

backend/test/unit/email-status/EmailStatusVerifierFactory.test.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ const reacherDefaultConfig = {
1616
REACHER_MICROSOFT365_USE_API: true,
1717
REACHER_GMAIL_USE_API: true,
1818
REACHER_YAHOO_USE_API: true,
19-
REACHER_REQUEST_TIMEOUT_MS: 5
19+
REACHER_REQUEST_TIMEOUT_MS: 5,
20+
REACHER_RATE_LIMITER_REQUESTS: 5,
21+
REACHER_RATE_LIMITER_INTERVAL: 1000
2022
};
2123

2224
const outlookEmails = [

0 commit comments

Comments
 (0)