Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 6 additions & 29 deletions ReleaseNotes.md
Original file line number Diff line number Diff line change
@@ -1,31 +1,8 @@
## 🔥 Hot fixing v[23.3](https://github.com/ThreeMammals/Ocelot/releases/tag/23.3.0) (version {0}) aka [Blue Olympic Balumbes](https://www.youtube.com/live/j-Ou-ggS718?si=fPPwmOwjYEZq70H9&t=9518) release
> Codenamed: **[Blue Olympic Fiend](https://www.youtube.com/live/j-Ou-ggS718?si=fPPwmOwjYEZq70H9&t=9518)**
## :package: Documentation patch (version {0}), technical release
> Read the Docs: [Ocelot 23.3](https://ocelot.readthedocs.io/en/{0}/)
> Hot fixed versions: [23.3.0](https://github.com/ThreeMammals/Ocelot/releases/tag/23.3.0), [23.3.3](https://github.com/ThreeMammals/Ocelot/releases/tag/23.3.3)
> Milestone: [v23.3 Hotfixes](https://github.com/ThreeMammals/Ocelot/milestone/8)
> PDF Doc: [Ocelot 23.3](https://ocelot.readthedocs.io/_/downloads/en/{0}/pdf/)
> Hot fixed version: [23.3.4](https://github.com/ThreeMammals/Ocelot/releases/tag/23.3.4)

❤️ A heartfelt "Thank You" to [Roman Shevchik](https://github.com/antikorol) and [Massimiliano Innocenti](https://github.com/minnocenti901) for their contributions in testing and reporting the [Service Discovery](https://github.com/ThreeMammals/Ocelot/labels/Service%20Discovery) issues, #2110 and #2119, respectively!

### ℹ️ About
This release delivers a number of bug fixes for the predecessor's [23.3.0](https://github.com/ThreeMammals/Ocelot/releases/tag/23.3.0) release, which is full of new features but was not tested well. All bugs were combined into the [v23.3 Hotfixes](https://github.com/ThreeMammals/Ocelot/milestone/8) milestone.

Following the substantial refactoring of [Service Discovery](https://github.com/ThreeMammals/Ocelot/blob/main/docs/features/servicediscovery.rst) providers in the [23.3.0](https://github.com/ThreeMammals/Ocelot/releases/tag/23.3.0) release, the community identified and we have acknowledged several [critical service discovery defects](https://github.com/ThreeMammals/Ocelot/issues?q=is%3Aissue+milestone%3A%22v23.3+Hotfixes%22+label%3A%22Service+Discovery%22) with providers such as [Kube](https://github.com/ThreeMammals/Ocelot/blob/main/docs/features/kubernetes.rst) and [Consul](https://github.com/ThreeMammals/Ocelot/blob/main/docs/features/servicediscovery.rst#consul). The `Kube` provider, while somewhat unstable, remained operational; however, the `Consul` provider was entirely non-functional.

📓 If your projects rely on the [Service Discovery](https://ocelot.readthedocs.io/en/latest/features/servicediscovery.html) feature and cannot function without it, please upgrade to this version to utilize the full list of features of version [23.3.0](https://github.com/ThreeMammals/Ocelot/releases/tag/23.3.0).

### 🧑‍💻 Technical Information
A comprehensive explanation of the technical details would span several pages; therefore, it is advisable for fans of Ocelot to review all pertinent technical information within the issue descriptions associated with [the milestone](https://github.com/ThreeMammals/Ocelot/milestone/8).
Our team has implemented some **Breaking Changes** which we urge you to review carefully (details follow).

### ⚠️ Breaking Changes
Listed by priority:
- `ILoadBalancer` interface alteration: Method `Lease` is now `LeaseAsync`.
Interface FQN: `Ocelot.LoadBalancer.LoadBalancers.ILoadBalancer`
Method FQN: `Ocelot.LoadBalancer.LoadBalancers.ILoadBalancer.LeaseAsync`
- `DefaultConsulServiceBuilder` constructor modification: The first parameter's type has been changed from `Func<ConsulRegistryConfiguration>` to `IHttpContextAccessor`.
Class FQN: `Ocelot.Provider.Consul.DefaultConsulServiceBuilder`
Constructor signature: `public DefaultConsulServiceBuilder(IHttpContextAccessor contextAccessor, IConsulClientFactory clientFactory, IOcelotLoggerFactory loggerFactory)`
- Adjustments to `Lease` type: The `Lease` has been restructured from a class to a structure and elevated in the namespace hierarchy.
Struct FQN: `Ocelot.LoadBalancer.Lease`

📓 Should your [custom solutions](https://ocelot.readthedocs.io/en/latest/search.html?q=custom) involve overriding default Ocelot classes and their behavior, redevelopment or at least recompilation of the solution, followed by deployment, will be necessary.
### :information_source: About
This documentation patch pertains to HTML and PDF document layouts.
No NuGet packages have been uploaded.
30 changes: 20 additions & 10 deletions build.cake
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ using System.Linq;
using System.Text.RegularExpressions;

const string Release = "Release"; // task name, target, and Release config name
const string AllFrameworks = "net6.0;net7.0;net8.0";
const string LatestFramework = "net8.0";

var compileConfig = Argument("configuration", Release); // compile

// build artifacts
Expand Down Expand Up @@ -47,7 +50,7 @@ var releaseNotes = new List<string>();
// internal build variables - don't change these.
string committedVersion = "0.0.0-dev";
GitVersion versioning = null;
bool IsTechnicalRelease = false;
bool IsTechnicalRelease = true;

var target = Argument("target", "Default");
var slnFile = (target == Release) ? $"./Ocelot.{Release}.sln" : "./Ocelot.sln";
Expand Down Expand Up @@ -93,9 +96,10 @@ Task("Compile")
};
if (target != Release)
{
settings.Framework = "net8.0"; // build using .NET 8 SDK only
settings.Framework = LatestFramework; // build using .NET 8 SDK only
}
Information($"Settings {nameof(DotNetBuildSettings.Framework)}: {settings.Framework}");
string frameworkInfo = string.IsNullOrEmpty(settings.Framework) ? AllFrameworks : settings.Framework;
Information($"Settings {nameof(DotNetBuildSettings.Framework)}: {frameworkInfo}");
Information($"Settings {nameof(DotNetBuildSettings.Configuration)}: {settings.Configuration}");
DotNetBuild(slnFile, settings);
});
Expand Down Expand Up @@ -344,7 +348,7 @@ Task("RunUnitTests")
.IsDependentOn("Compile")
.Does(() =>
{
var testSettings = new DotNetTestSettings
var settings = new DotNetTestSettings
{
Configuration = compileConfig,
ResultsDirectory = artifactsForUnitTestsDir,
Expand All @@ -357,10 +361,12 @@ Task("RunUnitTests")
};
if (target != Release)
{
testSettings.Framework = "net8.0"; // .NET 8 SDK only
settings.Framework = LatestFramework; // .NET 8 SDK only
}
string frameworkInfo = string.IsNullOrEmpty(settings.Framework) ? AllFrameworks : settings.Framework;
Information($"Settings {nameof(DotNetTestSettings.Framework)}: {frameworkInfo}");
EnsureDirectoryExists(artifactsForUnitTestsDir);
DotNetTest(unitTestAssemblies, testSettings);
DotNetTest(unitTestAssemblies, settings);

var coverageSummaryFile = GetSubDirectories(artifactsForUnitTestsDir)
.First()
Expand Down Expand Up @@ -408,15 +414,17 @@ Task("RunAcceptanceTests")
var settings = new DotNetTestSettings
{
Configuration = compileConfig,
Framework = "net8.0", // .NET 8 SDK only
// Framework = LatestFramework, // .NET 8 SDK only
ArgumentCustomization = args => args
.Append("--no-restore")
.Append("--no-build")
};
if (target != Release)
{
settings.Framework = "net8.0"; // .NET 8 SDK only
settings.Framework = LatestFramework; // .NET 8 SDK only
}
string frameworkInfo = string.IsNullOrEmpty(settings.Framework) ? AllFrameworks : settings.Framework;
Information($"Settings {nameof(DotNetTestSettings.Framework)}: {frameworkInfo}");
EnsureDirectoryExists(artifactsForAcceptanceTestsDir);
DotNetTest(acceptanceTestAssemblies, settings);
});
Expand All @@ -428,15 +436,17 @@ Task("RunIntegrationTests")
var settings = new DotNetTestSettings
{
Configuration = compileConfig,
Framework = "net8.0", // .NET 8 SDK only
// Framework = LatestFramework, // .NET 8 SDK only
ArgumentCustomization = args => args
.Append("--no-restore")
.Append("--no-build")
};
if (target != Release)
{
settings.Framework = "net8.0"; // .NET 8 SDK only
settings.Framework = LatestFramework; // .NET 8 SDK only
}
string frameworkInfo = string.IsNullOrEmpty(settings.Framework) ? AllFrameworks : settings.Framework;
Information($"Settings {nameof(DotNetTestSettings.Framework)}: {frameworkInfo}");
EnsureDirectoryExists(artifactsForIntegrationTestsDir);
DotNetTest(integrationTestAssemblies, settings);
});
Expand Down
9 changes: 5 additions & 4 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,16 @@
# -- Project information -----------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information

project = 'Ocelot'
copyright = ' 2016-2024 ThreeMammals Ocelot team'
author = 'Tom Pallister, Raman Maksimchuk and Ocelot Core team at ThreeMammals'
project = 'Ocelot Gateway'
copyright = ' 2016-2024, ThreeMammals Ocelot team'
author = 'Tom Pallister, Raman Maksimchuk'
release = '23.3'

# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration

extensions = []
extensions = [
]

templates_path = ['_templates']
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
Expand Down
63 changes: 44 additions & 19 deletions docs/features/ratelimiting.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,23 +27,25 @@ To implement *rate limiting* for a Route, you need to incorporate the following
"Limit": 1
}

* **ClientWhitelist** - An array containing the whitelisted clients. Clients listed here will be exempt from rate limiting.
For more information on the **ClientIdHeader** option, refer to the :ref:`rl-global-configuration` section.
* **EnableRateLimiting** - This setting enables rate limiting on endpoints.
* **Period** - This parameter defines the duration for which the limit is applicable, such as ``1s`` (seconds), ``5m`` (minutes), ``1h`` (hours), and ``1d`` (days).
If you reach the exact **Limit** of requests, the excess occurs immediately, and the **PeriodTimespan** begins.
You must wait for the **PeriodTimespan** duration to pass before making another request.
Should you exceed the number of requests within the period more than the **Limit** permits, the **QuotaExceededMessage** will appear in the response, accompanied by the **HttpStatusCode**.
* **PeriodTimespan** - This parameter indicates the time in **seconds** after which a retry is permissible.
During this interval, the **QuotaExceededMessage** will appear in the response, accompanied by an **HttpStatusCode**.
* ``ClientWhitelist``: An array containing the whitelisted clients. Clients listed here will be exempt from rate limiting.
For more information on the ``ClientIdHeader`` option, refer to the :ref:`rl-global-configuration` section.
* ``EnableRateLimiting``: This setting enables rate limiting on endpoints.
* ``Period``: This parameter defines the duration for which the limit is applicable, such as ``1s`` (seconds), ``5m`` (minutes), ``1h`` (hours), and ``1d`` (days).
If you reach the exact ``Limit`` of requests, the excess occurs immediately, and the ``PeriodTimespan`` begins.
You must wait for the ``PeriodTimespan`` duration to pass before making another request.
Should you exceed the number of requests within the period more than the ``Limit`` permits, the ``QuotaExceededMessage`` will appear in the response, accompanied by the ``HttpStatusCode``.
* ``PeriodTimespan``: This parameter indicates the time in **seconds** after which a retry is permissible.
During this interval, the ``QuotaExceededMessage`` will appear in the response, accompanied by an ``HttpStatusCode``.
Clients are advised to consult the ``Retry-After`` header to determine the timing of subsequent requests.
* **Limit** - This parameter defines the upper limit of requests a client is allowed to make within a specified **Period**.
* ``Limit``: This parameter defines the upper limit of requests a client is allowed to make within a specified ``Period``.

.. _rl-global-configuration:

Global Configuration
^^^^^^^^^^^^^^^^^^^^

Global options are only accessible in the special :ref:`routing-dynamic` mode.

You can set the following in the ``GlobalConfiguration`` section of `ocelot.json`_:

.. code-block:: json
Expand All @@ -58,26 +60,49 @@ You can set the following in the ``GlobalConfiguration`` section of `ocelot.json
}
}

* **DisableRateLimitHeaders** - Determines if the ``X-Rate-Limit`` and ``Retry-After`` headers are disabled.
* **QuotaExceededMessage** - Defines the message displayed when the quota is exceeded. It is optional and the default message is informative.
* **HttpStatusCode** - Indicates the HTTP status code returned during *rate limiting*. The default value is **429** (`Too Many Requests`_).
* **ClientIdHeader** - Specifies the header used to identify clients, with ``ClientId`` as the default.

Future and ASP.NET Core Implementation
--------------------------------------
.. list-table::
:widths: 35 65
:header-rows: 1

* - *Property*
- *Description*
* - ``DisableRateLimitHeaders``
- Determines if the ``X-Rate-Limit`` and ``Retry-After`` headers are disabled
* - ``QuotaExceededMessage``
- Defines the message displayed when the quota is exceeded. It is optional and the default message is informative.
* - ``HttpStatusCode``
- Indicates the HTTP status code returned during *rate limiting*. The default value is **429** (`Too Many Requests`_).
* - ``ClientIdHeader``
- Specifies the header used to identify clients, with ``ClientId`` as the default.

Notes
"""""

1. Global ``RateLimitOptions`` are supported when the :ref:`sd-dynamic-routing` feature is configured with :doc:`../features/servicediscovery`.
Hence, if :doc:`../features/servicediscovery` is not set up, only the options for static routes need to be defined to impose limitations at the route level.
2. Global *Rate Limiting* options may not be practical because they impose limits on all routes.
It's reasonable to assert that in a Microservices architecture, it's an unusual approach to apply the same limitations to all routes.
Configuring per-route limiting could be a more tailored solution.
Global *Rate Limiting* is logical if all routes share the same downstream hosts, thus limiting the usage of a single service.
3. *Rate Limiting* is now built-in with ASP.NET Core 7, as discussed in the following topic below.
Our team holds the view that the ASP.NET ``RateLimiter`` enables global limitations through its rate limiting policies.

Future and ASP.NET Implementation
---------------------------------

The Ocelot team is contemplating a redesign of the *Rate Limiting* feature following the `Announcing Rate Limiting for .NET`_ by Brennan Conroy on July 13th, 2022.
Currently, no decision has been made, and the previous version of the feature remains part of the `20.0`_ release for .NET 7. [#f2]_

Discover the new features being introduced in the ASP.NET Core 7.0 release:
Discover the new features in the ASP.NET Core 7.0 release:

* The `RateLimiter Class <https://learn.microsoft.com/en-us/dotnet/api/system.threading.ratelimiting.ratelimiter>`_, available since ASP.NET Core 7.0
* The `System.Threading.RateLimiting <https://www.nuget.org/packages/System.Threading.RateLimiting>`_ NuGet package
* The `Rate limiting middleware in ASP.NET Core <https://learn.microsoft.com/en-us/aspnet/core/performance/rate-limit>`_ article by Arvin Kahbazi, Maarten Balliauw, and Rick Anderson

While retaining the old implementation as an Ocelot built-in feature makes sense, we plan to transition to the new Rate Limiter from the ``Microsoft.AspNetCore.RateLimiting`` namespace.
While it makes sense to retain the old implementation as a built-in feature of Ocelot, we are planning to transition to the new Rate Limiter from the ``Microsoft.AspNetCore.RateLimiting`` namespace.

Please share your thoughts with us in the `Discussions <https://github.com/ThreeMammals/Ocelot/discussions>`_ space of the repository. |octocat|
We invite you to share your thoughts with us in the `Discussions <https://github.com/ThreeMammals/Ocelot/discussions>`_ space of the repository. |octocat|

""""

Expand Down
Loading