Mbonea commited on
Commit
f14d7e5
·
1 Parent(s): fdd2359

Back off SMS queue after gateway throttling

Browse files
src/jobs/expireTokens.job.js CHANGED
@@ -78,7 +78,11 @@ async function expireTokens() {
78
  if (token.customer_phone) {
79
  sms.sendSMS(
80
  token.customer_phone,
81
- messages.tokenExpired(token.device_name, token.plan_name)
 
 
 
 
82
  ).catch((err) => {
83
  console.error(`[expireTokens] Expiry SMS failed for ${token.code}:`, err.message);
84
  });
 
78
  if (token.customer_phone) {
79
  sms.sendSMS(
80
  token.customer_phone,
81
+ messages.tokenExpired(token.device_name, token.plan_name),
82
+ {
83
+ ttl: 6 * 60 * 60,
84
+ priority: sms.priorities.low,
85
+ }
86
  ).catch((err) => {
87
  console.error(`[expireTokens] Expiry SMS failed for ${token.code}:`, err.message);
88
  });
src/services/sms.js CHANGED
@@ -2,16 +2,17 @@ const axios = require('axios');
2
  const crypto = require('crypto');
3
  const db = require('../config/db');
4
 
5
- const SEND_INTERVAL_MS = Number(process.env.SMS_SEND_INTERVAL_MS || 1500);
6
- const MAX_ATTEMPTS = Number(process.env.SMS_MAX_ATTEMPTS || 3);
7
- const RATE_LIMIT_BACKOFF_MS = Number(process.env.SMS_RATE_LIMIT_BACKOFF_MS || 15000);
8
- const MAX_BACKOFF_MS = Number(process.env.SMS_MAX_BACKOFF_MS || 30000);
9
  const DEFAULT_TTL_SECONDS = 24 * 60 * 60;
10
  const DEFAULT_PRIORITY = 0;
11
  const HIGH_PRIORITY = 100;
12
 
13
  let sendQueue = Promise.resolve();
14
  let lastSendAt = 0;
 
15
 
16
  function normalizePhone(phone) {
17
  const d = phone.replace(/\D/g, '');
@@ -46,6 +47,9 @@ function retryAfterMs(err) {
46
  }
47
 
48
  async function waitForTurn() {
 
 
 
49
  const elapsed = Date.now() - lastSendAt;
50
  const waitMs = Math.max(0, SEND_INTERVAL_MS - elapsed);
51
  if (waitMs > 0) await delay(waitMs);
@@ -108,11 +112,15 @@ async function sendWithRetry(to, message, options) {
108
  const statusCode = err.response?.status;
109
  const isRateLimited = statusCode === 429;
110
  const canRetry = isRateLimited && attempt < MAX_ATTEMPTS;
 
 
 
 
 
 
111
 
112
  if (!canRetry) break;
113
 
114
- const gatewayWait = retryAfterMs(err);
115
- const backoffMs = Math.min(gatewayWait || RATE_LIMIT_BACKOFF_MS * attempt, MAX_BACKOFF_MS);
116
  console.warn(`[SMS] Rate limited for ${to}; retrying attempt ${attempt + 1}/${MAX_ATTEMPTS} in ${backoffMs}ms`);
117
  await delay(backoffMs);
118
  }
 
2
  const crypto = require('crypto');
3
  const db = require('../config/db');
4
 
5
+ const SEND_INTERVAL_MS = Number(process.env.SMS_SEND_INTERVAL_MS || 5000);
6
+ const MAX_ATTEMPTS = Number(process.env.SMS_MAX_ATTEMPTS || 4);
7
+ const RATE_LIMIT_BACKOFF_MS = Number(process.env.SMS_RATE_LIMIT_BACKOFF_MS || 60000);
8
+ const MAX_BACKOFF_MS = Number(process.env.SMS_MAX_BACKOFF_MS || 180000);
9
  const DEFAULT_TTL_SECONDS = 24 * 60 * 60;
10
  const DEFAULT_PRIORITY = 0;
11
  const HIGH_PRIORITY = 100;
12
 
13
  let sendQueue = Promise.resolve();
14
  let lastSendAt = 0;
15
+ let rateLimitUntil = 0;
16
 
17
  function normalizePhone(phone) {
18
  const d = phone.replace(/\D/g, '');
 
47
  }
48
 
49
  async function waitForTurn() {
50
+ const cooldownMs = Math.max(0, rateLimitUntil - Date.now());
51
+ if (cooldownMs > 0) await delay(cooldownMs);
52
+
53
  const elapsed = Date.now() - lastSendAt;
54
  const waitMs = Math.max(0, SEND_INTERVAL_MS - elapsed);
55
  if (waitMs > 0) await delay(waitMs);
 
112
  const statusCode = err.response?.status;
113
  const isRateLimited = statusCode === 429;
114
  const canRetry = isRateLimited && attempt < MAX_ATTEMPTS;
115
+ const gatewayWait = retryAfterMs(err);
116
+ const backoffMs = Math.min(gatewayWait || RATE_LIMIT_BACKOFF_MS * attempt, MAX_BACKOFF_MS);
117
+
118
+ if (isRateLimited) {
119
+ rateLimitUntil = Math.max(rateLimitUntil, Date.now() + backoffMs);
120
+ }
121
 
122
  if (!canRetry) break;
123
 
 
 
124
  console.warn(`[SMS] Rate limited for ${to}; retrying attempt ${attempt + 1}/${MAX_ATTEMPTS} in ${backoffMs}ms`);
125
  await delay(backoffMs);
126
  }