The keycloak project ended with four open questions that design could not
settle. A two-VM lab was built to answer them by measurement, and this is
that material: 26 experiments, 125 raw command outputs, 22 browser captures.
Follows the import procedure in README.md.
source/ the originating repository verbatim — 78 documents, 28 SVGs,
8 manifests, plus .source-revision recording the commit
final/ the SSOT
document.md 729 lines written from the 29 experiment documents, not
concatenated: what was predicted, what was measured, and
where the measurement itself was wrong
evidence/raw 125 outputs, flattened to <experiment>__<file> because
the originals collided (01-baseline.txt appeared three
times) and the audit only globs the top level
evidence/meta one per raw file; command and exitCode are null and the
README says why rather than inventing them
evidence/browser 22 captures
assets/ three diagrams through techviz
.techviz/ their VizSpecs
A separate project rather than an addition to keycloak: the B-layer answers
that project's four questions, but the A, C and D layers are about cluster
failure, SSO and operations, and one document.md should hold one subject.
The four question records there can point here through 관계.
Recorded rather than papered over: only three of the 28 diagrams were
remade. The repository forbids hand-drawn SVG and forbids titles inside the
canvas; all 28 originals carry both, so converting them is redrawing, not
reformatting. They stay in source/ and the gap is written into the document.
verify-pipeline.py passes. audit-records.py reports no issues.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
249 lines
22 KiB
Plaintext
249 lines
22 KiB
Plaintext
Sub-scope 08 (mongo) changestream - manifest and negative-space probes
|
|
revision=a24ece9cf797f7ea647e33bf846b115208ed1ba5
|
|
generatedAt=2026-08-30T00:15:09+00:00
|
|
cwd=/shared/codebase/clean-architecture-backend-template/src
|
|
|
|
=== OWNED FILES ===
|
|
55410c37d99e15fd487d45057a2f44fe2b656582 main/java/dev/caskeleton/adapter/outbound/mongo/changestream/MongoChangeEventIdentity.java 97
|
|
2a41c567b37fd2cd0f7adcbd0cf1db3583f020bc main/java/dev/caskeleton/adapter/outbound/mongo/changestream/MongoChangeStreamPipeline.java 85
|
|
462398af539336129b4a1f0cf669a94eb0c52120 main/java/dev/caskeleton/adapter/outbound/mongo/changestream/MongoChangeStreamState.java 35
|
|
d6a137168ebf884948907dc09a86833bc68a1983 main/java/dev/caskeleton/adapter/outbound/mongo/changestream/MongoChangeStreamSubscription.java 50
|
|
b9cb4a344e54678c7c02fc48e71851fc2e84e79c main/java/dev/caskeleton/adapter/outbound/mongo/changestream/MongoClusterTime.java 53
|
|
240d41177c0bf08b810928ed61dbdd07874b4a43 main/java/dev/caskeleton/adapter/outbound/mongo/changestream/MongoResumeCheckpoint.java 100
|
|
ccac8af549c5ed7b23ed3be2fa1ad68cc1ef5f48 main/java/dev/caskeleton/adapter/outbound/mongo/changestream/MongoResumeCheckpointStore.java 24
|
|
22ee8f0391d93b109f3ffa763f1a2acc03564de8 main/java/dev/caskeleton/adapter/outbound/mongo/changestream/MongoResumePosition.java 18
|
|
52b776c4178d40bae2e7b48cfcff2207c25cc3ab main/java/dev/caskeleton/adapter/outbound/mongo/changestream/MongoResumeTokenCodec.java 38
|
|
76e710168870ef9d9e8a464dba087e247315ccff main/java/dev/caskeleton/adapter/outbound/mongo/changestream/consumer/MongoChangeStreamSource.java 54
|
|
5d2c65139d86fefc8f341a120dd3abdff345f368 main/java/dev/caskeleton/adapter/outbound/mongo/changestream/consumer/ReactiveMongoChangeStreamConsumer.java 221
|
|
6d2bd659cc831094d7854fcfc4560846ff03927a main/java/dev/caskeleton/adapter/outbound/mongo/changestream/consumer/SpringReactiveChangeStreamSource.java 71
|
|
8a7ba018966876acb9c64b9e7906ba11407f0c44 main/java/dev/caskeleton/adapter/outbound/mongo/changestream/projector/MongoChangeClaim.java 25
|
|
43032013612390ba42527cfa06d5c74f47409a42 main/java/dev/caskeleton/adapter/outbound/mongo/changestream/projector/MongoChangeDeduplicationStore.java 50
|
|
ba15c66e206050463073a2c373e88936d6ec6f36 main/java/dev/caskeleton/adapter/outbound/mongo/changestream/projector/MongoChangeProjectionResult.java 65
|
|
75e656da9f039e0124dee52b0e4b55555429c943 main/java/dev/caskeleton/adapter/outbound/mongo/changestream/projector/MongoChangeProjector.java 23
|
|
8a49dd99ecf66f528ddba3f17c38f5594d3dc3d4 main/java/dev/caskeleton/adapter/outbound/mongo/changestream/projector/MongoChangeStreamRunner.java 124
|
|
a956f31fd1f2779fc1063cfd1407ab098f65bb82 main/java/dev/caskeleton/adapter/outbound/mongo/changestream/recovery/MongoChangeHistoryLostException.java 35
|
|
8b02975c382f8df615b19260076554c64aaabf66 main/java/dev/caskeleton/adapter/outbound/mongo/changestream/recovery/MongoChangeStreamRecoveryDecision.java 36
|
|
fe947e6c533518c9560650b808cc29b1b0e23ae6 main/java/dev/caskeleton/adapter/outbound/mongo/changestream/recovery/MongoChangeStreamRecoveryPolicy.java 67
|
|
88ca505e553bf03721e270d95cf43de6446f5406 main/java/dev/caskeleton/adapter/outbound/mongo/changestream/recovery/MongoInvalidateRecovery.java 46
|
|
c51cc24680d0b2cd33c18ca36d4c87f6518287b8 test/java/dev/caskeleton/adapter/outbound/mongo/changestream/MongoChangeStreamPipelineTest.java 153
|
|
60a0312b904e8b8ecee216bc84942c2ce8fbe4cc test/java/dev/caskeleton/adapter/outbound/mongo/changestream/MongoResumeCheckpointStoreTest.java 85
|
|
a9c7b48469df8438d48ae3edfce562c692c99ab8 test/java/dev/caskeleton/adapter/outbound/mongo/changestream/consumer/ChangeStreamConsumerLifecycleTest.java 332
|
|
39c83409212c07edc25c72849e35a3488d3fe7df test/java/dev/caskeleton/adapter/outbound/mongo/changestream/projector/MongoChangeStreamRunnerTest.java 357
|
|
d20e9e4712dae2642af4308eda984f84ff0ce8b0 test/java/dev/caskeleton/adapter/outbound/mongo/changestream/recovery/MongoChangeStreamRecoveryPolicyTest.java 69
|
|
|
|
production: 21
|
|
test: 5
|
|
production LOC: 1317 total
|
|
|
|
=== 8.1 reachability: beans and cross-package production references ===
|
|
$ grep -n 'ChangeStream\|changestream\|Projector\|Resume' adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/autoconfigure/MongoPlatformAutoConfiguration.java
|
|
209: public dev.caskeleton.adapter.outbound.mongo.changestream.consumer.MongoChangeStreamSource
|
|
210: mongoChangeStreamSource(
|
|
213: return new dev.caskeleton.adapter.outbound.mongo.changestream.consumer
|
|
214: .SpringReactiveChangeStreamSource(template, collections);
|
|
228: dev.caskeleton.adapter.outbound.mongo.changestream.MongoChangeStreamSubscription.class,
|
|
229: dev.caskeleton.adapter.outbound.mongo.changestream.MongoResumeCheckpointStore.class,
|
|
230: dev.caskeleton.adapter.outbound.mongo.changestream.MongoResumeTokenCodec.class,
|
|
231: dev.caskeleton.adapter.outbound.mongo.changestream.projector.MongoChangeProjector.class,
|
|
232: dev.caskeleton.adapter.outbound.mongo.changestream.projector.MongoChangeDeduplicationStore
|
|
235: public dev.caskeleton.adapter.outbound.mongo.changestream.consumer
|
|
236: .ReactiveMongoChangeStreamConsumer
|
|
237: reactiveMongoChangeStreamConsumer(
|
|
238: dev.caskeleton.adapter.outbound.mongo.changestream.MongoChangeStreamSubscription
|
|
240: dev.caskeleton.adapter.outbound.mongo.changestream.consumer.MongoChangeStreamSource
|
|
242: dev.caskeleton.adapter.outbound.mongo.changestream.MongoResumeCheckpointStore
|
|
244: dev.caskeleton.adapter.outbound.mongo.changestream.MongoResumeTokenCodec tokens,
|
|
245: dev.caskeleton.adapter.outbound.mongo.changestream.projector.MongoChangeProjector
|
|
247: dev.caskeleton.adapter.outbound.mongo.changestream.projector
|
|
250: return new dev.caskeleton.adapter.outbound.mongo.changestream.consumer
|
|
251: .ReactiveMongoChangeStreamConsumer(
|
|
256: new dev.caskeleton.adapter.outbound.mongo.changestream.MongoChangeStreamPipeline(
|
|
257: new dev.caskeleton.adapter.outbound.mongo.changestream.projector
|
|
258: .MongoChangeStreamRunner(projector, deduplication, checkpoints)),
|
|
259: new dev.caskeleton.adapter.outbound.mongo.changestream.recovery
|
|
260: .MongoChangeStreamRecoveryPolicy(),
|
|
261: new dev.caskeleton.adapter.outbound.mongo.changestream.recovery
|
|
exit=0
|
|
|
|
$ git grep -n 'changeStreams' adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/autoconfigure/MongoPlatformSettings.java adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/autoconfigure/MongoPlatformAutoConfiguration.java adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/autoconfigure/MongoStartupValidator.java
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/autoconfigure/MongoPlatformAutoConfiguration.java:363: properties.changeStreams(),
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/autoconfigure/MongoPlatformSettings.java:22: * assuming it. Both it and {@code changeStreams} used to be literal {@code true}s passed into
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/autoconfigure/MongoPlatformSettings.java:30: boolean changeStreams,
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/autoconfigure/MongoPlatformSettings.java:55: changeStreams = false;
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/autoconfigure/MongoStartupValidator.java:34: private final boolean changeStreamsEnabled;
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/autoconfigure/MongoStartupValidator.java:44: boolean changeStreamsEnabled,
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/autoconfigure/MongoStartupValidator.java:51: this.changeStreamsEnabled = changeStreamsEnabled;
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/autoconfigure/MongoStartupValidator.java:104: if (changeStreamsEnabled && !capabilities.isStable(MongoCapability.CHANGE_STREAM)) {
|
|
exit=0
|
|
|
|
$ git grep -ln 'changestream' -- 'adapter/outbound/persistence-mongo/src/main' | grep -v '/changestream/'
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/advanced/bridge/MongoChangeMessagingBridge.java
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/advanced/bridge/MongoChangeToIntegrationEventMapper.java
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/autoconfigure/MongoPlatformAutoConfiguration.java
|
|
exit=0
|
|
|
|
$ git grep -n 'new ReactiveMongoChangeStreamConsumer\|new SpringReactiveChangeStreamSource\|new MongoChangeStreamPipeline\|new MongoChangeStreamRunner' -- 'adapter/outbound/persistence-mongo/src/main'
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/changestream/consumer/ReactiveMongoChangeStreamConsumer.java:145: new MongoChangeStreamPipeline.MongoChangeEvent(
|
|
exit=0
|
|
|
|
=== 8.1b implementations of the three SPIs a deployment must supply ===
|
|
$ git grep -n 'implements MongoResumeTokenCodec\|implements MongoResumeCheckpointStore\|implements MongoChangeDeduplicationStore\|implements MongoChangeProjector' -- 'adapter/outbound/persistence-mongo/src'
|
|
adapter/outbound/persistence-mongo/src/test/java/dev/caskeleton/adapter/outbound/mongo/advanced/bridge/MongoChangeMessagingBridgeTest.java:115: private static final class CountingCheckpointStore implements MongoResumeCheckpointStore {
|
|
adapter/outbound/persistence-mongo/src/test/java/dev/caskeleton/adapter/outbound/mongo/changestream/MongoChangeStreamPipelineTest.java:117: private static final class AlwaysClaims implements MongoChangeDeduplicationStore {
|
|
adapter/outbound/persistence-mongo/src/test/java/dev/caskeleton/adapter/outbound/mongo/changestream/MongoChangeStreamPipelineTest.java:136: private static final class NoOpCheckpoints implements MongoResumeCheckpointStore {
|
|
adapter/outbound/persistence-mongo/src/test/java/dev/caskeleton/adapter/outbound/mongo/changestream/consumer/ChangeStreamConsumerLifecycleTest.java:211: private static final class PlainTextCodec implements MongoResumeTokenCodec {
|
|
adapter/outbound/persistence-mongo/src/test/java/dev/caskeleton/adapter/outbound/mongo/changestream/consumer/ChangeStreamConsumerLifecycleTest.java:261: private static final class RecordingCheckpointStore implements MongoResumeCheckpointStore {
|
|
adapter/outbound/persistence-mongo/src/test/java/dev/caskeleton/adapter/outbound/mongo/changestream/consumer/ChangeStreamConsumerLifecycleTest.java:295: private final class CountingProjector implements MongoChangeProjector {
|
|
adapter/outbound/persistence-mongo/src/test/java/dev/caskeleton/adapter/outbound/mongo/changestream/consumer/ChangeStreamConsumerLifecycleTest.java:314: private static final class AlwaysClaims implements MongoChangeDeduplicationStore {
|
|
adapter/outbound/persistence-mongo/src/test/java/dev/caskeleton/adapter/outbound/mongo/changestream/projector/MongoChangeStreamRunnerTest.java:101: private static final class RecordingCheckpointStore implements MongoResumeCheckpointStore {
|
|
adapter/outbound/persistence-mongo/src/test/java/dev/caskeleton/adapter/outbound/mongo/changestream/projector/MongoChangeStreamRunnerTest.java:290: private static final class ClaimingDeduplicationStore implements MongoChangeDeduplicationStore {
|
|
adapter/outbound/persistence-mongo/src/test/java/dev/caskeleton/adapter/outbound/mongo/changestream/projector/MongoChangeStreamRunnerTest.java:339: private static final class EmptyDeduplicationStore implements MongoChangeDeduplicationStore {
|
|
exit=0
|
|
|
|
=== 8.2 the high-water mark: set before processing, kept across a resume ===
|
|
$ grep -n 'advancesPosition\|getAndAccumulate\|highWaterMark' adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/MongoChangeStreamPipeline.java 2>/dev/null || grep -n 'advancesPosition\|getAndAccumulate\|highWaterMark' adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/changestream/MongoChangeStreamPipeline.java
|
|
32: private final AtomicReference<MongoClusterTime> highWaterMark = new AtomicReference<>();
|
|
49: if (!advancesPosition(event.clusterTime())) {
|
|
58: private boolean advancesPosition(MongoClusterTime candidate) {
|
|
60: highWaterMark.getAndAccumulate(
|
|
67: public MongoClusterTime highWaterMark() {
|
|
68: return highWaterMark.get();
|
|
exit=0
|
|
|
|
$ grep -n 'allowsCheckpointAdvance' -B 8 adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/changestream/projector/MongoChangeProjectionResult.java
|
|
38- }
|
|
39-
|
|
40- /** The event could not be interpreted and was routed to the parking workflow. */
|
|
41- public static MongoChangeProjectionResult parked(String reason) {
|
|
42- return new MongoChangeProjectionResult(Outcome.PARKED, reason);
|
|
43- }
|
|
44-
|
|
45- /** True when the checkpoint may advance past this event. */
|
|
46: public boolean allowsCheckpointAdvance() {
|
|
exit=0
|
|
|
|
$ grep -n 'recoverFrom\|openAndConsume\|Flux.defer' adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/changestream/consumer/ReactiveMongoChangeStreamConsumer.java
|
|
87: .thenMany(Flux.defer(this::openAndConsume))
|
|
88: .onErrorResume(this::recoverFrom);
|
|
101: private Flux<MongoChangeProjectionResult> openAndConsume() {
|
|
188: private Flux<MongoChangeProjectionResult> recoverFrom(Throwable failure) {
|
|
199: return Flux.defer(this::openAndConsume).onErrorResume(this::haltOn);
|
|
exit=0
|
|
|
|
=== 8.2b does any test cover a redelivery after a resume? ===
|
|
$ grep -n 'aResumableFailureReopensFromTheCheckpoint' -A 16 adapter/outbound/persistence-mongo/src/test/java/dev/caskeleton/adapter/outbound/mongo/changestream/consumer/ChangeStreamConsumerLifecycleTest.java
|
|
93: void aResumableFailureReopensFromTheCheckpoint() {
|
|
94- checkpoints.stored = Optional.of(checkpoint("token-1", MongoResumePosition.RESUME_AFTER));
|
|
95- MongoQueryException resumable = queryFailure(133, "ResumableChangeStreamError");
|
|
96- RecordingSource source =
|
|
97- new RecordingSource(
|
|
98- Flux.error(resumable), Flux.just(event("token-2", 2, OperationType.INSERT)));
|
|
99-
|
|
100- ReactiveMongoChangeStreamConsumer consumer = consumer(source);
|
|
101- StepVerifier.create(consumer.run()).expectNextCount(1).verifyComplete();
|
|
102-
|
|
103- assertThat(source.opens).isEqualTo(2);
|
|
104- assertThat(source.reopenedAt.orElseThrow().token().getString("_data").getValue())
|
|
105- .as("the last written position is the last event a projection completed for")
|
|
106- .isEqualTo("token-1");
|
|
107- }
|
|
108-
|
|
109- @Test
|
|
exit=0
|
|
|
|
$ grep -n 'anEventBehindTheHighWaterMarkIsDropped' -A 24 adapter/outbound/persistence-mongo/src/test/java/dev/caskeleton/adapter/outbound/mongo/changestream/MongoChangeStreamPipelineTest.java
|
|
62: void anEventBehindTheHighWaterMarkIsDropped() {
|
|
63- List<String> projected = new ArrayList<>();
|
|
64- MongoChangeStreamPipeline pipeline =
|
|
65- new MongoChangeStreamPipeline(
|
|
66- new MongoChangeStreamRunner(
|
|
67- (identity, change) -> {
|
|
68- projected.add(change.getString("id").getValue());
|
|
69- return Mono.just(MongoChangeProjectionResult.applied());
|
|
70- },
|
|
71- new AlwaysClaims(),
|
|
72- new NoOpCheckpoints()));
|
|
73-
|
|
74- pipeline
|
|
75- .process(Flux.just(event("a", 5), event("late", 2), event("b", 6)))
|
|
76- .collectList()
|
|
77- .block();
|
|
78-
|
|
79- assertThat(projected)
|
|
80- .as("running it would move the resume checkpoint backwards over applied work")
|
|
81- .containsExactly("a", "b");
|
|
82- assertThat(pipeline.highWaterMark()).isEqualTo(new MongoClusterTime(1_700_000_000L, 6));
|
|
83- }
|
|
84-
|
|
85- @Test
|
|
86- @DisplayName("cluster time compares numerically, not as text")
|
|
exit=0
|
|
|
|
$ grep -n 'aBusyClaimNeverAdvancesTheCheckpoint' -A 22 adapter/outbound/persistence-mongo/src/test/java/dev/caskeleton/adapter/outbound/mongo/changestream/projector/MongoChangeStreamRunnerTest.java
|
|
173: void aBusyClaimNeverAdvancesTheCheckpoint() {
|
|
174- RecordingCheckpointStore checkpoints = new RecordingCheckpointStore();
|
|
175- ClaimingDeduplicationStore deduplication = new ClaimingDeduplicationStore();
|
|
176- deduplication.claimFor(IDENTITY);
|
|
177-
|
|
178- MongoChangeStreamRunner runner =
|
|
179- new MongoChangeStreamRunner(
|
|
180- (identity, change) -> Mono.just(MongoChangeProjectionResult.applied()),
|
|
181- deduplication,
|
|
182- checkpoints);
|
|
183-
|
|
184- MongoChangeProjectionResult result =
|
|
185- runner.runOne(IDENTITY, new BsonDocument(), CHECKPOINT).block();
|
|
186-
|
|
187- assertThat(result.outcome()).isEqualTo(MongoChangeProjectionResult.Outcome.CLAIMED_ELSEWHERE);
|
|
188- assertThat(checkpoints.saveCount())
|
|
189- .as("the holder may still fail, and the stream never replays what the checkpoint passed")
|
|
190- .isZero();
|
|
191- }
|
|
192-
|
|
193- @Test
|
|
194- @org.junit.jupiter.api.DisplayName("a crash after claiming leaves the event retryable")
|
|
195- void aCrashAfterClaimingLeavesTheEventRetryable() {
|
|
exit=0
|
|
|
|
=== 8.3 duplicate mechanisms inside recovery ===
|
|
$ git grep -n 'onHistoryLost\|onResumableFailure\|onInvalidate\|checkpointFor\|requireCorrectResumeOption\|autoResumable\|MongoChangeHistoryLostException' -- 'adapter/outbound/persistence-mongo/src'
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/advanced/tenancy/database/MongoTenantMigrationCoordinator.java:85: public Optional<MongoMigrationCheckpoint> checkpointFor(String tenantKey) {
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/changestream/MongoChangeStreamState.java:32: public boolean autoResumable() {
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/changestream/consumer/ReactiveMongoChangeStreamConsumer.java:119: invalidates.requireCorrectResumeOption(checkpoint, checkpoint.position());
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/changestream/recovery/MongoChangeHistoryLostException.java:16:public final class MongoChangeHistoryLostException extends MongoPersistenceException {
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/changestream/recovery/MongoChangeHistoryLostException.java:22: public MongoChangeHistoryLostException(
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/changestream/recovery/MongoChangeStreamRecoveryPolicy.java:29: public MongoChangeStreamRecoveryDecision onHistoryLost(String subscriptionProfile) {
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/changestream/recovery/MongoChangeStreamRecoveryPolicy.java:36: public MongoChangeStreamRecoveryDecision onResumableFailure() {
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/changestream/recovery/MongoChangeStreamRecoveryPolicy.java:46: public MongoChangeStreamRecoveryDecision onInvalidate() {
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/changestream/recovery/MongoInvalidateRecovery.java:19: public MongoResumeCheckpoint checkpointFor(String subscriptionProfile, byte[] invalidateToken) {
|
|
adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/changestream/recovery/MongoInvalidateRecovery.java:31: public void requireCorrectResumeOption(
|
|
adapter/outbound/persistence-mongo/src/test/java/dev/caskeleton/adapter/outbound/mongo/changestream/recovery/MongoChangeStreamRecoveryPolicyTest.java:21: MongoChangeStreamRecoveryDecision decision = policy.onHistoryLost("orders");
|
|
adapter/outbound/persistence-mongo/src/test/java/dev/caskeleton/adapter/outbound/mongo/changestream/recovery/MongoChangeStreamRecoveryPolicyTest.java:31: assertThat(policy.onResumableFailure().autoResume()).isTrue();
|
|
adapter/outbound/persistence-mongo/src/test/java/dev/caskeleton/adapter/outbound/mongo/changestream/recovery/MongoChangeStreamRecoveryPolicyTest.java:55: MongoResumeCheckpoint checkpoint = recovery.checkpointFor("orders", new byte[] {1, 2, 3});
|
|
adapter/outbound/persistence-mongo/src/test/java/dev/caskeleton/adapter/outbound/mongo/changestream/recovery/MongoChangeStreamRecoveryPolicyTest.java:59: () -> recovery.requireCorrectResumeOption(checkpoint, MongoResumePosition.RESUME_AFTER))
|
|
adapter/outbound/persistence-mongo/src/test/java/dev/caskeleton/adapter/outbound/mongo/changestream/recovery/MongoChangeStreamRecoveryPolicyTest.java:65: assertThat(MongoChangeStreamState.RUNNING.autoResumable()).isTrue();
|
|
adapter/outbound/persistence-mongo/src/test/java/dev/caskeleton/adapter/outbound/mongo/changestream/recovery/MongoChangeStreamRecoveryPolicyTest.java:66: assertThat(MongoChangeStreamState.HISTORY_LOST.autoResumable()).isFalse();
|
|
adapter/outbound/persistence-mongo/src/test/java/dev/caskeleton/adapter/outbound/mongo/changestream/recovery/MongoChangeStreamRecoveryPolicyTest.java:67: assertThat(MongoChangeStreamState.FAILED.autoResumable()).isFalse();
|
|
exit=0
|
|
|
|
=== 8.4 documentation drift: the runbooks the policy names ===
|
|
$ ls ../docs/mongodb/runbooks/ 2>&1
|
|
failover.md
|
|
history-lost.md
|
|
unknown-commit.md
|
|
exit=0
|
|
|
|
$ grep -rn 'HISTORY_LOST_RUNBOOK\|FAILURE_RUNBOOK' adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/changestream/recovery/MongoChangeStreamRecoveryPolicy.java
|
|
18: public static final String HISTORY_LOST_RUNBOOK = "docs/mongodb/runbooks/history-lost.md";
|
|
21: public static final String FAILURE_RUNBOOK = "docs/mongodb/runbooks/failover.md";
|
|
32: MongoChangeStreamState.HISTORY_LOST, HISTORY_LOST_RUNBOOK);
|
|
55: MongoChangeStreamState.HISTORY_LOST, HISTORY_LOST_RUNBOOK);
|
|
60: return MongoChangeStreamRecoveryDecision.halt(MongoChangeStreamState.FAILED, FAILURE_RUNBOOK);
|
|
exit=0
|
|
|
|
$ find .. -name 'history-lost.md' -o -name 'failover.md' | head
|
|
../docs/mongodb/runbooks/failover.md
|
|
../docs/mongodb/runbooks/history-lost.md
|
|
exit=0
|
|
|