Skip to content

Commit

Permalink
fix:allow to only override elevated limits but merging with original …
Browse files Browse the repository at this point in the history
…config (#71)
  • Loading branch information
pubalokta authored May 31, 2024
1 parent b2cd2dc commit 0aa08e1
Show file tree
Hide file tree
Showing 3 changed files with 146 additions and 44 deletions.
39 changes: 39 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,45 @@ overrides: {
}
```

We can also override the elevated_limits configuration:
```js
buckets = {
ip: {
size: 10,
per_second: 5,
overrides: {
'awesome-key': {
elevated_limits: {
size: 200,
per_second: 200,
}
}
}
}
}
```

If elevated_limits is provided within the override and no size, per_interval, or unlimited is overridden, limitd-redis
will copy them from the base bucket configuration. Thus, the configuration above after being processed will look like:
```js
buckets = {
ip: {
size: 10,
per_second: 5,
overrides: {
'awesome-key': {
size: 10,
per_second: 5,
elevated_limits: {
size: 200,
per_second: 200,
}
}
}
}
}
```

## ERL (Elevated Rate Limits)
### Prerequisites
Redis 6.2+ is required to use ERL.
Expand Down
27 changes: 23 additions & 4 deletions lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,7 @@ function normalizeType(params) {
override.match = new RegExp(overrideDef.match, 'i');
}

// If the override doesn't provide elevated_limits use the ones defined in the upper level (if any)
if (!override.elevated_limits && type.elevated_limits) {
override.elevated_limits = type.elevated_limits;
}
Object.assign(override, normalizeElevatedOverrides(type, override));

if (!override.until || override.until >= new Date()) {
if (override.match) {
Expand All @@ -100,6 +97,28 @@ function normalizeType(params) {
return type;
}

function normalizeElevatedOverrides(type, override) {
// If the override doesn't provide elevated_limits use the ones defined in the base type (if any)
const normalizedOverride = {}
if (!override.elevated_limits) {
Object.assign(normalizedOverride, override, { elevated_limits: type.elevated_limits })
return normalizedOverride;
}

// If size, per_interval, and unlimited are undefined for the override, and it contains elevated_limits,
// copy the size, per_interval, and unlimited from the base type configuration.
if (typeof override.unlimited === 'undefined'
&& typeof override.size === 'undefined'
&& typeof override.per_interval === 'undefined') {
Object.assign(normalizedOverride,
override,
_.omit(type, 'overrides', 'overridesMatch'),
{elevated_limits: override.elevated_limits}
);
}
return normalizedOverride;
}

/**
* Load the buckets configuration.
*
Expand Down
124 changes: 84 additions & 40 deletions test/utils.tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,52 +58,96 @@ describe('utils', () => {
expect(elevated_limits).to.be.undefined;
});


it('should add overrides', () => {
const bucket = {
size: 100,
per_second: 100,
elevated_limits: {
size: 200,
per_second: 200,
erl_activation_period_seconds: 300,
quota_per_calendar_month: 5
},
overrides: {
'127.0.0.1': {
describe('when overrides are provided', () => {
it('should add overrides', () => {
const bucket = {
size: 100,
per_second: 100,
elevated_limits: {
size: 200,
per_second: 200,
elevated_limits: {
size: 400,
per_second: 400,
erl_activation_period_seconds: 900,
quota_per_calendar_month: 10,
},
erl_activation_period_seconds: 300,
quota_per_calendar_month: 5
},
overrides: {
'127.0.0.1': {
size: 200,
per_second: 200,
elevated_limits: {
size: 400,
per_second: 400,
erl_activation_period_seconds: 900,
quota_per_calendar_month: 10,
},
}
}
}
};
const response = normalizeType(bucket);
const { elevated_limits, overrides, overridesMatch, overridesCache, ...rest } = response;
expect(overrides['127.0.0.1']).to.not.be.null;
expect(overrides['127.0.0.1']).excluding('drip_interval').excluding('elevated_limits').to.deep.equal({
size: 200,
interval: 1000,
per_interval: 200,
ttl: 1,
ms_per_interval: 0.2,
name: "127.0.0.1",
until: undefined
};
const response = normalizeType(bucket);
const { elevated_limits, overrides, overridesMatch, overridesCache, ...rest } = response;
expect(overrides['127.0.0.1']).to.not.be.null;
expect(overrides['127.0.0.1']).excluding(['drip_interval', 'elevated_limits']).to.deep.equal({
size: 200,
interval: 1000,
per_interval: 200,
ttl: 1,
ms_per_interval: 0.2,
name: "127.0.0.1",
until: undefined
});
expect(overrides['127.0.0.1'].elevated_limits).excluding('drip_interval').to.deep.equal({
size: 400,
interval: 1000,
per_interval: 400,
ttl: 1,
ms_per_interval: 0.4,
erl_configured_for_bucket: true,
});
});
expect(overrides['127.0.0.1'].elevated_limits).excluding('drip_interval').to.deep.equal({
size: 400,
interval: 1000,
per_interval: 400,
ttl: 1,
ms_per_interval: 0.4,
erl_configured_for_bucket: true,



it('should allow to only override elevated_limits', () => {
const bucket = {
size: 100,
per_second: 100,
elevated_limits: {
size: 200,
per_second: 200,
},
overrides: {
'127.0.0.1': {
elevated_limits: {
size: 400,
per_second: 400,
},
}
}
};
const response = normalizeType(bucket);
const { elevated_limits, overrides, overridesMatch, overridesCache, ...rest } = response;
expect(overrides['127.0.0.1']).to.not.be.null;
expect(overrides['127.0.0.1']).excluding(['drip_interval', 'elevated_limits']).to.deep.equal({
size: 100,
interval: 1000,
per_interval: 100,
ttl: 1,
ms_per_interval: 0.1,
name: "127.0.0.1",
until: undefined
});
expect(overrides['127.0.0.1'].elevated_limits).excluding('drip_interval').to.deep.equal({
size: 400,
interval: 1000,
per_interval: 400,
ttl: 1,
ms_per_interval: 0.4,
erl_configured_for_bucket: true,
});

});
});
});
})


describe('quotaExpiration', () => {
const tests = [{
Expand Down

0 comments on commit 0aa08e1

Please sign in to comment.