Skip to content

feat: add computation quotas check#1013

Open
GhilesA wants to merge 2 commits into
mainfrom
feat/add_quotas_on_computation
Open

feat: add computation quotas check#1013
GhilesA wants to merge 2 commits into
mainfrom
feat/add_quotas_on_computation

Conversation

@GhilesA

@GhilesA GhilesA commented Jul 6, 2026

Copy link
Copy Markdown

PR Summary

  • send error when max quota is reached
  • expose quota check status (can be enabled if necessary, default quota check is off for now)

@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c7dde51d-43e2-42e5-8389-a98e8269e882

📥 Commits

Reviewing files that changed from the base of the PR and between e8a8de9 and b4accf1.

📒 Files selected for processing (24)
  • src/main/java/org/gridsuite/study/server/controller/StudyController.java
  • src/main/java/org/gridsuite/study/server/dto/OperationType.java
  • src/main/java/org/gridsuite/study/server/dto/UserProfileInfos.java
  • src/main/java/org/gridsuite/study/server/error/StudyBusinessErrorCode.java
  • src/main/java/org/gridsuite/study/server/service/ConsumerService.java
  • src/main/java/org/gridsuite/study/server/service/StudyService.java
  • src/main/java/org/gridsuite/study/server/service/UserAdminService.java
  • src/main/resources/config/application.yaml
  • src/test/java/org/gridsuite/study/server/NetworkModificationTest.java
  • src/test/java/org/gridsuite/study/server/NodeSequenceTest.java
  • src/test/java/org/gridsuite/study/server/ShortCircuitTest.java
  • src/test/java/org/gridsuite/study/server/StateEstimationTest.java
  • src/test/java/org/gridsuite/study/server/StudyControllerDynamicMarginCalculationTest.java
  • src/test/java/org/gridsuite/study/server/StudyControllerDynamicSecurityAnalysisTest.java
  • src/test/java/org/gridsuite/study/server/StudyControllerDynamicSimulationTest.java
  • src/test/java/org/gridsuite/study/server/StudyServiceTest.java
  • src/test/java/org/gridsuite/study/server/VoltageInitTest.java
  • src/test/java/org/gridsuite/study/server/dto/OperationTypeTest.java
  • src/test/java/org/gridsuite/study/server/rootnetworks/ModificationToExcludeTest.java
  • src/test/java/org/gridsuite/study/server/service/StudyServiceDynamicSimulationTest.java
  • src/test/java/org/gridsuite/study/server/service/UserAdminServiceTest.java
  • src/test/java/org/gridsuite/study/server/utils/TestUtils.java
  • src/test/java/org/gridsuite/study/server/utils/wiremock/UserAdminServerStubs.java
  • src/test/resources/application-default.yml
✅ Files skipped from review due to trivial changes (2)
  • src/test/resources/application-default.yml
  • src/test/java/org/gridsuite/study/server/VoltageInitTest.java
🚧 Files skipped from review as they are similar to previous changes (21)
  • src/test/java/org/gridsuite/study/server/dto/OperationTypeTest.java
  • src/test/java/org/gridsuite/study/server/service/StudyServiceDynamicSimulationTest.java
  • src/test/java/org/gridsuite/study/server/StudyControllerDynamicSimulationTest.java
  • src/test/java/org/gridsuite/study/server/StudyControllerDynamicSecurityAnalysisTest.java
  • src/main/java/org/gridsuite/study/server/error/StudyBusinessErrorCode.java
  • src/test/java/org/gridsuite/study/server/NodeSequenceTest.java
  • src/test/java/org/gridsuite/study/server/StateEstimationTest.java
  • src/test/java/org/gridsuite/study/server/service/UserAdminServiceTest.java
  • src/main/resources/config/application.yaml
  • src/test/java/org/gridsuite/study/server/StudyControllerDynamicMarginCalculationTest.java
  • src/main/java/org/gridsuite/study/server/dto/UserProfileInfos.java
  • src/test/java/org/gridsuite/study/server/rootnetworks/ModificationToExcludeTest.java
  • src/test/java/org/gridsuite/study/server/utils/wiremock/UserAdminServerStubs.java
  • src/main/java/org/gridsuite/study/server/service/UserAdminService.java
  • src/test/java/org/gridsuite/study/server/ShortCircuitTest.java
  • src/test/java/org/gridsuite/study/server/utils/TestUtils.java
  • src/main/java/org/gridsuite/study/server/dto/OperationType.java
  • src/test/java/org/gridsuite/study/server/StudyServiceTest.java
  • src/test/java/org/gridsuite/study/server/NetworkModificationTest.java
  • src/main/java/org/gridsuite/study/server/service/StudyService.java
  • src/main/java/org/gridsuite/study/server/service/ConsumerService.java

