Rate Limiting Kepler services
This topic describes how to set up Rate Limiting for Kepler services. These instructions apply to Relativity Server 2024 and later, and are intended for Relativity administrators. You will need access to SQL Server Management Studio and the EDDS database, or the Instance Settings console, to set up the rate limiting described here.
What is rate limiting?
Rate limiting puts a speed limit on how often a particular Relativity service can be called in a given amount of time.
Think of it like a tollbooth with a sign that says "no more than 1,000 cars per minute". Cars under that limit pass through normally. Once the limit is reached, additional cars are turned away until the next minute starts. Kepler rate limiting works the same way for calls made to Relativity's web services (called Kepler services) — it protects the system from being overwhelmed by too many requests in too short a time.
Rate limiting is only enforced for a service once an administrator configures a limit for it with an instance setting. Until you do that, no limit is applied.
How it works
Once you've configured a limit for a service, every call to that service passes through a checkpoint before it reaches the service itself:
- Under the limit — the request goes through normally, and the response includes a few informational usage headers
- Limit reached for this time window — the request is blocked with an HTTP
429response, and the caller must wait and retry.
See the section What callers see when a limit is hit for more information on the headers and behavior.
This works automatically for normal Relativity traffic — there is no separate step you need to take to make calls count toward the limit. The only thing that determines whether a limit applies is whether you have configured one for that service in the instance setting.
Before you begin
Prerequisites:
- Access to SQL Server Management Studio (or another tool for running SQL) connected to the
EDDSdatabase, or access to the Relativity Instance Settings console (Server > Instance Settings) if you'd rather add the setting through the User Interface instead of SQL. - A maintenance window. Changing this setting does not require restarting Relativity, but it's good practice to make configuration changes at a quiet time.
- The name of the Kepler service you want to limit, if you are only limiting one or two services rather than all of them.
- Measure your traffic before picking a number. There is no one-size-fits-all limit. The right number of requests per time window depends on how many users and workspaces you have, and how much of your traffic is bulk exports, large productions, or automated integrations. A limit that's safe for a small environment could throttle real users in a larger one. Before setting a limit, look at your own recent traffic for the services you're protecting — for example, your Kepler metrics or IIS logs — to find a realistic peak, and set your limit with a safety margin above it, rather than guessing.
Create the instance setting
This is the setting that turns rate limiting on for a service and defines its limit. Add it either through the Relativity user interface, or with SQL.
Option A: Add it through the Relativity UI
Go to Home > Instance Settings > New Instance Setting and fill in:
| Field | Value |
|---|---|
| Name | RateLimitConfiguration
|
| Section | Relativity.Platform.Discovery
|
| Machine | Leave blank (applies to all servers) |
| Value Type | Text
|
| Value | Your rate limit rule, for example r=Relativity.Services.Environmental.IEnvironmentModule;l=3;w=10 |
Option B: Add it with SQL instead
EXEC [eddsdbo].CreateInstanceSetting
@section = 'Relativity.Platform.Discovery',
@name = 'RateLimitConfiguration',
@machineName = '',
@value = 'r=Relativity.Services.Environmental.IEnvironmentModule;l=1000;w=60',
@description = 'A list of rate limit configurations, one for each Kepler Module which is being rate limited.',
@valueType = 'Text',
@initialValue = 'r=Relativity.Services.Environmental.IEnvironmentModule;l=1000;w=60',
@createAsSystemArtifact = 0
Reading and writing the setting's value
The value field looks technical, but it follows one simple pattern: three letters, each followed by an equal sign and a number or name, separated by semicolons.
| Letter | Stands for | What you put there |
|---|---|---|
r
|
Route | The name of the Kepler service being limited, for example Relativity.Services.Environmental.IEnvironmentModule |
l
|
Limit | The maximum number of calls allowed in the time window, for example 1000 |
w
|
Window | The length of the time window, in seconds, for example 60 for one minute |
So r=Relativity.ObjectManager;l=1000;w=60 reads as: allow up to 1,000 calls to the ObjectManager service every 60 seconds. Letters can be upper- or lower-case.
To set limits on more than one service, separate each rule with a pipe character (|):
r=Relativity.Services.Environmental.IEnvironmentModule;l=1000;w=60|r=Relativity.ObjectManager;l=1000;w=30
Configuring every service at once
If you want a limit applied to every Kepler service rather than typing a rule for each one by hand, every registered Kepler service has an entry in a table called ApplicationServiceIdentity. The following script is an example of how you could enumerate all of those services with SQL and automatically build a value in the r/l/w format. It is a starting point for your own automation, not a script to copy as-is.
Before running anything like this, measure your traffic first and choose @NumberOfRequests and @TimespanInSeconds based on what you actually observe. Applying one arbitrary limit to every service at once, without measuring first, risks throttling legitimate traffic on your busier endpoints.
DECLARE @NumberOfRequests INT = 1000;
-- the L (limit) parameter — set from your own measured traffic
DECLARE @TimespanInSeconds INT = 60;
-- the W (window) parameter — set from your own measured traffic
IF (
NOT EXISTS(
SELECT
1
FROM
[EDDS].[eddsdbo].[InstanceSetting]
WHERE
[Section] = N 'Relativity.Platform.Discovery'
AND [Name] = N 'RateLimitConfiguration'
AND [MachineName] = ''
)
) BEGIN DECLARE @configurationValue NVARCHAR(MAX);
SET
@configurationValue = (
SELECT
STRING_AGG(
CAST(
CONCAT(
'r=', [Identifier], ';L=', @NumberOfRequests,
';W=', @TimespanInSeconds
) AS NVARCHAR(MAX)
),
'|'
) WITHIN GROUP (
ORDER BY
[Identifier]
) AS RateLimitConfiguration
FROM
EDDS.eddsdbo.ApplicationServiceIdentity
);
IF (@configurationValue IS NULL) BEGIN
SET
@configurationValue = '';
END
EXEC [eddsdbo].CreateInstanceSetting @section = 'Relativity.Platform.Discovery',
@name = 'RateLimitConfiguration',
@machineName = '',
@value = @configurationValue,
@description = 'A list of rate limit configurations, one for each Kepler Module which is being rate limited.',
@valueType = 'Text',
@initialValue = @configurationValue,
@createAsSystemArtifact = 0;
END
The script would need to be modified if the instance setting already exists. The
[eddsdbo].CreateInstanceSetting stored procedure won't overwrite an existing setting.What callers see when a limit is hit
Once a limit is active, every response to a rate-limited call carries a few extra, informational headers.
Under the limit (HTTP 200) — the call goes through normally, and the response includes:
RateLimit-Limit— the limit for this serviceRateLimit-Remaining— calls left in this time windowRateLimit-Reset— seconds until the window resets
Limit reached (HTTP 429) — the call is blocked until the window resets. The caller receives:
- An HTTP
429status code - A
Retry-Afterheader — seconds to wait before trying again - A message body:
{"message": "API rate limit exceeded"}
Applications built on .NET that call a rate-limited service directly will see this as a TooManyRequestsException rather than a raw 429. Its Delta value tells the application how long to wait, matching the Retry-After header.
Frequently asked questions
Do I need to restart Relativity for a change to take effect?
No. Instance setting changes are picked up automatically on Relativity's normal refresh cycle (about every 30 seconds). New limits apply starting with the next time window for that service.
How do I find the exact name to use for the "r" (route) value?
Each Kepler service has an entry in the ApplicationServiceIdentity table, in a column named Identifier. That identifier is exactly the value to use for r=. The illustration script reads this column automatically for every service.
What happens if I make a typo in the value field?
A rule that doesn't match the expected r=…;l=…;w=… pattern is simply ignored for that entry, rather than causing an error. But it also means that service won't be rate limited as intended. Double-check the format after saving.
How do I decide what limit to set?
Don't guess. Measure your own environment's traffic first, and set your limit with a safety margin above your observed legitimate peak.
On this page