# 관측 인터페이스가 세우는 계약 MongoOperationObservation.java:6 /** MongoOperationObservation.java:7 * One in-flight operation's observation scope (design §27). MongoOperationObservation.java:8 * MongoOperationObservation.java:9 *
{@link AutoCloseable} so the scope closes on every path, including the one where the callback MongoOperationObservation.java:10 * throws something the platform never classified. An observation that only closes on success MongoOperationObservation.java:11 * produces metrics that look healthy precisely when the system is not. MongoOperationObservation.java:12 */ MongoOperationObservation.java:13 public interface MongoOperationObservation extends AutoCloseable { MongoOperationObservation.java:14 MongoOperationObservation.java:15 /** Records a successful completion and its write outcome. */ MongoOperationObservation.java:16 void success(MongoExecutionOutcome outcome); MongoOperationObservation.java:17 MongoOperationObservation.java:18 /** Records a failure, using only the bounded metadata the failure context is allowed to carry. */ MongoOperationObservation.java:19 void failure(MongoFailureContext failureContext); MongoOperationObservation.java:20 MongoOperationObservation.java:21 /** The trace identifier of this observation, or an empty string when tracing is off. */ MongoOperationObservation.java:22 String traceId(); MongoOperationObservation.java:23 MongoOperationObservation.java:24 @Override MongoOperationObservation.java:25 void close(); MongoOperationObservation.java:26 } # 예산 초과 분기 DefaultMongoImperativeExecutor.java:85 long startedAt = System.nanoTime(); DefaultMongoImperativeExecutor.java:86 try (MongoOperationObservation observation = observer.start(context, operationType)) { DefaultMongoImperativeExecutor.java:87 try { DefaultMongoImperativeExecutor.java:88 T value = callback.doInMongo(access); DefaultMongoImperativeExecutor.java:89 Duration elapsed = Duration.ofNanos(System.nanoTime() - startedAt); DefaultMongoImperativeExecutor.java:90 // A read is not a confirmed write. Recording every successful FIND as WRITE_CONFIRMED made DefaultMongoImperativeExecutor.java:91 // the metric that answers "are writes being acknowledged" count reads as well. DefaultMongoImperativeExecutor.java:92 MongoExecutionOutcome outcome = MongoCompletion.successOutcomeFor(operationType); DefaultMongoImperativeExecutor.java:93 if (elapsed.compareTo(context.timeout()) > 0) { DefaultMongoImperativeExecutor.java:94 // The context declares a deadline on every operation and nothing compared anything to it. DefaultMongoImperativeExecutor.java:95 // A callback cannot be interrupted mid-driver-call, so this cannot cut the work short — DefaultMongoImperativeExecutor.java:96 // but reporting a breach beats reporting success for work that ran past its budget. DefaultMongoImperativeExecutor.java:97 observation.success(outcome); DefaultMongoImperativeExecutor.java:98 throw MongoOperationRejectedException.of( DefaultMongoImperativeExecutor.java:99 context.operationName().value(), DefaultMongoImperativeExecutor.java:100 "the operation ran for " DefaultMongoImperativeExecutor.java:101 + elapsed.toMillis() DefaultMongoImperativeExecutor.java:102 + "ms against a declared timeout of " DefaultMongoImperativeExecutor.java:103 + context.timeout().toMillis() DefaultMongoImperativeExecutor.java:104 + "ms"); DefaultMongoImperativeExecutor.java:105 } DefaultMongoImperativeExecutor.java:106 observation.success(outcome); DefaultMongoImperativeExecutor.java:107 return new MongoOperationResult<>(context, value, outcome, elapsed); DefaultMongoImperativeExecutor.java:108 } catch (MongoPersistenceException alreadyTranslated) { DefaultMongoImperativeExecutor.java:109 observation.failure(alreadyTranslated.failureContext()); DefaultMongoImperativeExecutor.java:110 throw alreadyTranslated; DefaultMongoImperativeExecutor.java:111 } catch (MongoException driverFailure) { DefaultMongoImperativeExecutor.java:112 throw translated(context, operationType, startedAt, observation, driverFailure); DefaultMongoImperativeExecutor.java:113 } catch (DataAccessException springFailure) { DefaultMongoImperativeExecutor.java:114 throw translated(context, operationType, startedAt, observation, unwrap(springFailure)); DefaultMongoImperativeExecutor.java:115 } DefaultMongoImperativeExecutor.java:116 } DefaultMongoImperativeExecutor.java:117 } DefaultMongoImperativeExecutor.java:118 # 그 예외가 무엇을 상속하는가 MongoOperationRejectedException.java:1 package dev.caskeleton.adapter.outbound.mongo.api.error; MongoOperationRejectedException.java:2 MongoOperationRejectedException.java:3 import dev.caskeleton.adapter.outbound.mongo.api.MongoOperationName; MongoOperationRejectedException.java:4 import java.io.Serial; MongoOperationRejectedException.java:5 MongoOperationRejectedException.java:6 /** MongoOperationRejectedException.java:7 * The platform refused the operation locally, before any server was contacted (design §15, §16.2). MongoOperationRejectedException.java:8 * MongoOperationRejectedException.java:9 *
This is the guardrail exception: unregistered field, unregistered operator, raised budget, MongoOperationRejectedException.java:10 * write stage in a read API, deep skip, missing tenant context, admin command on a runtime client. MongoOperationRejectedException.java:11 * It is always {@code NOT_SENT} and never retryable, because retrying a rejected request only MongoOperationRejectedException.java:12 * repeats the rejection. MongoOperationRejectedException.java:13 */ MongoOperationRejectedException.java:14 public final class MongoOperationRejectedException extends MongoPersistenceException { MongoOperationRejectedException.java:15 MongoOperationRejectedException.java:16 @Serial private static final long serialVersionUID = 1L; MongoOperationRejectedException.java:17 MongoOperationRejectedException.java:18 public MongoOperationRejectedException(String summary, MongoFailureContext failureContext) { MongoOperationRejectedException.java:19 super(summary, failureContext); MongoOperationRejectedException.java:20 } MongoOperationRejectedException.java:21 MongoOperationRejectedException.java:22 /** Rejects an operation identified only by name, before profiles were resolved. */ MongoOperationRejectedException.java:23 public static MongoOperationRejectedException of(String operationName, String summary) { MongoOperationRejectedException.java:24 return new MongoOperationRejectedException( MongoOperationRejectedException.java:25 summary, MongoFailureContext.rejected(new MongoOperationName(operationName))); MongoOperationRejectedException.java:26 } MongoOperationRejectedException.java:27 # 한 관측에 두 번 기록되는가 try 블록 안에서 observation.success 를 부르는 줄 : 2 개 같은 try 의 catch 가 observation.failure 를 부르는 줄 : 1 개 이 파일에서 두 메서드를 부르는 자리 전부 : DefaultMongoImperativeExecutor.java:97 observation.success(outcome); DefaultMongoImperativeExecutor.java:106 observation.success(outcome); DefaultMongoImperativeExecutor.java:109 observation.failure(alreadyTranslated.failureContext()); DefaultMongoImperativeExecutor.java:129 observation.failure(translated.failureContext().withTraceId(observation.traceId())); # 출하 구현이 그것을 어떻게 다루는가 MicrometerMongoOperationObserver.java:62 private final Tags baseTags; MicrometerMongoOperationObserver.java:63 MicrometerMongoOperationObserver.java:64 private Tags outcomeTags; MicrometerMongoOperationObserver.java:65 MicrometerMongoOperationObserver.java:66 private boolean stopped; MicrometerMongoOperationObserver.java:67 MicrometerMongoOperationObserver.java:68 private MicrometerObservation(MeterRegistry registry, Timer.Sample sample, Tags baseTags) { MicrometerMongoOperationObserver.java:69 this.registry = registry; MicrometerMongoOperationObserver.java:70 this.sample = sample; MicrometerMongoOperationObserver.java:71 this.baseTags = baseTags; MicrometerMongoOperationObserver.java:72 this.outcomeTags = Tags.of("result", "unknown", "failureCategory", "none"); MicrometerMongoOperationObserver.java:73 } MicrometerMongoOperationObserver.java:74 MicrometerMongoOperationObserver.java:75 @Override MicrometerMongoOperationObserver.java:76 public void success(MongoExecutionOutcome outcome) { MicrometerMongoOperationObserver.java:77 outcomeTags = Tags.of("result", outcome.name(), "failureCategory", "none"); MicrometerMongoOperationObserver.java:78 } MicrometerMongoOperationObserver.java:79 MicrometerMongoOperationObserver.java:80 @Override MicrometerMongoOperationObserver.java:81 public void failure(MongoFailureContext failureContext) { MicrometerMongoOperationObserver.java:82 outcomeTags = MicrometerMongoOperationObserver.java:83 Tags.of( MicrometerMongoOperationObserver.java:84 "result", MicrometerMongoOperationObserver.java:85 failureContext.outcome().name(), MicrometerMongoOperationObserver.java:86 "failureCategory", MicrometerMongoOperationObserver.java:87 failureContext.category().name()); MicrometerMongoOperationObserver.java:88 } MicrometerMongoOperationObserver.java:89 MicrometerMongoOperationObserver.java:90 @Override MicrometerMongoOperationObserver.java:91 public String traceId() { MicrometerMongoOperationObserver.java:92 return ""; MicrometerMongoOperationObserver.java:93 } MicrometerMongoOperationObserver.java:94 MicrometerMongoOperationObserver.java:95 @Override MicrometerMongoOperationObserver.java:96 public void close() { MicrometerMongoOperationObserver.java:97 if (stopped) { MicrometerMongoOperationObserver.java:98 return; MicrometerMongoOperationObserver.java:99 } MicrometerMongoOperationObserver.java:100 stopped = true; MicrometerMongoOperationObserver.java:101 sample.stop(registry.timer(TIMER_NAME, baseTags.and(outcomeTags))); MicrometerMongoOperationObserver.java:102 } MicrometerMongoOperationObserver.java:103 } # 다른 구현이 있는가 MongoOperationObservation 을 구현하는 자리 : 2 개 main · NoOpMongoOperationObserver.java:29 private static final class NoOpObservation implements MongoOperationObservation { main · MicrometerMongoOperationObserver.java:56 private static final class MicrometerObservation implements MongoOperationObservation { [대조] MongoOperationObserver 를 구현하는 자리 : 2 개 NoOpMongoOperationObserver.java:27 } NoOpMongoOperationObserver.java:28 NoOpMongoOperationObserver.java:29 private static final class NoOpObservation implements MongoOperationObservation { NoOpMongoOperationObserver.java:30 NoOpMongoOperationObserver.java:31 @Override NoOpMongoOperationObserver.java:32 public void success(MongoExecutionOutcome outcome) { NoOpMongoOperationObserver.java:33 // Nothing is recorded when telemetry is not configured. NoOpMongoOperationObserver.java:34 } NoOpMongoOperationObserver.java:35 NoOpMongoOperationObserver.java:36 @Override NoOpMongoOperationObserver.java:37 public void failure(MongoFailureContext failureContext) { NoOpMongoOperationObserver.java:38 // Nothing is recorded when telemetry is not configured. NoOpMongoOperationObserver.java:39 } NoOpMongoOperationObserver.java:40 NoOpMongoOperationObserver.java:41 @Override NoOpMongoOperationObserver.java:42 public String traceId() { NoOpMongoOperationObserver.java:43 return ""; NoOpMongoOperationObserver.java:44 } NoOpMongoOperationObserver.java:45 NoOpMongoOperationObserver.java:46 @Override NoOpMongoOperationObserver.java:47 public void close() { NoOpMongoOperationObserver.java:48 // Nothing to release. NoOpMongoOperationObserver.java:49 } NoOpMongoOperationObserver.java:50 }