거래 스레드의 토큰 발급을 이력에 TRANSACTION 으로 구분

토큰이 없거나 만료되어 거래 중 발급한 경우도 SCHEDULE 로 기록되던 문제 수정
This commit is contained in:
curry772
2026-09-14 10:52:03 +09:00
parent ac5e617b37
commit 64bf89582a
2 changed files with 18 additions and 11 deletions
@@ -258,7 +258,7 @@ public class AccessTokenManagerByDB implements Lifecycle {
if (cached == null) { if (cached == null) {
logger.debug("Token not exists for adapter group: {}", adapterGroupName); logger.debug("Token not exists for adapter group: {}", adapterGroupName);
sessionManager.getOutboundAccessToken(adapterGroupName, sessionManager.getOutboundAccessToken(adapterGroupName,
token -> issueToken(credential)); token -> issueToken(credential, TokenIssueHistory.TRIGGER_SCHEDULE));
} else if (cached.getExpiration() == null) { } else if (cached.getExpiration() == null) {
// 만료시각이 없는 토큰은 갱신 시점을 판단할 수 없다. // 만료시각이 없는 토큰은 갱신 시점을 판단할 수 없다.
@@ -272,7 +272,7 @@ public class AccessTokenManagerByDB implements Lifecycle {
logger.debug("Token expires before next schedule : {}, expiration date: {}", logger.debug("Token expires before next schedule : {}, expiration date: {}",
adapterGroupName, cached.getExpiration()); adapterGroupName, cached.getExpiration());
sessionManager.reissueOutboundAccessToken(adapterGroupName, cached.getAccessToken(), sessionManager.reissueOutboundAccessToken(adapterGroupName, cached.getAccessToken(),
intervalTime, token -> issueToken(credential)); intervalTime, token -> issueToken(credential, TokenIssueHistory.TRIGGER_SCHEDULE));
} else { } else {
logger.debug( logger.debug(
@@ -300,7 +300,10 @@ public class AccessTokenManagerByDB implements Lifecycle {
} }
} }
private AccessTokenVO issueToken(OutboundOAuthCredentialVo outboundOAuthCredentialVo) { /**
* @param trigger 발급 이력에 남길 호출 경로 (TokenIssueHistory.TRIGGER_*)
*/
private AccessTokenVO issueToken(OutboundOAuthCredentialVo outboundOAuthCredentialVo, String trigger) {
String adapterGroupName = outboundOAuthCredentialVo.getAdapterGroupName(); String adapterGroupName = outboundOAuthCredentialVo.getAdapterGroupName();
AccessTokenVO accessToken = null; AccessTokenVO accessToken = null;
try { try {
@@ -335,12 +338,12 @@ public class AccessTokenManagerByDB implements Lifecycle {
accessToken = (AccessTokenVO) service.execute(adapterGroupName, properties, accessToken = (AccessTokenVO) service.execute(adapterGroupName, properties,
outboundOAuthCredentialVo); outboundOAuthCredentialVo);
} catch (Exception e) { } catch (Exception e) {
recordIssueHistory(adapterGroupName, TokenIssueHistory.TRIGGER_SCHEDULE, type, startTime, null, recordIssueHistory(adapterGroupName, trigger, type, startTime, null,
toFailReason(e)); toFailReason(e));
throw e; throw e;
} }
recordIssueHistory(adapterGroupName, TokenIssueHistory.TRIGGER_SCHEDULE, type, startTime, recordIssueHistory(adapterGroupName, trigger, type, startTime,
accessToken, null); accessToken, null);
// 발급에 실패했는데도 빈 토큰을 반환하는 구현체가 있다. 그대로 캐시되면 // 발급에 실패했는데도 빈 토큰을 반환하는 구현체가 있다. 그대로 캐시되면
@@ -354,12 +357,12 @@ public class AccessTokenManagerByDB implements Lifecycle {
return accessToken; return accessToken;
} else { } else {
recordIssueHistory(adapterGroupName, TokenIssueHistory.TRIGGER_SCHEDULE, type, recordIssueHistory(adapterGroupName, trigger, type,
System.currentTimeMillis(), null, "토큰 발급 구현체를 찾을 수 없음"); System.currentTimeMillis(), null, "토큰 발급 구현체를 찾을 수 없음");
logger.warn("Token service not found for type: {} and adapter group: {}", type, adapterGroupName); logger.warn("Token service not found for type: {} and adapter group: {}", type, adapterGroupName);
} }
} else { } else {
recordIssueHistory(adapterGroupName, TokenIssueHistory.TRIGGER_SCHEDULE, null, recordIssueHistory(adapterGroupName, trigger, null,
System.currentTimeMillis(), null, "어댑터 설정을 찾을 수 없음"); System.currentTimeMillis(), null, "어댑터 설정을 찾을 수 없음");
logger.warn("No valid adapter configuration found for adapter group: {}", adapterGroupName); logger.warn("No valid adapter configuration found for adapter group: {}", adapterGroupName);
} }
@@ -429,7 +432,7 @@ public class AccessTokenManagerByDB implements Lifecycle {
* 3. 주의사항 : accessToken 은 앞 UNMASKED_TOKEN_LENGTH 자만 남겨 보관한다. * 3. 주의사항 : accessToken 은 앞 UNMASKED_TOKEN_LENGTH 자만 남겨 보관한다.
* *
* @param adapterGroupName 어댑터그룹명 * @param adapterGroupName 어댑터그룹명
* @param trigger SCHEDULE / RETRY * @param trigger SCHEDULE / RETRY / TRANSACTION
* @param serviceClass 사용한 발급 구현체 클래스명 * @param serviceClass 사용한 발급 구현체 클래스명
* @param startTime 발급 시도 시각 * @param startTime 발급 시도 시각
* @param accessToken 발급된 토큰. 실패 시 null. * @param accessToken 발급된 토큰. 실패 시 null.
@@ -553,7 +556,8 @@ public class AccessTokenManagerByDB implements Lifecycle {
OutboundOAuthCredentialVo outboundOAuthCredentialVo = outboundOAuthCredentialVos OutboundOAuthCredentialVo outboundOAuthCredentialVo = outboundOAuthCredentialVos
.get(adapterGroupName); .get(adapterGroupName);
return issueToken(outboundOAuthCredentialVo); // 스케줄러가 아니라 거래 스레드가 토큰이 없거나 만료된 것을 보고 발급하는 경로다.
return issueToken(outboundOAuthCredentialVo, TokenIssueHistory.TRIGGER_TRANSACTION);
} }
}); });
@@ -17,15 +17,18 @@ public class TokenIssueHistory {
/** 스케줄러의 주기 발급 */ /** 스케줄러의 주기 발급 */
public static final String TRIGGER_SCHEDULE = "SCHEDULE"; public static final String TRIGGER_SCHEDULE = "SCHEDULE";
/** 거래 중 재발급 */ /** 거래 중 재발급 (기관이 토큰을 거부한 경우) */
public static final String TRIGGER_RETRY = "RETRY"; public static final String TRIGGER_RETRY = "RETRY";
/** 거래 중 발급 (캐시에 토큰이 없거나 이미 만료된 경우) */
public static final String TRIGGER_TRANSACTION = "TRANSACTION";
private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss"; private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
/** 발급을 시도한 시각 */ /** 발급을 시도한 시각 */
private final String issuedAt; private final String issuedAt;
/** SCHEDULE | RETRY */ /** SCHEDULE | RETRY | TRANSACTION */
private final String trigger; private final String trigger;
/** 사용한 발급 구현체 클래스명 */ /** 사용한 발급 구현체 클래스명 */