Files
document-haness/docs/clean-architecture-backend-template/final/evidence/raw/a06-f013-recordapplied-around.txt
T
DongHyeonkaandClaude Opus 5 b2963105a8 docs(keycloak-session-store): import the session-storage lab as a new project
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>
2026-09-04 22:51:59 +09:00

70 lines
3.3 KiB
Plaintext

# 조립된 경로에서 갱신과 원장 기록 사이에 있는 것
// Still refreshed after execute, but the refresh is no longer what protects the run: the
// heartbeat inside the context is. This one only proves the lease survived to the end, before
// anything is written to the ledger under it.
lock.refresh(template.maxTime());
if (!migration.postcondition().isSatisfied(context, result)) {
throw MongoOperationRejectedException.of(
"migration.postcondition",
"migration "
+ migration.id()
...
result.resumePoint().ifPresent(checkpoint -> ledger.saveCheckpoint(checkpoint, lock.fence()));
if (result.status() == MongoMigrationResult.Status.COMPLETED && !context.dryRun()) {
ledger.recordApplied(
migration.id(), migration.checksum(), context.operator(), clock.instant(), lock.fence());
}
# 완료를 만드는 팩토리는 체크포인트를 남기지 않는다
/** The migration finished. */
public static MongoMigrationResult completed(long processedCount) {
return new MongoMigrationResult(Status.COMPLETED, processedCount, null, "");
}
/** The migration made progress and stored a checkpoint to resume from. */
public static MongoMigrationResult incomplete(
long processedCount, MongoMigrationCheckpoint checkpoint) {
return new MongoMigrationResult(
Status.INCOMPLETE, processedCount, Objects.requireNonNull(checkpoint, "checkpoint"), "");
}
# 그 갱신이 던지는 것
if (stillOwned != 1) {
held = false;
throw new IllegalStateException(
"the migration lease was lost before it could be refreshed; another runner may have "
+ "taken it after this one appeared to stall");
}
# 같은 인터페이스의 다른 잠금 구현이 같은 상황에 던지는 것
public void refresh(Duration extension) {
Objects.requireNonNull(extension, "extension");
if (!held.get()) {
throw MongoOperationRejectedException.of(
"migration.lock", "the migration lease has been released and cannot be extended");
}
extend.accept(extension);
# 다른 원장 구현은 펜스 인자를 쓰지 않는다
long fence) {
recorded.put(
Objects.requireNonNull(migrationId, "migrationId"),
new AppliedMigration(migrationId, checksum, operator, appliedAt));
}
# recordApplied 를 부르는 시험 전수
MongoMigrationRunnerTest.java:23: ledger.recordApplied(
MongoMigrationRunnerTest.java:40: ledger.recordApplied(
MongoMigrationLaneTest.java:130: ledger.recordApplied(
MongoMigrationLaneTest.java:227: ledger.recordApplied(id, new MongoMigrationChecksum("abc"), "operator", FIXED.instant(), 1L);
MongoMigrationLaneTest.java:231: ledger.recordApplied(
# 그중 실서버에서 두 번 부르는 시험이 단언하는 것
() ->
ledger.recordApplied(
id, new MongoMigrationChecksum("abc"), "operator", FIXED.instant(), 1L))
.as("the unique index, not the read-then-write check, is what makes this impossible")
.isInstanceOf(RuntimeException.class);
# 고유 색인을 만드는 메서드를 부르는 곳 전수
test/java/dev/caskeleton/adapter/outbound/mongo/migration/MongoMigrationLaneTest.java
main/java/dev/caskeleton/adapter/outbound/mongo/migration/MongoCollectionMigrationLedger.java