Add support for system-level mutation mode for zero-downtime migration#42
Add support for system-level mutation mode for zero-downtime migration#42
Conversation
Introduce `globalMutationMode` in `GraphConfig` to enable configuration of mutation processing modes. Updated tests to verify ASYNC mutation mode behavior.
Introduce `MutationMode` to handle synchronous and asynchronous mutation processing. Extend test fixtures and services to validate mutation behavior in both modes.
Extend test fixtures to include multi-edge schema creation and DDL operations for both sync and async modes. Update tests to validate multi-edge mutation behavior.
Introduce `globalMutationMode` in `Graph` to globally define mutation processing mode. Update mutation services to respect `globalMutationMode` and fallback to sync when unspecified. Revise tests to validate behavior for ASYNC and sync scenarios.
Remove redundant type arguments in readValue calls and simplify property initialization by eliminating explicit nullable type declaration.
Add unit tests to validate behavior when globalMutationMode is set to SYNC, ensuring synchronous processing overrides label-specific async configurations for both single-edge and multi-edge mutations.
Introduce `globalMutationMode` property to `GraphProperties` for configuring mutation processing modes. Update `GraphConfiguration` to apply global mutation mode settings when provided.
|
@em3s please review this PR! |
|
@eazyhozy nice work! Quick review:
|
|
@em3s Thanks for a quick feedback. I updated the description above.
|
|
Reformatted per #62 via |
|
The primary goal of this PR (#41) is to introduce a new configuration that can override table-level Key Principles
Current vs. Proposed BehaviorCurrently, the behavior is defined as follows(according to
By introducing
(Note: Request level remains the highest priority to ensure synchronous processing for dedicated paths like external async processors.) Feedback Requested
|
…riority Update `MutationModeContext` to handle global mutation modes along with request-specific overrides, ensuring priority order is request > global > label. Add comprehensive test coverage for various combinations of mutation modes and scenarios.
Update method signatures in mutation services to rename the `sync` parameter to `mode` for improved clarity and consistency. Adjust related controller and test references accordingly.
…vice Simplify variable naming for improved readability and consistency within mutation services. Adjust related references accordingly.
Eliminate multi-edge schema and related DDL operations from test fixtures as they are no longer used. Simplify tests and improve maintainability.
Simplify method signature by providing a default value for the `configBuilder` parameter in the `create` method. Improves usability and reduces redundancy.
Eliminate the unused `MutationMode` parameter in test fixture methods and related calls. Simplifies method signatures and improves code clarity.
|
@dosu plz summarize the file changes. |
|
Created changelog: https://app.dosu.dev/documents/2e3e62c0-3fd1-40d5-bbaf-1f1fb41d04c2 To reply, just mention @dosu. How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other |
…ncerns Rewrite V3MutationServiceGlobalAsyncSpec with 6 tests covering 3 scenarios (global overrides table, global overrides request, internal overrides global) x 2 table types (EDGE, MULTI_EDGE). Simplify verifyWal to only check queue flag, since MutationModeContext logic is fully covered by MutationModeContextSpec. Remove internal mode tests from V3MutationServiceSpec and V3MutationServiceAsyncSpec as they now belong in GlobalAsyncSpec.
# Conflicts: # engine/src/main/kotlin/com/kakao/actionbase/v2/engine/v3/V3MutationService.kt
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Port globalMutationMode and internal mode concepts to the new MutationEngine/MutationService architecture introduced in main. - Extend engine MutationModeContext with global/internal fields - Add globalMutationMode to MutationEngine interface - Add internalMutate() API to MutationService - Add /internal/sync endpoints to Edge/MultiEdge controllers - Migrate GlobalAsyncSpec tests to new MutationService API Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move global/internal precedence matrix tests from v2 package (MutationModeContextSpec) to engine package (MutationModeContextTest) to align with main's refactored structure. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds of(table, request) convenience overload that delegates to the 4-arg factory with global=null and internal=null, matching the engine package's MutationModeContext API. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…e coverage Remove comprehensive test and merge overlapping cases into focused tests. Reorganize OfWithSystemAndForceTest from 24 to 13 cases while maintaining full matrix coverage. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ontext Rename globalMutationMode to systemMutationMode and replace internal MutationMode parameter with boolean force flag. This changes the priority model from "internal > global > request > label" to "request(force=true) > system > request(force=false) > label". Remove separate internalMutate methods from Graph and MutationService, consolidating into a single mutate method with a force parameter. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
engine/src/main/kotlin/com/kakao/actionbase/engine/service/MutationService.kt
Outdated
Show resolved
Hide resolved
engine/src/main/kotlin/com/kakao/actionbase/v2/engine/metadata/MutationModeContext.kt
Outdated
Show resolved
Hide resolved
engine/src/main/kotlin/com/kakao/actionbase/engine/metadata/MutationModeContext.kt
Outdated
Show resolved
Hide resolved
engine/src/main/kotlin/com/kakao/actionbase/v2/engine/metadata/MutationModeContext.kt
Outdated
Show resolved
Hide resolved
engine/src/main/kotlin/com/kakao/actionbase/engine/metadata/MutationModeContext.kt
Outdated
Show resolved
Hide resolved
engine/src/test/kotlin/com/kakao/actionbase/engine/metadata/MutationModeContextTest.kt
Show resolved
Hide resolved
engine/src/test/kotlin/com/kakao/actionbase/engine/metadata/MutationModeContextTest.kt
Show resolved
Hide resolved
Reorder KDoc to place queue formula after constraints, rename isSyncOnIgnoreTable to isSyncRequestOnIgnoreTable for clarity, and reorder test parameters to match (label, request, system, queue). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove dedicated /internal/sync endpoints from EdgeMutationController and MultiEdgeMutationController. Add force query parameter to existing /sync endpoints to achieve the same behavior. Rename MutationService.force to forceSyncMode for clarity. Add E2E tests verifying /sync?force=true overrides system=ASYNC. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The priority rule and matrix table already convey the resolution logic.
Remove redundant mode = when { ... } block per self-review.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…nModeContextTest Reorder YAML fields from (label, system, request, queue) to (label, request, system, queue) to match function parameter order. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ypass The merge from main dropped the force parameter from Graph.mutate(), causing DdlService compilation failures. Restore the parameter and pass systemMutationMode and force to MutationModeContext.of(). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…Engine Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
c2c10b9 to
7eee1f7
Compare
|
LGTM 👍 |
Summary
This PR implements support for a
system-mutation-modeconfiguration. This allows operators to enforce a specific mutation mode (SYNC or ASYNC) across the entire graph instance, overriding individual label settings.A
forcequery parameter on the existing/syncendpoint allows internal systems (e.g., Async Processor) to bypass the system override and maintain synchronous processing guarantees.Closes #41
Design
Before (Request > Table)
After (Request(force) > System > Request > Table)
Design Background
The
/syncendpoint is currently used by both internal systems (Async Processor) and external services. A simpleSystem > Request > Tablehierarchy would silently override external/syncrequests whenSystem=ASYNCis set. Theforceparameter solves this by allowing callers to explicitly opt out of the system override when needed.Use Case: Zero-Downtime HBase Cluster Migration
system-mutation-mode=ASYNC→ All requests are queued to Kafka/sync?force=true(bypasses System)Changes
globalMutationModetosystemMutationModeinGraphPropertiesandGraphConfig.internalMutatemethods fromGraphandMutationService.mutatemethod withforceSyncMode: Booleanparameter./internal/syncendpoints; addedforcequery parameter to existing/syncendpoints.global/internalparameters withsystem/force..of()factory method.request(force=true) > system > request(force=false) > table.forceSyncMode=trueinternally to maintain synchronous guarantees.Files Changed
Engine (main)
MutationEngine.kt— RenamedglobalMutationModetosystemMutationModeMutationModeContext.kt(engine + v2) — Replacedglobal/internalwithsystem/force; private constructor +.of()factoryMutationService.kt— Consolidatedmutate/internalMutateinto singlemutatewithforceSyncModeGraph.kt— Renamed property; consolidated mutate APIsGraphConfig.kt— Renamed config property and builder methodDdlService.kt— Changed frominternalMutatetomutate(..., forceSyncMode=true)KafkaProducer.kt,WalLog.kt,V2BackedEngine.kt,V2BackedMessageBinding.kt— Minor adjustmentsServer (main)
GraphProperties.kt— Renamed tosystemMutationModeGraphConfiguration.kt— WiredsystemMutationModeintoGraphConfig.BuilderEdgeMutationController.kt— Removed/internal/sync; addedforceparam to/syncMultiEdgeMutationController.kt— SameTests
MutationModeContextTest.kt— Full precedence matrix coverage (25 cases)MutationServiceSystemAsyncSpec.kt— system=ASYNC override + force=true bypass testsEdgeMutationForceSyncTest.kt— E2E tests for/sync?force=trueDdlServiceSpec.kt— VerifiedsystemMutationModedoes not affect DDLStartUpTest.kt— Verified server initialization with system mutation modeHow to Test
Configuration
Add the following to your
application.yaml. This configuration is optional and can be omitted to continue using label-specific settings.Verification
During local execution, check the initialization logs:
$ ./gradlew server:bootRun ... com.kakao.actionbase.v2.engine.Graph : graph initialized with config: GraphConfig(..., systemMutationMode=ASYNC)Force Sync
The Async Processor uses the
forceparameter to bypass the system override:POST /graph/v3/databases/{database}/tables/{table}/edges/sync?force=true POST /graph/v3/databases/{database}/tables/{table}/multi-edges/sync?force=trueDDL operations are also unaffected — they invoke
mutate(..., forceSyncMode=true)directly.Further TODO
/edges/asyncorsyncModequery parameter) so callers can explicitly request ASYNC processing.