📝 Walkthrough

Walkthrough

This PR adds operation-based quotas for study computations, including a new quota enum, REST quota management calls, quota enforcement in study flows, quota release in consumers, a feature flag, and matching test updates.

Changes

Operation quota tracking

Layer / File(s) Summary
OperationType enum and mapping
src/main/java/org/gridsuite/study/server/dto/OperationType.java, src/main/java/org/gridsuite/study/server/dto/UserProfileInfos.java, src/main/java/org/gridsuite/study/server/error/StudyBusinessErrorCode.java, src/test/java/org/gridsuite/study/server/dto/OperationTypeTest.java
Adds OperationType, maps ComputationType values to quota types, changes profile quota data to Map<OperationType, Integer>, and adds the MAX_OPERATION_TYPE_EXCEEDED error code.
UserAdminService quota REST endpoints
src/main/java/org/gridsuite/study/server/service/UserAdminService.java, src/test/java/org/gridsuite/study/server/service/UserAdminServiceTest.java
Replaces the old build-limit lookup with quota map queries and quota start/end REST calls, with tests covering each endpoint.
StudyService quota enforcement and controller preflight
src/main/java/org/gridsuite/study/server/service/StudyService.java, src/main/java/org/gridsuite/study/server/controller/StudyController.java, src/test/java/org/gridsuite/study/server/StudyServiceTest.java, src/test/java/org/gridsuite/study/server/service/StudyServiceDynamicSimulationTest.java
Adds quota checking configuration and enforcement, switches build limits to per-operation quotas, starts quota tracking for supported computation flows, and wires controller preflight checks before computation entrypoints.
ConsumerService quota release on completion
src/main/java/org/gridsuite/study/server/service/ConsumerService.java
Ends quota-tracked operations when computation messages report failure, stop, debug, or completion.
Quota feature flag configuration
src/main/resources/config/application.yaml, src/test/resources/application-default.yml
Adds the study.enable-operation-quotas setting and disables it in test defaults.
Test mocks and WireMock stubs updated for quota API
src/test/java/org/gridsuite/study/server/NetworkModificationTest.java, src/test/java/org/gridsuite/study/server/NodeSequenceTest.java, src/test/java/org/gridsuite/study/server/ShortCircuitTest.java, src/test/java/org/gridsuite/study/server/StateEstimationTest.java, src/test/java/org/gridsuite/study/server/VoltageInitTest.java, src/test/java/org/gridsuite/study/server/StudyControllerDynamic*Test.java, src/test/java/org/gridsuite/study/server/rootnetworks/ModificationToExcludeTest.java, src/test/java/org/gridsuite/study/server/utils/TestUtils.java, src/test/java/org/gridsuite/study/server/utils/wiremock/UserAdminServerStubs.java
Updates test stubs, mocked beans, request assertions, and quota payloads to match the new API and ignore quota traffic in generic request checks.

Suggested reviewers: SlimaneAmar, AbdelHedhili

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the main change: adding computation quota checks.
Description check ✅ Passed The description matches the PR’s quota-limit error handling and configurable quota-check status.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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/controller/StudyController.java

ast-grep timed out on this file

src/main/java/org/gridsuite/study/server/service/StudyService.java

ast-grep retry budget exhausted before isolating this batch

src/main/java/org/gridsuite/study/server/service/UserAdminService.java

ast-grep retry budget exhausted before isolating this batch

  • 13 others

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@GhilesA GhilesA force-pushed the feat/add_quotas_on_computation branch from 03724ef to 05ec476 Compare July 6, 2026 13:44

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 value

Duplicated removeServeEventsMatching pair across the two teardown helpers.

Consider extracting a small private helper (e.g. removeQuotaServeEvents(WireMockServer)) to avoid repeating the same two lines in assertWiremockServerRequestsEmptyThenShutdown and assertWiremockServerRequestsEmptyThenClear.

🤖 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 win

Narrow the quota-skip regex to avoid masking legitimate GET /quota/max verification.

"/v1/users/.*/quota/.*" also matches a GET .../quota/max request, not just the start/end tracking calls it's meant to filter out. This differs from the precise UserAdminServerStubs.QUOTA_START_URL_PATTERN/QUOTA_END_URL_PATTERN (which require a /start or /end suffix) 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

📥 Commits

Reviewing files that changed from the base of the PR and between a76a79c and 2e6c5ac.

