# javadoc 은 넣기를 upsert 로 정의한다
19: * <p>An enqueue is an upsert: the same file reported twice updates the open item rather than adding
20: * a second one. Reconciliation runs on a schedule and re-raises whatever it still cannot settle, so
21: * an append-only queue would grow one row per sweep per unresolved file and bury the distinct
22: * problems under repetitions of the same one.
# 저장소 javadoc 은 최신 이유가 이긴다고 적는다
24:  /**
25:   * Re-raises an open item instead of adding a second one.
26:   *
27:   * <p>Reconciliation is retried on a schedule, so the same file reaches the queue repeatedly. One
28:   * open item per file keeps the queue a worklist rather than a failure log; the newest reason wins
29:   * because it describes the most recent evidence.
30:   */

# 구현은 갱신하고, 0 이면 저장한다
42:  @Override
43:  public void enqueue(FileId fileId, String reasonCode) {
44:    Instant now = clock.instant();
45:    if (items.refreshPending(fileId.value(), reasonCode, now) > 0) {
46:      return;
47:    }
48:    items.save(
49:        new RecoveryItemEntity(UUID.randomUUID(), fileId.value(), reasonCode, STATUS_PENDING, now));
50:  }
#   그 저장이 persist 로 갈지 merge 로 갈지 정하는 것
#     엔티티의 @Version 필드: 0
#     Persistable 구현: 0

# 데이터베이스가 파일당 열린 항목을 하나로 강제한다
52--- At most one open item per file: the queue is a worklist, not a log of every sweep.
53:CREATE UNIQUE INDEX uq_fs_recovery_open
54-    ON fs_recovery_item (file_id)
55-    WHERE status = 'PENDING';
56-

# 호출자가 실제로 받는 예외
195:  private <T> T executeLegacy(TransactionTemplate template, Supplier<T> action) {
196-    try {
197-      return template.execute(status -> action.get());
198-    } catch (RuntimeException failure) {
199-      throw exceptionTranslator
200-          .translate(failure)
201-          .map(RuntimeException.class::cast)
202-          .orElse(failure);
203-    }
204-  }
20:          "23505", OperationalError.DB_UNIQUE_VIOLATION,

# 이 넣기를 부르는 프로덕션 코드와 그 경계
application-core/src/main/java/dev/caskeleton/application/fileserver/upload/DefaultFinalizeUploadService.java:323:            recoveryQueue.enqueue(verifying.fileId(), "READY_COMMIT_UNCONFIRMED");
application-core/src/main/java/dev/caskeleton/application/fileserver/recovery/DefaultFileReconciliationService.java:220:          recoveryQueue.enqueue(record.fileId(), reasonCode);
    } catch (RuntimeException exception) {
      // The object is on the volume and the record does not say so — the definition of an ambiguous
      // completion. Enqueued in its own boundary, because the one that failed took nothing with it.
      transactions.inWrite(
          () -> {
            recoveryQueue.enqueue(verifying.fileId(), "READY_COMMIT_UNCONFIRMED");
          });
      throw new AmbiguousCompletionException(
          "content was published but the READY commit could not be confirmed",
#   조정 쪽 진입점을 부르는 프로덕션 코드: 0
#   조정이 집어 올리는 대상의 조건
27:  private static final Duration STALE_AFTER = Duration.ofMinutes(5);
71:            clock.instant().minus(STALE_AFTER),

# 같은 저장소가 승패를 데이터베이스에 물어보는 자리
application-core/src/main/java/dev/caskeleton/application/notification/platform/dispatch/NotificationRequestInsertOutcome.java:16: * anything: {@code ON CONFLICT DO NOTHING RETURNING} returns a row when the caller won and no rows
messaging/messaging-inbox-jdbc-postgresql/src/main/java/dev/caskeleton/messaging/inbox/JdbcInboxRepository.java:20: * <p>Reservation is an {@code INSERT ... ON CONFLICT DO NOTHING} whose affected-row count is the
messaging/messaging-inbox-jdbc-postgresql/src/main/java/dev/caskeleton/messaging/inbox/JdbcInboxRepository.java:36:      ON CONFLICT (message_id, consumer_id) DO NOTHING
