chore: remove storage from REST - #2530
Conversation
22c0f7d to
1f33d50
Compare
winklerm
left a comment
There was a problem hiding this comment.
Thank you, looks much better, the API is clearly defined - love that!
1f33d50 to
953f87c
Compare
|
@LDWNS the failing downstream ESS is caused by assignability analysis using the storage service, which is being removed from the REST endpoint by this PR. Options:
|
|
The code coverage is still below the standards, but this PR actually increases it for the solver-worker module. |
There was a problem hiding this comment.
Pull request overview
This PR decouples the REST layer from direct storage/messaging usage by introducing a SolverWorkerFacade abstraction that orchestrates storage operations and solver-worker lifecycle events/commands, and updates Quarkus resource generation accordingly.
Changes:
- Introduce
SolverWorkerFacade(interface) andDefaultSolverWorkerFacade(implementation) to centralize dataset lifecycle orchestration (create/derive/patch/solve/terminate/logs). - Refactor REST resources and Quarkus-generated resource constructor signatures to depend on
SolverWorkerFacadeinstead of storage + channel emitters. - Add unit tests and test utilities for the new facade, and update dependencies to include the JSON patch module.
Reviewed changes
Copilot reviewed 25 out of 25 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| service/worker/src/test/java/ai/timefold/solver/service/worker/impl/testutil/RecordingMutinyEmitter.java | Adds a test emitter that records Mutiny payloads for facade unit tests. |
| service/worker/src/test/java/ai/timefold/solver/service/worker/impl/testutil/RecordingEmitter.java | Adds a test emitter that records reactive-messaging payloads for facade unit tests. |
| service/worker/src/test/java/ai/timefold/solver/service/worker/impl/testdata/TestdataStorageService.java | Provides a real AbstractStorageService implementation for worker facade tests. |
| service/worker/src/test/java/ai/timefold/solver/service/worker/impl/testdata/TestdataStorage.java | Adds an in-memory Storage implementation to avoid mocked storage in tests. |
| service/worker/src/test/java/ai/timefold/solver/service/worker/impl/testdata/TestdataModelOutputMetrics.java | Minimal test model output metrics type for storage/facade tests. |
| service/worker/src/test/java/ai/timefold/solver/service/worker/impl/testdata/TestdataModelOutput.java | Minimal test model output type for storage/facade tests. |
| service/worker/src/test/java/ai/timefold/solver/service/worker/impl/testdata/TestdataModelInputMetrics.java | Minimal test model input metrics type for storage/facade tests. |
| service/worker/src/test/java/ai/timefold/solver/service/worker/impl/testdata/TestdataModelInput.java | Minimal test model input with equality for asserting storage writes in tests. |
| service/worker/src/test/java/ai/timefold/solver/service/worker/impl/testdata/TestdataModelConstraintJustification.java | Minimal constraint justification type for the generic storage service. |
| service/worker/src/test/java/ai/timefold/solver/service/worker/impl/testdata/TestdataModelConfigOverrides.java | Minimal config overrides type used by the test storage service. |
| service/worker/src/test/java/ai/timefold/solver/service/worker/impl/DefaultSolverWorkerFacadeTest.java | Adds unit tests validating facade orchestration and persistence behavior. |
| service/worker/src/main/java/ai/timefold/solver/service/worker/impl/DefaultSolverWorkerFacade.java | New worker-side implementation coordinating storage with lifecycle events/commands. |
| service/worker/pom.xml | Adjusts worker dependencies to include the JSON patch module and Jackson support. |
| service/test-model/src/test/java/ai/timefold/solver/model/testmodel/EmployeeScheduleResourceTest.java | Fixes import location for OperationOnPost after package reorganization. |
| service/rest/src/main/java/ai/timefold/solver/service/rest/impl/AbstractModelAPIResource.java | Refactors REST endpoints to delegate lifecycle operations to SolverWorkerFacade. |
| service/rest/src/main/java/ai/timefold/solver/service/rest/api/ModelRest.java | Removes REST extension hook exposing storage directly. |
| service/quarkus/deployment/src/main/java/ai/timefold/solver/service/quarkus/deployment/rest/ModelResourceWithMapsTypeInfo.java | Updates generated resource constructor signature to inject SolverWorkerFacade. |
| service/quarkus/deployment/src/main/java/ai/timefold/solver/service/quarkus/deployment/rest/ModelResourceTypeInfo.java | Removes channel-annotation plumbing now that emitters are no longer injected. |
| service/quarkus/deployment/src/main/java/ai/timefold/solver/service/quarkus/deployment/rest/ModelResourceBeanGenerator.java | Updates generation logic (and example) to align with new constructor signatures. |
| service/quarkus/deployment/src/main/java/ai/timefold/solver/service/quarkus/deployment/rest/EnterpriseModelResourceWithMapsTypeInfo.java | Updates enterprise generated resource constructor signature to inject SolverWorkerFacade. |
| service/quarkus/deployment/src/main/java/ai/timefold/solver/service/quarkus/deployment/rest/EnterpriseModelResourceTypeInfo.java | Updates enterprise generated resource constructor signature to inject SolverWorkerFacade. |
| service/quarkus/deployment/src/main/java/ai/timefold/solver/service/quarkus/deployment/rest/DefaultModelResourceTypeInfo.java | Updates default generated resource constructor signature to inject SolverWorkerFacade. |
| service/maps/service-rest/src/main/java/ai/timefold/solver/service/maps/service/rest/impl/AbstractMapsModelAPIResource.java | Aligns maps REST resource constructor to the new SolverWorkerFacade injection model. |
| service/json/src/main/java/ai/timefold/solver/service/json/internal/patch/JsonPatch.java | Minor cleanup using isEmpty() and String.isEmpty() in patch logic. |
| service/definition/src/main/java/ai/timefold/solver/service/definition/impl/solver/SolverWorkerFacade.java | Adds the new facade interface used by REST and implemented by the worker. |
Comments suppressed due to low confidence (2)
service/definition/src/main/java/ai/timefold/solver/service/definition/impl/solver/SolverWorkerFacade.java:129
- The terminate(..) Javadoc has
@paramand@returnon the same line, which can cause Javadoc generation to fail with failOnError=true.
/**
* Terminates the ongoing solve for the given dataset (if any) and returns the current model response
*
* @param id the dataset identifier * @return the {@link ModelResponse} for the dataset after termination
*/
service/definition/src/main/java/ai/timefold/solver/service/definition/impl/solver/SolverWorkerFacade.java:163
- The getModelInput(..) Javadoc block contains stray '*' characters and inline tags that can break Javadoc generation when failOnError=true.
/**
* * Returns the {@link ModelInput} originally submitted for the given dataset. * * @param id the dataset identifier
* * @return the model input, or {@code null} if not found
*/
1caab2e to
6da485d
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 25 out of 25 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (1)
service/worker/src/main/java/ai/timefold/solver/service/worker/impl/DefaultSolverWorkerFacade.java:296
- createPatchedDataset(...) can throw a NullPointerException if the parent metadata is missing even when the parent input exists, so handle parentRun==null consistently with the earlier not-found checks.
metadata.setParentId(id);
// set origin id based on the origin id of the parent data set
Metadata parentRun = getMetadata(id);
metadata.setOriginId(parentRun.getOriginId());
metadata.datasetCreated();
6da485d to
2d8e7ce
Compare
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 25 out of 25 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (1)
service/definition/src/main/java/ai/timefold/solver/service/definition/impl/solver/SolverWorkerFacade.java:37
- The Javadoc for createDataset(String, DatasetSelector, ...) has an extra
/**line that makes the comment malformed and can fail the build under strict Javadoc settings; remove the stray/**and keep a single Javadoc block.
/**
/**
* Creates a new dataset derived from an existing one (identified by {@code id}) without starting the solving process.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 25 out of 25 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (4)
service/definition/src/main/java/ai/timefold/solver/service/definition/impl/solver/SolverWorkerFacade.java:38
- The Javadoc contains an accidental nested
/**line which produces broken documentation output and may trigger doclint failures; remove the extra* /**line so the block starts directly with the description.
/**
* /**
* Creates a new dataset derived from an existing one (identified by {@code id}) without starting the solving process.
* The resulting dataset is validated and computed asynchronously.
service/definition/src/main/java/ai/timefold/solver/service/definition/impl/solver/SolverWorkerFacade.java:178
- The
getSolvedModelInputJavadoc is duplicated and includes a stray/**line which can cause Javadoc generation warnings/errors; keep a single Javadoc block without the duplicate fragment.
/**
* Returns the {@link ModelInput} representing the solved state of the given dataset (i.e. planning entities updated
* with the best solution).
*
* /**
* Returns the {@link ModelInput} representing the solved state of the given dataset (i.e. planning entities updated
* with the best solution).
*
service/worker/src/main/java/ai/timefold/solver/service/worker/impl/DefaultSolverWorkerFacade.java:261
parentRunis dereferenced without a null-check, so a partial/failedstoreProblemwrite (input present but metadata missing) would cause an NPE; throwItemNotFoundExceptionwhengetMetadata(id)returns null.
// set origin id based on the origin id of the parent data set
Metadata parentRun = getMetadata(id);
metadata.setOriginId(parentRun.getOriginId());
service/worker/src/main/java/ai/timefold/solver/service/worker/impl/DefaultSolverWorkerFacade.java:296
parentRunis dereferenced without a null-check, so inconsistent storage state could crash patching with an NPE; throwItemNotFoundExceptionwhengetMetadata(id)returns null before usinggetOriginId().
// set origin id based on the origin id of the parent data set
Metadata parentRun = getMetadata(id);
metadata.setOriginId(parentRun.getOriginId());
metadata.datasetCreated();
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 25 out of 25 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (1)
service/rest/src/main/java/ai/timefold/solver/service/rest/impl/AbstractModelAPIResource.java:281
fromPatch()allows an empty/null request body via@Validated(nullable = true, ...)but then dereferencespatchRequestthroughsolverWorkerFacade.*, which can cause a NullPointerException at runtime; make the body non-nullable by removingnullable = true(or add an explicit null check and return 400).
@Validated(nullable = true,
operationId = OperationId.FROM_PATCH) ModelInputPatchRequest<ModelConfigurationOverrides_> patchRequest) {
|


Fixes https://github.com/TimefoldAI/timefold-solver-enterprise/issues/591.
SolverWorkerFacadeSolverWorkerFacadeis now unit-testedfrom-patchused to catchIllegalStateException, but the patching utils throwIllegalArgumentException