📒 Files selected for processing (24)
  • src/main/java/org/gridsuite/study/server/controller/StudyController.java
  • src/main/java/org/gridsuite/study/server/dto/OperationType.java
  • src/main/java/org/gridsuite/study/server/dto/UserProfileInfos.java
  • src/main/java/org/gridsuite/study/server/error/StudyBusinessErrorCode.java
  • src/main/java/org/gridsuite/study/server/service/ConsumerService.java
  • src/main/java/org/gridsuite/study/server/service/StudyService.java
  • src/main/java/org/gridsuite/study/server/service/UserAdminService.java
  • src/main/resources/config/application.yaml
  • src/test/java/org/gridsuite/study/server/NetworkModificationTest.java
  • src/test/java/org/gridsuite/study/server/NodeSequenceTest.java
  • src/test/java/org/gridsuite/study/server/ShortCircuitTest.java
  • src/test/java/org/gridsuite/study/server/StateEstimationTest.java
  • src/test/java/org/gridsuite/study/server/StudyControllerDynamicMarginCalculationTest.java
  • src/test/java/org/gridsuite/study/server/StudyControllerDynamicSecurityAnalysisTest.java
  • src/test/java/org/gridsuite/study/server/StudyControllerDynamicSimulationTest.java
  • src/test/java/org/gridsuite/study/server/StudyServiceTest.java
  • src/test/java/org/gridsuite/study/server/VoltageInitTest.java
  • src/test/java/org/gridsuite/study/server/dto/OperationTypeTest.java
  • src/test/java/org/gridsuite/study/server/rootnetworks/ModificationToExcludeTest.java
  • src/test/java/org/gridsuite/study/server/service/StudyServiceDynamicSimulationTest.java
  • src/test/java/org/gridsuite/study/server/service/UserAdminServiceTest.java
  • src/test/java/org/gridsuite/study/server/utils/TestUtils.java
  • src/test/java/org/gridsuite/study/server/utils/wiremock/UserAdminServerStubs.java
  • src/test/resources/application-default.yml

@GhilesA GhilesA changed the title WIP: feat: add computation quotas check feat: add computation quotas check Jul 7, 2026
@GhilesA GhilesA requested review from EtienneLt and etiennehomer July 7, 2026 14:15
@GhilesA GhilesA force-pushed the feat/add_quotas_on_computation branch 2 times, most recently from e8a8de9 to 4de5dc8 Compare July 7, 2026 14:51
feat: fix tests
feat: add test
@GhilesA GhilesA force-pushed the feat/add_quotas_on_computation branch from 4de5dc8 to b4accf1 Compare July 8, 2026 09:00
@sonarqubecloud

Copy link
Copy Markdown

@etiennehomer etiennehomer left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not enough time to test and to review UT
But i'm ok with the global design

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

author

import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

author

private final ComputationParametersService computationParametersService;
private final UserAdminService userAdminService;

public ConsumerService(ObjectMapper objectMapper,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no indentation changes in the class plz

notificationService.emitComputationDebugFileStatus(studyUuid, receiverObj.getNodeUuid(), receiverObj.getRootNetworkUuid(), computationType, userId, resultUuid, errorMessage);
}));
// free quota
if (userId != null) {

@etiennehomer etiennehomer Jul 10, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In debug mode, at the end of the computation, you'll receive 2 notifications :

  • the classic one that says that the computation is done
  • the one that said that the debug zip is ready for download.
    So you should not endOperationWithQuota() in consumeCalculationDebug(). That would free twice

private final StudyService self;

@Value("${study.enable-operation-quotas}")
private boolean shouldCheckOperationQuotas = true;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default value in the application.yaml is enough ?

new LoadFlowService.ParametersInfos(lfParametersUuid, withRatioTapChangers, isSecurityNode), lfReportUuid, userId);
rootNetworkNodeInfoService.updateLoadflowResultUuid(nodeUuid, rootNetworkUuid, result, withRatioTapChangers);

userAdminService.startOperationWithQuota(userId, OperationType.mapFromComputationType(LOAD_FLOW), result);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we keep the startOperationWithQuota() in StudyService and not LoadflowService.runLoadflow() ?
This would allow to write some code that call runLoadflow() and do not call startOperationWithQuota()
But maybe StudyService is fine

notificationService.emitRootNetworksUpdated(studyUuid);
}

public void assertOnQuotasAvailability(ComputationType computationType, String userId) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method could be just a call to a user-admin-server endpoint that returns true/false (computation allowed or not)
But you did this in anticipation of the coming front giving the quota information to the users ? Makes sense in that case

DYNAMIC_SECURITY,
DYNAMIC_MARGIN;

public static OperationType mapFromComputationType(ComputationType computationType) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

keep same enum labels between ComputationType and OperationType

/**
* @author Ghiles Abdellah {@literal <ghiles.abdellah at rte-france.com>}
*/
public enum OperationType {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

QuotaType ? Another name ?
Because cases and builds are not operation. They static stuff staying in the system

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And is it ok to use the same enum for elements that have quotas but different nature (number of LF at the same time VS number of cases stored in the system)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants