Added request throttling to stay under the Stripe Search API rate limits (#17393)
refs https://github.com/TryGhost/Product/issues/3593 - also uses `.current_period_end` instead of `.created_at` to retrieve the most recent subscription, when multiple customer with the same email address are found. Reason: `created_at` date is reset when migrating subscriptions between Stripe accounts
This commit is contained in:
parent
1de6120b55
commit
daa19e06b4
@ -2,7 +2,13 @@ const {VersionMismatchError} = require('@tryghost/errors');
|
||||
const debug = require('@tryghost/debug')('stripe');
|
||||
const Stripe = require('stripe').Stripe;
|
||||
const LeakyBucket = require('leaky-bucket');
|
||||
|
||||
/* Stripe has the following rate limits:
|
||||
* - For most APIs, 100 read requests per second in live mode, 25 read requests per second in test mode
|
||||
* - For search, 20 requests per second in both live and test modes
|
||||
*/
|
||||
const EXPECTED_API_EFFICIENCY = 0.95;
|
||||
const EXPECTED_SEARCH_API_EFFICIENCY = 0.15;
|
||||
|
||||
const STRIPE_API_VERSION = '2020-08-27';
|
||||
|
||||
@ -70,6 +76,7 @@ module.exports = class StripeAPI {
|
||||
} else {
|
||||
this._rateLimitBucket = new LeakyBucket(EXPECTED_API_EFFICIENCY * 100, 1);
|
||||
}
|
||||
this._searchRateLimitBucket = new LeakyBucket(EXPECTED_SEARCH_API_EFFICIENCY * 100, 1);
|
||||
this._configured = true;
|
||||
}
|
||||
|
||||
@ -230,6 +237,7 @@ module.exports = class StripeAPI {
|
||||
* @returns {Promise<string|null>} Stripe Customer ID, if found
|
||||
*/
|
||||
async getCustomerIdByEmail(email) {
|
||||
await this._searchRateLimitBucket.throttle();
|
||||
try {
|
||||
const result = await this._stripe.customers.search({
|
||||
query: `email:"${email}"`,
|
||||
@ -261,8 +269,8 @@ module.exports = class StripeAPI {
|
||||
|
||||
// find the customer with the most recent subscription
|
||||
for (let subscription of customer.subscriptions.data) {
|
||||
if (subscription.created > latestSubscriptionTime) {
|
||||
latestSubscriptionTime = subscription.created;
|
||||
if (subscription.current_period_end && subscription.current_period_end > latestSubscriptionTime) {
|
||||
latestSubscriptionTime = subscription.current_period_end;
|
||||
latestCustomer = customer;
|
||||
}
|
||||
}
|
||||
@ -420,7 +428,7 @@ module.exports = class StripeAPI {
|
||||
const metadata = options.metadata || undefined;
|
||||
const customerId = customer ? customer.id : undefined;
|
||||
const customerEmail = customer ? customer.email : options.customerEmail;
|
||||
|
||||
|
||||
await this._rateLimitBucket.throttle();
|
||||
let discounts;
|
||||
if (options.coupon) {
|
||||
|
@ -209,8 +209,8 @@ describe('StripeAPI', function () {
|
||||
id: 'recent_customer_id',
|
||||
subscriptions: {
|
||||
data: [
|
||||
{created: 1000},
|
||||
{created: 9000}
|
||||
{current_period_end: 1000},
|
||||
{current_period_end: 9000}
|
||||
]
|
||||
}
|
||||
},
|
||||
@ -224,7 +224,7 @@ describe('StripeAPI', function () {
|
||||
id: 'old_customer_id',
|
||||
subscriptions: {
|
||||
data: [
|
||||
{created: 5000}
|
||||
{current_period_end: 5000}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user