WIP: feat: add computation quotas check#1013
Conversation
📝 WalkthroughWalkthroughThis PR introduces an operation-based quota system. A new ChangesOperation quota tracking
Sequence Diagram(s)sequenceDiagram
participant Client
participant StudyService
participant UserAdminService
participant ConsumerService
Client->>StudyService: run computation
StudyService->>StudyService: assertOnQuotasAvailability(computationType, userId)
StudyService->>UserAdminService: getUserCurrentQuota / getUserMaxQuota
UserAdminService-->>StudyService: quota values
StudyService->>UserAdminService: startOperationWithQuota(userId, operationType, resultUuid)
StudyService-->>Client: computation result UUID
Note over ConsumerService: computation completes asynchronously
ConsumerService->>ConsumerService: read userId, resultUuid from message headers
ConsumerService->>UserAdminService: endOperationWithQuota(userId, operationType, resultUuid)
ConsumerService-->>Client: notify result/failure/stop
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ast-grep (0.44.1)src/main/java/org/gridsuite/study/server/service/StudyService.javaast-grep timed out on this file src/main/java/org/gridsuite/study/server/service/UserAdminService.javaast-grep retry budget exhausted before isolating this batch src/main/resources/config/application.yamlast-grep retry budget exhausted before isolating this batch
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
03724ef to
05ec476
Compare
|
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
src/test/java/org/gridsuite/study/server/utils/TestUtils.java (2)
239-264: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueDuplicated
removeServeEventsMatchingpair across the two teardown helpers.Consider extracting a small private helper (e.g.
removeQuotaServeEvents(WireMockServer)) to avoid repeating the same two lines inassertWiremockServerRequestsEmptyThenShutdownandassertWiremockServerRequestsEmptyThenClear.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/test/java/org/gridsuite/study/server/utils/TestUtils.java` around lines 239 - 264, The two teardown helpers, assertWiremockServerRequestsEmptyThenShutdown and assertWiremockServerRequestsEmptyThenClear, repeat the same removeServeEventsMatching calls for the quota start/end URLs. Extract that duplicated logic into a small private helper such as removeQuotaServeEvents(WireMockServer) and call it from both methods so the quota-event cleanup is centralized and easier to maintain.
112-140: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winNarrow the quota-skip regex to avoid masking legitimate GET
/quota/maxverification.
"/v1/users/.*/quota/.*"also matches a GET.../quota/maxrequest, not just the start/end tracking calls it's meant to filter out. This differs from the preciseUserAdminServerStubs.QUOTA_START_URL_PATTERN/QUOTA_END_URL_PATTERN(which require a/startor/endsuffix) already imported in this file. If a future MockWebServer-based test needs to verify the max-quota check call, this broader filter would silently skip it.♻️ Suggested fix reusing the precise patterns
do { recordedRequest = Objects.requireNonNull(server.takeRequest(TIMEOUT, TimeUnit.MILLISECONDS)); // skip quota start/end requests that are auto-handled and not part of test assertions - } while (recordedRequest.getPath() != null && recordedRequest.getPath().matches("/v1/users/.*/quota/.*")); + } while (recordedRequest.getPath() != null + && (recordedRequest.getPath().matches(UserAdminServerStubs.QUOTA_START_URL_PATTERN) + || recordedRequest.getPath().matches(UserAdminServerStubs.QUOTA_END_URL_PATTERN)));Apply the same change in
getRequestsDone.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/test/java/org/gridsuite/study/server/utils/TestUtils.java` around lines 112 - 140, The quota-request filtering in TestUtils.assertRequestMatches and getRequestsDone is too broad and can accidentally skip legitimate GET /quota/max calls. Replace the generic "/v1/users/.*/quota/.*" match with the precise quota start/end patterns already available in this file via UserAdminServerStubs.QUOTA_START_URL_PATTERN and UserAdminServerStubs.QUOTA_END_URL_PATTERN, and apply the same narrowing in both helper methods.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/main/java/org/gridsuite/study/server/service/ConsumerService.java`:
- Around line 402-405: The quota release path in ConsumerService’s handler only
checks userId before calling userAdminService.endOperationWithQuota, so it can
pass a null resultUuid and build a malformed quota URL. Update the free-quota
block to require both userId and resultUuid before invoking
endOperationWithQuota, matching the guard already used in the stopped handler,
and keep the call to OperationType.mapFromComputationType(computationType)
unchanged.
---
Nitpick comments:
In `@src/test/java/org/gridsuite/study/server/utils/TestUtils.java`:
- Around line 239-264: The two teardown helpers,
assertWiremockServerRequestsEmptyThenShutdown and
assertWiremockServerRequestsEmptyThenClear, repeat the same
removeServeEventsMatching calls for the quota start/end URLs. Extract that
duplicated logic into a small private helper such as
removeQuotaServeEvents(WireMockServer) and call it from both methods so the
quota-event cleanup is centralized and easier to maintain.
- Around line 112-140: The quota-request filtering in
TestUtils.assertRequestMatches and getRequestsDone is too broad and can
accidentally skip legitimate GET /quota/max calls. Replace the generic
"/v1/users/.*/quota/.*" match with the precise quota start/end patterns already
available in this file via UserAdminServerStubs.QUOTA_START_URL_PATTERN and
UserAdminServerStubs.QUOTA_END_URL_PATTERN, and apply the same narrowing in both
helper methods.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: bd8f74b1-33af-4c41-a8f8-f55735d4b2f6
📒 Files selected for processing (24)
src/main/java/org/gridsuite/study/server/controller/StudyController.javasrc/main/java/org/gridsuite/study/server/dto/OperationType.javasrc/main/java/org/gridsuite/study/server/dto/UserProfileInfos.javasrc/main/java/org/gridsuite/study/server/error/StudyBusinessErrorCode.javasrc/main/java/org/gridsuite/study/server/service/ConsumerService.javasrc/main/java/org/gridsuite/study/server/service/StudyService.javasrc/main/java/org/gridsuite/study/server/service/UserAdminService.javasrc/main/resources/config/application.yamlsrc/test/java/org/gridsuite/study/server/NetworkModificationTest.javasrc/test/java/org/gridsuite/study/server/NodeSequenceTest.javasrc/test/java/org/gridsuite/study/server/ShortCircuitTest.javasrc/test/java/org/gridsuite/study/server/StateEstimationTest.javasrc/test/java/org/gridsuite/study/server/StudyControllerDynamicMarginCalculationTest.javasrc/test/java/org/gridsuite/study/server/StudyControllerDynamicSecurityAnalysisTest.javasrc/test/java/org/gridsuite/study/server/StudyControllerDynamicSimulationTest.javasrc/test/java/org/gridsuite/study/server/StudyServiceTest.javasrc/test/java/org/gridsuite/study/server/VoltageInitTest.javasrc/test/java/org/gridsuite/study/server/dto/OperationTypeTest.javasrc/test/java/org/gridsuite/study/server/rootnetworks/ModificationToExcludeTest.javasrc/test/java/org/gridsuite/study/server/service/StudyServiceDynamicSimulationTest.javasrc/test/java/org/gridsuite/study/server/service/UserAdminServiceTest.javasrc/test/java/org/gridsuite/study/server/utils/TestUtils.javasrc/test/java/org/gridsuite/study/server/utils/wiremock/UserAdminServerStubs.javasrc/test/resources/application-default.yml
| // free quota | ||
| if (userId != null) { | ||
| userAdminService.endOperationWithQuota(userId, OperationType.mapFromComputationType(computationType), resultUuid); | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Also guard on resultUuid != null before freeing quota.
Here resultUuid can be null (the resultUuid header may be absent on a failure message — it's only assigned when resultId != null). With only the userId != null check, endOperationWithQuota is called with a null operation id, producing a malformed URL such as /quota/LOAD_FLOW/null/end. The stopped handler at Line 431 correctly guards both. Align this handler:
🐛 Proposed fix
- // free quota
- if (userId != null) {
+ // free quota
+ if (userId != null && resultUuid != null) {
userAdminService.endOperationWithQuota(userId, OperationType.mapFromComputationType(computationType), resultUuid);
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // free quota | |
| if (userId != null) { | |
| userAdminService.endOperationWithQuota(userId, OperationType.mapFromComputationType(computationType), resultUuid); | |
| } | |
| // free quota | |
| if (userId != null && resultUuid != null) { | |
| userAdminService.endOperationWithQuota(userId, OperationType.mapFromComputationType(computationType), resultUuid); | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/main/java/org/gridsuite/study/server/service/ConsumerService.java` around
lines 402 - 405, The quota release path in ConsumerService’s handler only checks
userId before calling userAdminService.endOperationWithQuota, so it can pass a
null resultUuid and build a malformed quota URL. Update the free-quota block to
require both userId and resultUuid before invoking endOperationWithQuota,
matching the guard already used in the stopped handler, and keep the call to
OperationType.mapFromComputationType(computationType) unchanged.



PR Summary