# 같은 원자 참조를 쓰는 전이 일곱 127: public void markAuthenticationFailed(String reasonCode) { 139: public boolean markThrottled() { 156: public boolean markDegraded(String reasonCode) { 182: public boolean markHealthy() { 205: public boolean resumeHealthy() { 221: public boolean markDraining() { 235: public boolean markDisabled() { # resumeHealthy 가 적은 보장과 구현 195: /** 196: * Clear an operator-imposed state. 197: * 198: *

This is the admin counterpart of {@link #markHealthy()}: it resumes a runtime that an 199: * operator drained or disabled. It still refuses {@code AUTHENTICATION_FAILED}, because declaring 200: * a provider healthy does not give it a credential the provider will accept — the caller is told 201: * so rather than being handed a runtime that will fail on its first attempt. 202: * 203: * @return whether the runtime is now healthy 204: */ 205: public boolean resumeHealthy() { 206: return health 207: .updateAndGet( 208: current -> 209: current.state() == ProviderRuntimeState.AUTHENTICATION_FAILED 210: ? current 211: : new RuntimeHealth(ProviderRuntimeState.HEALTHY, Optional.empty())) 212: .state() 213: == ProviderRuntimeState.HEALTHY; 214: } # 현재 값을 받아 놓고 쓰지 않는 둘 221: public boolean markDraining() { 222: return health 223: .updateAndGet( 224: current -> 225: new RuntimeHealth(ProviderRuntimeState.DRAINING, Optional.of("DRAINING"))) 226: .state() 227: == ProviderRuntimeState.DRAINING; 228: } 235: public boolean markDisabled() { 236: return health 237: .updateAndGet( 238: current -> 239: new RuntimeHealth(ProviderRuntimeState.DISABLED, Optional.of("DISABLED"))) 240: .state() 241: == ProviderRuntimeState.DISABLED; 242: } # set 으로 쓰는 하나 127: public void markAuthenticationFailed(String reasonCode) { 128: Objects.requireNonNull(reasonCode, "reasonCode"); 129: // One write, so the state and the reason it carries are never observed apart. 130: health.set( 131: new RuntimeHealth(ProviderRuntimeState.AUTHENTICATION_FAILED, Optional.of(reasonCode))); 132: } # 관리자 포트가 여섯을 분배한다 30: return switch (desiredState) { 31: case DISABLED -> runtime.markDisabled(); 32: case DRAINING -> runtime.markDraining(); 33: case HEALTHY -> runtime.resumeHealthy(); 34: case DEGRADED -> runtime.markDegraded(reason); 35: case THROTTLED -> runtime.markThrottled(); 36: case AUTHENTICATION_FAILED -> { 37: runtime.markAuthenticationFailed(reason); 38: yield true; 39: } # 헬스 보고기가 unhealthy 로 보는 상태 18: * 19: *

A provider whose credentials were rejected reports unhealthy even though the process is fine: 20: * that is exactly the condition an operator needs paged on, and it is invisible from process-level 21: * health. 63: ProviderRuntimeState state = runtime.get().state(); 64: if (state == ProviderRuntimeState.AUTHENTICATION_FAILED 65: || state == ProviderRuntimeState.DISABLED) { 66: healthy = false; 67: } # 사유 코드를 읽는 곳 ProviderRuntime.java:84: *

Prefer this to calling {@link #state()} and {@link #unhealthyReason()} in turn: two reads ProviderRuntime.java:97: public Optional unhealthyReason() { 23: public record ProviderHealth( 24- String profileId, String state, long credentialGeneration, int activeAttempts) { # 이 보장을 확인하는 test 124: @DisplayName("an operator can resume a drained or disabled runtime but not a failed credential") 125: void resumeHealthyClearsOperatorStatesOnly() { 126: ProviderRuntime drained = runtime(1, 1); 127: drained.markDraining(); 128: assertThat(drained.resumeHealthy()).isTrue(); 129: 130: ProviderRuntime disabled = runtime(1, 1); 131: disabled.markDisabled(); 132: assertThat(disabled.resumeHealthy()).isTrue(); 133: 134: ProviderRuntime failed = runtime(1, 1); 135: failed.markAuthenticationFailed("INVALID_CREDENTIAL"); 136: assertThat(failed.resumeHealthy()) 137: .as("declaring it healthy does not give it a credential the provider accepts") 143: @DisplayName("degrading an already failed runtime is refused rather than silently ignored") 144: void degradingAFailedRuntimeIsRefused() { 145: ProviderRuntime runtime = runtime(1, 1); 146: runtime.markAuthenticationFailed("INVALID_CREDENTIAL"); 147: 148: assertThat(runtime.markDegraded("UPSTREAM_5XX")).isFalse(); 149: assertThat(runtime.health().reason()).contains("INVALID_CREDENTIAL"); 150: }