Skip to content

Commit 2be2b25

Browse files
authored
Merge pull request #6128 from scality/improvement/CLDSRV-855/update_helpers
CLDSRV-855: Update helpers
2 parents fb3cb1c + 185e209 commit 2be2b25

File tree

11 files changed

+715
-302
lines changed

11 files changed

+715
-302
lines changed

lib/Config.js

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1860,23 +1860,15 @@ class Config extends EventEmitter {
18601860
this.enableVeeamRoute = config.enableVeeamRoute;
18611861
}
18621862

1863-
this.rateLimiting = {
1864-
enabled: false,
1865-
bucket: {
1866-
configCacheTTL: constants.rateLimitDefaultConfigCacheTTL,
1867-
},
1868-
};
1863+
// Parse and validate all rate limiting configuration
1864+
this.rateLimiting = parseRateLimitConfig(config.rateLimiting);
18691865

1870-
if (config.rateLimiting?.enabled) {
1871-
// rate limiting uses the same localCache config defined for S3 to avoid
1872-
// config duplication.
1866+
// Rate limiting uses the same localCache config defined for S3 to avoid config duplication.
1867+
// If rate limiting is enabled check to make sure it is also configured.
1868+
if (this.rateLimiting.enabled) {
18731869
assert(this.localCache, 'localCache must be defined when rate limiting is enabled');
1874-
1875-
// Parse and validate all rate limiting configuration
1876-
this.rateLimiting = parseRateLimitConfig(config.rateLimiting);
18771870
}
18781871

1879-
18801872
if (config.capabilities) {
18811873
if (config.capabilities.locationTypes) {
18821874
this.supportedLocationTypes = new Set(config.capabilities.locationTypes);

lib/api/apiUtils/rateLimit/cache.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
const configCache = new Map();
2+
const bucketOwnerCache = new Map();
23

34
const namespace = {
45
bucket: 'bkt',
6+
account: 'acc',
57
};
68

79
function cacheSet(cache, key, value, ttl) {
@@ -54,13 +56,23 @@ const setCachedConfig = formatKeyDecorator(cacheSet.bind(null, configCache));
5456
const deleteCachedConfig = formatKeyDecorator(cacheDelete.bind(null, configCache));
5557
const expireCachedConfigs = cacheExpire.bind(null, configCache);
5658

59+
const getCachedBucketOwner = cacheGet.bind(null, bucketOwnerCache);
60+
const setCachedBucketOwner = cacheSet.bind(null, bucketOwnerCache);
61+
const deleteCachedBucketOwner = cacheDelete.bind(null, bucketOwnerCache);
62+
const expireCachedBucketOwners = cacheExpire.bind(null, bucketOwnerCache);
63+
5764
module.exports = {
5865
namespace,
5966
setCachedConfig,
6067
getCachedConfig,
6168
expireCachedConfigs,
6269
deleteCachedConfig,
70+
setCachedBucketOwner,
71+
getCachedBucketOwner,
72+
deleteCachedBucketOwner,
73+
expireCachedBucketOwners,
6374
// Do not access directly
6475
// Used only for tests
6576
configCache,
77+
bucketOwnerCache,
6678
};

lib/api/apiUtils/rateLimit/cleanup.js

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,34 @@
1-
const { expireCachedConfigs } = require('./cache');
1+
const { expireCachedConfigs, expireCachedBucketOwners } = require('./cache');
22
const { rateLimitCleanupInterval } = require('../../../../constants');
33

4-
let cleanupInterval = null;
4+
let cleanupTimer = null;
5+
6+
function cleanupJob(log, options = {}) {
7+
const expiredConfigs = expireCachedConfigs();
8+
const expiredBucketOwners = expireCachedBucketOwners();
9+
if (expiredConfigs > 0 || expiredBucketOwners > 0) {
10+
log.debug('Rate limit cleanup completed', { expiredConfigs, expiredBucketOwners });
11+
}
12+
13+
cleanupTimer = setTimeout(() => cleanupJob(log, options), rateLimitCleanupInterval);
14+
if (!options.skipUnref) {
15+
cleanupTimer.unref();
16+
}
17+
}
18+
519

620
/**
721
* Start periodic cleanup of expired rate limit counters and cached configs
822
*
923
* Runs every 10 seconds to:
1024
* - Remove expired GCRA counters (where emptyAt <= now)
1125
* - Remove expired cached rate limit configs (where TTL expired)
26+
* - Remove expired cached bucket owners (where TTL expired)
1227
*
1328
* This prevents memory leaks from accumulating expired entries.
1429
*/
1530
function startCleanupJob(log, options = {}) {
16-
if (cleanupInterval) {
31+
if (cleanupTimer) {
1732
log.warn('Rate limit cleanup job already running');
1833
return;
1934
}
@@ -22,18 +37,12 @@ function startCleanupJob(log, options = {}) {
2237
interval: rateLimitCleanupInterval,
2338
});
2439

25-
cleanupInterval = setInterval(() => {
26-
const now = Date.now();
27-
const expiredConfigs = expireCachedConfigs(now);
28-
if (expiredConfigs > 0) {
29-
log.debug('Rate limit cleanup completed', { expiredConfigs });
30-
}
31-
}, rateLimitCleanupInterval);
40+
cleanupTimer = setTimeout(() => cleanupJob(log, options), rateLimitCleanupInterval);
3241

3342
// Prevent cleanup job from keeping process alive
3443
// Skip unref() in test environment to work with sinon fake timers
3544
if (!options.skipUnref) {
36-
cleanupInterval.unref();
45+
cleanupTimer.unref();
3746
}
3847
}
3948

@@ -42,9 +51,9 @@ function startCleanupJob(log, options = {}) {
4251
* Used for graceful shutdown or testing
4352
*/
4453
function stopCleanupJob(log) {
45-
if (cleanupInterval) {
46-
clearInterval(cleanupInterval);
47-
cleanupInterval = null;
54+
if (cleanupTimer !== null) {
55+
clearTimeout(cleanupTimer);
56+
cleanupTimer = null;
4857
if (log) {
4958
log.info('Stopped rate limit cleanup job');
5059
}

lib/api/apiUtils/rateLimit/config.js

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ const Joi = require('@hapi/joi');
22
const { errors, ArsenalError } = require('arsenal');
33

44
const { rateLimitDefaultConfigCacheTTL, rateLimitDefaultBurstCapacity } = require('../../../../constants');
5-
const { calculateInterval } = require('./gcra');
65

76
/**
87
* Full Rate Limiting Configuration Example
@@ -191,6 +190,24 @@ const rateLimitConfigSchema = Joi.object({
191190
code: errors.SlowDown.message,
192191
message: errors.SlowDown.description,
193192
}),
193+
}).default({
194+
enabled: false,
195+
nodes: 1,
196+
tokenBucketBufferSize: 50,
197+
tokenBucketRefillThreshold: 20,
198+
bucket: {
199+
configCacheTTL: rateLimitDefaultConfigCacheTTL,
200+
defaultBurstCapacity: rateLimitDefaultBurstCapacity,
201+
},
202+
account: {
203+
configCacheTTL: rateLimitDefaultConfigCacheTTL,
204+
defaultBurstCapacity: rateLimitDefaultBurstCapacity,
205+
},
206+
error: {
207+
statusCode: 503,
208+
code: errors.SlowDown.message,
209+
message: errors.SlowDown.description,
210+
},
194211
});
195212

196213
/**
@@ -203,10 +220,10 @@ const rateLimitConfigSchema = Joi.object({
203220
* @returns {RateLimitClassConfig} Transformed rate limit config
204221
*/
205222
function transformClassConfig(resourceClass, validatedCfg, nodes) {
206-
const transformed = {
207-
defaultConfig: undefined,
208-
configCacheTTL: validatedCfg.configCacheTTL,
209-
defaultBurstCapacity: validatedCfg.defaultBurstCapacity,
223+
const defaultConfig = {
224+
RequestsPerSecond: {
225+
BurstCapacity: validatedCfg.defaultBurstCapacity,
226+
},
210227
};
211228

212229
if (validatedCfg.defaultConfig?.requestsPerSecond) {
@@ -223,23 +240,18 @@ function transformClassConfig(resourceClass, validatedCfg, nodes) {
223240
);
224241
}
225242

226-
// Use provided burstCapacity or fall back to default
227-
const effectiveBurstCapacity = burstCapacity || transformed.defaultBurstCapacity;
228-
229-
// Calculate per-node interval using distributed architecture
230-
const interval = calculateInterval(limit, nodes);
231-
232243
// Store both the original limit and the calculated values
233-
transformed.defaultConfig = {
234-
limit,
235-
requestsPerSecond: {
236-
interval,
237-
bucketSize: effectiveBurstCapacity * 1000,
238-
},
244+
defaultConfig.RequestsPerSecond = {
245+
Limit: limit,
246+
BurstCapacity: burstCapacity || validatedCfg.defaultBurstCapacity,
239247
};
240248
}
241249

242-
return transformed;
250+
return {
251+
defaultConfig,
252+
configCacheTTL: validatedCfg.configCacheTTL,
253+
defaultBurstCapacity: validatedCfg.defaultBurstCapacity,
254+
};
243255
}
244256

245257
/**

0 commit comments

Comments
 (0)