Request Cost accounting - adding a cost for various api request actions.#32890
Merged
Request Cost accounting - adding a cost for various api request actions.#32890
Conversation
…adding a cost for various api request actions. ref: #32886
jdotcms
reviewed
Aug 11, 2025
jdotcms
reviewed
Aug 11, 2025
jdotcms
approved these changes
Aug 11, 2025
Implementing request costing. - Adding annotation for @RequestCost(increment=2) - RequestCostAPI - Adding appropriate annotations - Adding cost reporting ref: #32890
Implementing request costing. - Adding Tests ref: #32890
Implementing request costing. - Adding Tests ref: #32890
Implementing request costing. fixing annotations ref: #32890
Implementing request costing. fixing reporting ref: #32890
Using an Enum to centralize pricing ref: #32890
Using an Enum to centralize pricing ref: #32890
Using an Enum to centralize pricing ref: #32890
…appens in real time, not after a request has finished. ref: #32886
spbolton
approved these changes
Jan 7, 2026
sfreudenthaler
approved these changes
Jan 7, 2026
Member
sfreudenthaler
left a comment
There was a problem hiding this comment.
my friend Claude and I agree that this is good to go 🥇 🤖
This was referenced Jan 26, 2026
github-merge-queue Bot
pushed a commit
that referenced
this pull request
Jan 27, 2026
This PR fixes: #34300 ## Cleanup: Remove container variantId usage and use page-level variantId ### Problem The codebase was attempting to extract `variantId` from container objects via `container?.parentPermissionable?.variantId`, but this property no longer exists after [PR #32890](#32890). This resulted in `variantId` always being `undefined` when used in container operations. Additionally, containers don't actually have `variantId` - it's a **page-level concept**, not a container-level one. The `/api/v1/page/copyContent` endpoint expects the **page-level variantId** in the `DotTreeNode` payload, not a container's variantId. ### Changes 1. **Removed `variantId` from `getContainersData` function** (`libs/sdk/uve/src/lib/dom/dom.utils.ts`) - Removed the TODO comment and code attempting to extract `variantId` from `parentPermissionable.variantId` - This property no longer exists in the API response 2. **Removed `variantId` from `EditableContainerData` interface** (`libs/sdk/types/src/lib/editor/public.ts`) - Removed the optional `variantId?: string` property since containers don't have variantId 3. **Updated `getCurrentTreeNode` to use page-level variantId** (`libs/portlets/edit-ema/portlet/src/lib/store/features/editor/withEditor.ts`) - Changed from using `container.variantId` to `store.$variantId()` which provides the page-level variantId - This ensures the correct variantId is sent to the `/api/v1/page/copyContent` endpoint 4. **Made `ContainerPayload.variantId` optional** (`libs/portlets/edit-ema/portlet/src/lib/shared/models.ts`) - Changed from `variantId: string` to `variantId?: string` with documentation explaining containers don't have variantId 5. **Updated tests** (`libs/portlets/edit-ema/portlet/src/lib/store/features/editor/withEditor.spec.ts`) - Updated test expectations to verify page-level variantId is used - Added test cases to ensure container variantId is ignored ### Impact - ✅ **Fixes incorrect API calls**: The `/api/v1/page/copyContent` endpoint now receives the correct page-level variantId instead of `undefined` - ✅ **Removes dead code**: Eliminates code attempting to access a non-existent property - ✅ **Improves code clarity**: Makes it explicit that variantId is a page-level concept, not container-level - ✅ **No breaking changes**: `ContainerPayload.variantId` is now optional, maintaining backward compatibility ### Testing - Updated unit tests to verify `getCurrentTreeNode` uses page-level variantId from `store.$variantId()` - Added test cases to ensure container variantId is properly ignored - All existing tests pass ### Related - Related to issue: [Issue #34300](#34300) - Follows up on: [PR #32890](#32890) which removed `parentPermissionable` from container API responses
github-merge-queue Bot
pushed a commit
that referenced
this pull request
Jan 27, 2026
This PR fixes: #34300 ## Cleanup: Remove container variantId usage and use page-level variantId ### Problem The codebase was attempting to extract `variantId` from container objects via `container?.parentPermissionable?.variantId`, but this property no longer exists after [PR #32890](#32890). This resulted in `variantId` always being `undefined` when used in container operations. Additionally, containers don't actually have `variantId` - it's a **page-level concept**, not a container-level one. The `/api/v1/page/copyContent` endpoint expects the **page-level variantId** in the `DotTreeNode` payload, not a container's variantId. ### Changes 1. **Removed `variantId` from `getContainersData` function** (`libs/sdk/uve/src/lib/dom/dom.utils.ts`) - Removed the TODO comment and code attempting to extract `variantId` from `parentPermissionable.variantId` - This property no longer exists in the API response 2. **Removed `variantId` from `EditableContainerData` interface** (`libs/sdk/types/src/lib/editor/public.ts`) - Removed the optional `variantId?: string` property since containers don't have variantId 3. **Updated `getCurrentTreeNode` to use page-level variantId** (`libs/portlets/edit-ema/portlet/src/lib/store/features/editor/withEditor.ts`) - Changed from using `container.variantId` to `store.$variantId()` which provides the page-level variantId - This ensures the correct variantId is sent to the `/api/v1/page/copyContent` endpoint 4. **Made `ContainerPayload.variantId` optional** (`libs/portlets/edit-ema/portlet/src/lib/shared/models.ts`) - Changed from `variantId: string` to `variantId?: string` with documentation explaining containers don't have variantId 5. **Updated tests** (`libs/portlets/edit-ema/portlet/src/lib/store/features/editor/withEditor.spec.ts`) - Updated test expectations to verify page-level variantId is used - Added test cases to ensure container variantId is ignored ### Impact - ✅ **Fixes incorrect API calls**: The `/api/v1/page/copyContent` endpoint now receives the correct page-level variantId instead of `undefined` - ✅ **Removes dead code**: Eliminates code attempting to access a non-existent property - ✅ **Improves code clarity**: Makes it explicit that variantId is a page-level concept, not container-level - ✅ **No breaking changes**: `ContainerPayload.variantId` is now optional, maintaining backward compatibility ### Testing - Updated unit tests to verify `getCurrentTreeNode` uses page-level variantId from `store.$variantId()` - Added test cases to ensure container variantId is properly ignored - All existing tests pass ### Related - Related to issue: [Issue #34300](#34300) - Follows up on: [PR #32890](#32890) which removed `parentPermissionable` from container API responses
dsolistorres
pushed a commit
that referenced
this pull request
Feb 20, 2026
…ns. (#32890) This PR Implements a request cost accounting system that tracks API usage and provides optional rate limiting using a leaky token bucket algorithm. ## Key Features ### Request Cost Tracking - Assigns cost values to expensive operations (ES queries, file operations, image processing, etc.) - Uses ByteBuddy AOP to intercept annotated methods via @RequestCost - Adds `x-dotrequest-cost` response header showing request cost - Periodic logging of request metrics (requests, total cost, avg cost per request) ### Optional Rate Limiting - Leaky token bucket implementation (LeakyTokenBucketImpl) - Adds `x-dotratelimit-toks-max` response header showing how many tokens remain in bucket and the max bucket value. - Configurable via `RATE_LIMIT_ENABLED`, `RATE_LIMIT_REFILL_PER_SECOND`, `RATE_LIMIT_MAX_BUCKET_SIZE` - Disabled by default. - When enabled, it will subtract the cost of any request from the tokens in the bucket. The bucket will refill at the rate of `RATE_LIMIT_REFILL_PER_SECOND`. If the bucket is empty, the rate limiter will reject requests with a `429` or `To Many Request` error when tokens are exhausted. <img width="592" height="297" alt="Screenshot 2026-01-07 at 10 08 45 AM" src="https://github.com/user-attachments/assets/b96b9a75-abc0-478d-bac2-1715af0eb56c" /> ### Accounting Modes If you are logged in, you can add a query parameter `dotAccounting` to any request to get an accounting of its cost, e.g. ``` https://local.dotcms.site:8443/?dotAccounting=LOG ``` - NONE - No tracking - HEADER - Cost in response header (default) - LOG - Detailed logging per operation - HTML - Visual report for debugging (admin only) ### Configuration with defaults ``` REQUEST_COST_ACCOUNTING_ENABLED=true # Enable/disable cost reporting REQUEST_COST_TIME_WINDOW_SECONDS=60 # Cost Logging interval RATE_LIMIT_ENABLED=false # Enable hard rate limiting RATE_LIMIT_REFILL_PER_SECOND=500 # Token refill rate RATE_LIMIT_MAX_BUCKET_SIZE=10000 # Max tokens RATE_LIMIT_ADD_HEADER_INFO=true # Adds header which reports on number of tokens remaining ``` ### Tests - Added unit tests for RequestCostApi, RequestCostFilter, RequestCostRequestListener, LeakyTokenBucketImpl and RequestCostReport for validation. - Integration tests verify HTML report behavior and accounting stability across requests. ### To Do - Create a new LeakyTokenBucketImpl that reads token and bucket information from reddit for use across load balanced systems. - Log expensive requests, e.g. log any request > 1000 tokens ref: #32886
dsolistorres
pushed a commit
that referenced
this pull request
Feb 20, 2026
This PR fixes: #34300 ## Cleanup: Remove container variantId usage and use page-level variantId ### Problem The codebase was attempting to extract `variantId` from container objects via `container?.parentPermissionable?.variantId`, but this property no longer exists after [PR #32890](#32890). This resulted in `variantId` always being `undefined` when used in container operations. Additionally, containers don't actually have `variantId` - it's a **page-level concept**, not a container-level one. The `/api/v1/page/copyContent` endpoint expects the **page-level variantId** in the `DotTreeNode` payload, not a container's variantId. ### Changes 1. **Removed `variantId` from `getContainersData` function** (`libs/sdk/uve/src/lib/dom/dom.utils.ts`) - Removed the TODO comment and code attempting to extract `variantId` from `parentPermissionable.variantId` - This property no longer exists in the API response 2. **Removed `variantId` from `EditableContainerData` interface** (`libs/sdk/types/src/lib/editor/public.ts`) - Removed the optional `variantId?: string` property since containers don't have variantId 3. **Updated `getCurrentTreeNode` to use page-level variantId** (`libs/portlets/edit-ema/portlet/src/lib/store/features/editor/withEditor.ts`) - Changed from using `container.variantId` to `store.$variantId()` which provides the page-level variantId - This ensures the correct variantId is sent to the `/api/v1/page/copyContent` endpoint 4. **Made `ContainerPayload.variantId` optional** (`libs/portlets/edit-ema/portlet/src/lib/shared/models.ts`) - Changed from `variantId: string` to `variantId?: string` with documentation explaining containers don't have variantId 5. **Updated tests** (`libs/portlets/edit-ema/portlet/src/lib/store/features/editor/withEditor.spec.ts`) - Updated test expectations to verify page-level variantId is used - Added test cases to ensure container variantId is ignored ### Impact - ✅ **Fixes incorrect API calls**: The `/api/v1/page/copyContent` endpoint now receives the correct page-level variantId instead of `undefined` - ✅ **Removes dead code**: Eliminates code attempting to access a non-existent property - ✅ **Improves code clarity**: Makes it explicit that variantId is a page-level concept, not container-level - ✅ **No breaking changes**: `ContainerPayload.variantId` is now optional, maintaining backward compatibility ### Testing - Updated unit tests to verify `getCurrentTreeNode` uses page-level variantId from `store.$variantId()` - Added test cases to ensure container variantId is properly ignored - All existing tests pass ### Related - Related to issue: [Issue #34300](#34300) - Follows up on: [PR #32890](#32890) which removed `parentPermissionable` from container API responses
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR Implements a request cost accounting system that tracks API usage and provides optional rate limiting using a leaky token bucket algorithm.
Key Features
Request Cost Tracking
x-dotrequest-costresponse header showing request costOptional Rate Limiting
x-dotratelimit-toks-maxresponse header showing how many tokens remain in bucket and the max bucket value.RATE_LIMIT_ENABLED,RATE_LIMIT_REFILL_PER_SECOND,RATE_LIMIT_MAX_BUCKET_SIZERATE_LIMIT_REFILL_PER_SECOND. If the bucket is empty, the rate limiter will reject requests with a429orTo Many Requesterror when tokens are exhausted.Accounting Modes
If you are logged in, you can add a query parameter
dotAccountingto any request to get an accounting of its cost, e.g.Configuration with defaults
Tests
To Do
ref: #32886
This PR fixes: #32886