From d857d6902c709ced6e3817efa3dd2d10a4052ff5 Mon Sep 17 00:00:00 2001 From: Safija Hubljar Date: Tue, 2 Sep 2025 08:51:32 +0200 Subject: [PATCH 1/4] Request rate limiting --- src/.vuepress/config.js | 1 + .../bootstrap/request-rate-limiting.md | 104 ++++++++++++++++++ 2 files changed, 105 insertions(+) create mode 100644 src/en/developer-guide/applications/modules/bootstrap/request-rate-limiting.md diff --git a/src/.vuepress/config.js b/src/.vuepress/config.js index 86fd5981..fab346e4 100644 --- a/src/.vuepress/config.js +++ b/src/.vuepress/config.js @@ -209,6 +209,7 @@ module.exports = config({ children: [ ['applications/modules/bootstrap/tags', 'Tags'], ['applications/modules/bootstrap/dynamic-attributes', 'Dynamic Attributes'], + ['applications/modules/bootstrap/request-rate-limiting', 'Request rate limiting'], { title: 'Data', collapsable: true, diff --git a/src/en/developer-guide/applications/modules/bootstrap/request-rate-limiting.md b/src/en/developer-guide/applications/modules/bootstrap/request-rate-limiting.md new file mode 100644 index 00000000..b6274890 --- /dev/null +++ b/src/en/developer-guide/applications/modules/bootstrap/request-rate-limiting.md @@ -0,0 +1,104 @@ +--- +title: Api Request Rate Limit +tagline: The ApiRequestRateLimit plugin restricts the number of requests a user or process can execute within a defined time window. +author: Safija Hubljar +--- + +## Introduction + +The **ApiRequestRateLimit** plugin is designed to enforce request throttling in Dataverse by controlling how many operations can be performed within a specified sliding time window. +This helps to prevent abuse, protect overall system performance, and ensure reliable operation of both **Power Apps** and **Portal** scenarios. + +Instead of allowing unlimited requests, the plugin logs each attempt and validates whether the number of requests exceeds the configured threshold. If the limit is reached, an exception is thrown. + +#### Basic Concepts +- **Request Threshold** – maximum number of allowed requests within a defined time window. +- **Sliding Window** – duration in seconds used to count requests. +- **Partition Key** – combination of User, SDK Message, and Entity used to group requests. +- **Execution Log** – record stored in `talxis_executionlog` entity representing a single request. +- **Compatibility** – works with both **Power Apps** and **Portal**. + +## Entities +### Execution Log (talxis_executionlog) + +The plugin creates a log entry for each request to track request frequency. + +| Display Name | Logical Name | Description | +|-----------------|----------------------|-----------------------------------------------------------------------------| +| Execution Log | talxis_executionlog | Represents a single request execution recorded for rate limit evaluation. | +| Partition Id | partitionid | A unique identifier. | +| TTL in Seconds | ttlinseconds | Defines how long the log entry remains valid (default: 86400 seconds). | +| Created On | createdon | Timestamp of when the log entry was created. | + +## Technical Specifications + +- **Class name**: `ApiRequestRateLimit` +- **Base class**: `PluginBase` +- **Configuration**: JSON passed as unsecure configuration string + +```json + { + "requestTreshold": 100, + "slidingWindow": 3600 + } +``` + +* `requestTreshold`: Maximum number of allowed requests. + +* `slidingWindow`: Duration of time window in seconds. + +* **Default log TTL**: 86,400 seconds (24 hours). + +* **Supported Scenarios**: Power Apps, Portal. + +#### How it works + +1. Identifies the current user or record owner. +2. Build a unique partition key: `accessPrincipalId/userId;sdkMessageName;boundEntityLogicalName` +3. Queries `talxis_executionlog` for records within the sliding window. +4. If the request count >= threshold, a new log is created and an exception is thrown. +5. Otherwise, a new log entry is created and execution continues. + +### Example Exception + +If the threshold is exceeded, the following error is raised: + +```json +Too many requests +``` + +## Warning + +Improper setup may result in blocking valid operations. For example, bulk data imports or automated workflows may be unintentionally restricted if the limits are too low. Always validate the configuration in a sandbox environment before enabling the plugin in production. + +## Setup Guide + +To enable this plugin: + +1. Deploy the plugin assembly to your Dataverse environment. +2. Register the `ApiRequestRateLimit` step on the relevant SDK messages (`Create`, `Update`, `Delete`, or custom actions). +3. Provide an **unsecure configuration** string in JSON format defining threshold and sliding window. + +Example configuration string: + +```json +{ + "requestTreshold": 3, + "slidingWindow": 60 +} +``` + +This configuration allows up to 3 requests per user/message/entity within a 1-minute window. + +## Planned Improvements (v2) + +The following improvements are planned for version 2: + +1. **Metadata caching in static variable** + Store request metadata in memory on the plugin execution node to reduce database calls. Requires reliability testing. + +2. **Split logging into a separate plugin** + Move the execution log creation into an asynchronous post-operation plugin, reducing user wait time. Some inaccuracy in request counting may occur. + +3. **Portal backend integration** + Shift request limiting logic into the portal backend layer, preventing excessive requests before they reach Dataverse. From 4544aee09b6b201d03086db1f0316cadc95ab6b0 Mon Sep 17 00:00:00 2001 From: Safija Hubljar Date: Tue, 2 Sep 2025 09:27:18 +0200 Subject: [PATCH 2/4] Added desc for execution table --- .../modules/bootstrap/request-rate-limiting.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/en/developer-guide/applications/modules/bootstrap/request-rate-limiting.md b/src/en/developer-guide/applications/modules/bootstrap/request-rate-limiting.md index b6274890..9546f523 100644 --- a/src/en/developer-guide/applications/modules/bootstrap/request-rate-limiting.md +++ b/src/en/developer-guide/applications/modules/bootstrap/request-rate-limiting.md @@ -18,10 +18,15 @@ Instead of allowing unlimited requests, the plugin logs each attempt and validat - **Execution Log** – record stored in `talxis_executionlog` entity representing a single request. - **Compatibility** – works with both **Power Apps** and **Portal**. +## Warning + +Improper setup may result in blocking valid operations. For example, bulk data imports or automated workflows may be unintentionally restricted if the limits are too low. Always validate the configuration in a sandbox environment before enabling the plugin in production. + ## Entities ### Execution Log (talxis_executionlog) The plugin creates a log entry for each request to track request frequency. +This is an Elasticsearch table, and records are automatically deleted based on the configured TTL (time-to-live) settings. | Display Name | Logical Name | Description | |-----------------|----------------------|-----------------------------------------------------------------------------| @@ -67,10 +72,6 @@ If the threshold is exceeded, the following error is raised: Too many requests ``` -## Warning - -Improper setup may result in blocking valid operations. For example, bulk data imports or automated workflows may be unintentionally restricted if the limits are too low. Always validate the configuration in a sandbox environment before enabling the plugin in production. - ## Setup Guide To enable this plugin: From 2d48a420b777063caabde71bcf5d976cab0f07ee Mon Sep 17 00:00:00 2001 From: Safija Hubljar Date: Tue, 2 Sep 2025 09:31:59 +0200 Subject: [PATCH 3/4] Name fix --- .../applications/modules/bootstrap/request-rate-limiting.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/en/developer-guide/applications/modules/bootstrap/request-rate-limiting.md b/src/en/developer-guide/applications/modules/bootstrap/request-rate-limiting.md index 9546f523..71ce566b 100644 --- a/src/en/developer-guide/applications/modules/bootstrap/request-rate-limiting.md +++ b/src/en/developer-guide/applications/modules/bootstrap/request-rate-limiting.md @@ -26,7 +26,7 @@ Improper setup may result in blocking valid operations. For example, bulk data i ### Execution Log (talxis_executionlog) The plugin creates a log entry for each request to track request frequency. -This is an Elasticsearch table, and records are automatically deleted based on the configured TTL (time-to-live) settings. +This is an Elastic table, and records are automatically deleted based on the configured TTL (time-to-live) settings. | Display Name | Logical Name | Description | |-----------------|----------------------|-----------------------------------------------------------------------------| From 9548718ad26060b1ebb1fa9c682af115d08c6163 Mon Sep 17 00:00:00 2001 From: Safija Hubljar Date: Tue, 2 Sep 2025 13:47:01 +0200 Subject: [PATCH 4/4] Typo fix --- .../applications/modules/bootstrap/request-rate-limiting.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/en/developer-guide/applications/modules/bootstrap/request-rate-limiting.md b/src/en/developer-guide/applications/modules/bootstrap/request-rate-limiting.md index 71ce566b..bb8aaef4 100644 --- a/src/en/developer-guide/applications/modules/bootstrap/request-rate-limiting.md +++ b/src/en/developer-guide/applications/modules/bootstrap/request-rate-limiting.md @@ -43,12 +43,12 @@ This is an Elastic table, and records are automatically deleted based on the con ```json { - "requestTreshold": 100, + "requestThreshold": 100, "slidingWindow": 3600 } ``` -* `requestTreshold`: Maximum number of allowed requests. +* `requestThreshold`: Maximum number of allowed requests. * `slidingWindow`: Duration of time window in seconds. @@ -84,7 +84,7 @@ Example configuration string: ```json { - "requestTreshold": 3, + "requestThreshold": 3, "slidingWindow": 60 } ```