Conversation
Summary by CodeRabbit릴리스 노트
Walkthrough결제 환불에 멱등성 키(idempotencyKey)를 도입하고 취소 경로에 분산 락( Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant PaymentFacade as PaymentFacadeService\n(`@DistributedLock`)
participant TosspayClient as TosspaymentsClient
participant TossAPI as ExternalTossAPI
Client->>PaymentFacade: refundRequest(CancelRequest)
Note right of PaymentFacade: acquire distributed lock
PaymentFacade->>PaymentFacade: generate idempotencyKey ("cancel:" + paymentKey → UUID)
PaymentFacade->>TosspayClient: cancelPayment(paymentKey, cancelReq, idempotencyKey)
TosspayClient->>TossAPI: HTTP POST /payments/{paymentKey}/cancel\nHeader: Idempotency-Key: <idempotencyKey>
TossAPI-->>TosspayClient: 200 OK / error
TosspayClient-->>PaymentFacade: TosspaymentsPaymentResponse / error
PaymentFacade-->>Client: refundResult
Note left of PaymentFacade: release distributed lock
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! 이 PR은 토스페이먼츠 환불 처리의 안정성을 강화하기 위해 멱등성(Idempotency)을 구현하고 중복 환불을 방지하는 기능을 추가합니다. 이를 통해 결제 취소 요청이 여러 번 전송되더라도 한 번만 처리되도록 보장하여 데이터 일관성을 유지하고 잠재적인 오류를 줄입니다. Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Changelog
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. 멱등성 키, 환불은 한 번만, 안전한 거래. Footnotes
|
Test Results 47 files 47 suites 1m 25s ⏱️ Results for commit 6964c9b. ♻️ This comment has been updated with latest results. |
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/test/java/com/samhap/kokomen/payment/service/PaymentFacadeServiceTest.java (1)
303-361: 🧹 Nitpick | 🔵 Trivial3번째 인자에
any()를 사용하면 멱등키 누락 회귀를 잡지 못합니다.
cancelPayment(String paymentKey, TosspaymentsPaymentCancelRequest request, String idempotencyKey)메서드의 3번째 파라미터인idempotencyKey는 HTTP 헤더로 필수 전달되는 항목입니다.any()는 null도 매칭하므로, 서비스 로직이 변경되어 idempotencyKey를 누락하거나 null을 전달하는 경우를 테스트에서 감지할 수 없습니다.anyString()을 사용하여 null이 아닌 String이 전달되는지 확인해 주세요.🔧 제안 수정안
import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; @@ - when(tosspaymentsClient.cancelPayment(any(), any(), any())).thenReturn(cancelResponse); + when(tosspaymentsClient.cancelPayment(any(), any(), anyString())).thenReturn(cancelResponse); @@ - when(tosspaymentsClient.cancelPayment(any(), any(), any())).thenThrow(clientError); + when(tosspaymentsClient.cancelPayment(any(), any(), anyString())).thenThrow(clientError); @@ - when(tosspaymentsClient.cancelPayment(any(), any(), any())).thenThrow(clientError); + when(tosspaymentsClient.cancelPayment(any(), any(), anyString())).thenThrow(clientError); @@ - when(tosspaymentsClient.cancelPayment(any(), any(), any())) + when(tosspaymentsClient.cancelPayment(any(), any(), anyString())) .thenThrow(new HttpServerErrorException(HttpStatus.INTERNAL_SERVER_ERROR)); @@ - when(tosspaymentsClient.cancelPayment(any(), any(), any())) + when(tosspaymentsClient.cancelPayment(any(), any(), anyString())) .thenThrow(new ResourceAccessException("네트워크 오류")); @@ - when(tosspaymentsClient.cancelPayment(any(), any(), any())) + when(tosspaymentsClient.cancelPayment(any(), any(), anyString())) .thenThrow(new RuntimeException("예상치 못한 오류"));🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/test/java/com/samhap/kokomen/payment/service/PaymentFacadeServiceTest.java` around lines 303 - 361, The test uses a loose matcher for the third parameter of tosspaymentsClient.cancelPayment(...) which is the required idempotencyKey; replace the third matcher any() with anyString() so the mocks verify a non-null String is passed. Update every mock stubbing and when(...) call in PaymentFacadeServiceTest that calls tosspaymentsClient.cancelPayment(any(), any(), any()) to tosspaymentsClient.cancelPayment(any(), any(), anyString()) (and similarly for thenThrow/thenReturn cases) so the test will catch regressions that drop or pass null for the idempotencyKey.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/main/java/com/samhap/kokomen/payment/domain/TosspaymentsStatus.java`:
- Around line 4-10: TosspaymentsStatus enum is missing the WAITING_FOR_DEPOSIT
value which causes deserialization failures for virtual account responses; add a
new enum constant WAITING_FOR_DEPOSIT (with an appropriate comment like "가상계좌 입금
대기") to the TosspaymentsStatus enum so incoming API/webhook payloads that
contain that state deserialize correctly, and run/update unit/integration tests
that deserialize Toss Payments responses to verify no exceptions occur.
In `@src/main/java/com/samhap/kokomen/payment/service/PaymentFacadeService.java`:
- Around line 142-149: The cancelPayment method in PaymentFacadeService
currently creates a new random idempotencyKey each call (UUID.randomUUID()),
which breaks retry stability; replace this with a deterministic UUID derived
from the payment identifier so retries produce the same key (e.g., generate
idempotencyKey via UUID.nameUUIDFromBytes over request.paymentKey() plus a
static salt like "cancel" using StandardCharsets.UTF_8). Update the
idempotencyKey assignment in cancelPayment, add any necessary imports
(StandardCharsets), and ensure idempotencyKey is passed unchanged to
tosspaymentsClient.cancelPayment so identical cancel requests reuse the same
key.
---
Outside diff comments:
In
`@src/test/java/com/samhap/kokomen/payment/service/PaymentFacadeServiceTest.java`:
- Around line 303-361: The test uses a loose matcher for the third parameter of
tosspaymentsClient.cancelPayment(...) which is the required idempotencyKey;
replace the third matcher any() with anyString() so the mocks verify a non-null
String is passed. Update every mock stubbing and when(...) call in
PaymentFacadeServiceTest that calls tosspaymentsClient.cancelPayment(any(),
any(), any()) to tosspaymentsClient.cancelPayment(any(), any(), anyString())
(and similarly for thenThrow/thenReturn cases) so the test will catch
regressions that drop or pass null for the idempotencyKey.
ℹ️ Review info
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (5)
src/main/java/com/samhap/kokomen/interview/service/ResumeBasedInterviewService.javasrc/main/java/com/samhap/kokomen/payment/domain/TosspaymentsStatus.javasrc/main/java/com/samhap/kokomen/payment/external/TosspaymentsClient.javasrc/main/java/com/samhap/kokomen/payment/service/PaymentFacadeService.javasrc/test/java/com/samhap/kokomen/payment/service/PaymentFacadeServiceTest.java
| READY, // 결제 준비 | ||
| IN_PROGRESS, // 결제 진행 중 | ||
| DONE, // 승인 성공 | ||
| CANCELED, // 결제 취소 | ||
| PARTIAL_CANCELED, // 결제 부분 취소 | ||
| ABORTED, // 승인 실패 | ||
| EXPIRED // 유효 시간 만료 |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
Toss Payments API payment status values WAITING_FOR_DEPOSIT official documentation
💡 Result:
In the Toss Payments Core API Payment object, the status field can be one of these values:
READYIN_PROGRESSWAITING_FOR_DEPOSIT(virtual account only; issued account but customer hasn’t deposited yet)DONECANCELEDPARTIAL_CANCELEDABORTEDEXPIRED(after 30 minutes if not confirmed fromIN_PROGRESS) [1]
WAITING_FOR_DEPOSIT is officially documented as: a status that exists only in the virtual account payment flow, when the issued virtual account has not yet received the customer’s deposit. [1]
Sources
- [1] Toss Payments Developer Center — Core API Reference (Payment object
statusenum): (docs.tosspayments.com)
Citations:
🏁 Script executed:
# 파일 위치 확인 및 TosspaymentsStatus enum 전체 내용 조회
find . -name "TosspaymentsStatus.java" -type fRepository: samhap-soft/kokomen-backend
Length of output: 144
🏁 Script executed:
# TosspaymentsStatus enum의 전체 코드와 enum 상수 확인
cat -n "src/main/java/com/samhap/kokomen/payment/domain/TosspaymentsStatus.java"Repository: samhap-soft/kokomen-backend
Length of output: 396
🏁 Script executed:
# TosspaymentsStatus enum이 사용되는 모든 위치 찾기 (역직렬화, 매핑 등)
rg "TosspaymentsStatus" --type java -B 2 -A 2Repository: samhap-soft/kokomen-backend
Length of output: 24524
🏁 Script executed:
# Toss Payments 관련 설정, API 모델, 응답 처리 확인
fd -t f -e java . -path "*toss*" -o -path "*payment*" | head -20Repository: samhap-soft/kokomen-backend
Length of output: 239
가상계좌 결제 시 WAITING_FOR_DEPOSIT 상태 반환으로 역직렬화 실패 가능
Toss Payments API는 공식 문서에 WAITING_FOR_DEPOSIT를 정당한 결제 상태로 정의하고 있습니다(가상계좌 결제에서 계좌 발급 후 입금 대기 상태). 현재 enum에서 이 상태가 누락되어 있어, 해당 결제 방식 응답이 역직렬화되지 않습니다. 특히 웹훅 및 결제 조회 API 응답 처리 시 예외가 발생합니다.
🔧 수정 방안
public enum TosspaymentsStatus {
READY, // 결제 준비
IN_PROGRESS, // 결제 진행 중
+ WAITING_FOR_DEPOSIT, // 입금 대기 (가상계좌 등)
DONE, // 승인 성공
CANCELED, // 결제 취소
PARTIAL_CANCELED, // 결제 부분 취소
ABORTED, // 승인 실패
EXPIRED // 유효 시간 만료
}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/main/java/com/samhap/kokomen/payment/domain/TosspaymentsStatus.java`
around lines 4 - 10, TosspaymentsStatus enum is missing the WAITING_FOR_DEPOSIT
value which causes deserialization failures for virtual account responses; add a
new enum constant WAITING_FOR_DEPOSIT (with an appropriate comment like "가상계좌 입금
대기") to the TosspaymentsStatus enum so incoming API/webhook payloads that
contain that state deserialize correctly, and run/update unit/integration tests
that deserialize Toss Payments responses to verify no exceptions occur.
There was a problem hiding this comment.
저희 서비스는 가상계좌 결제 기능을 제공하지 않기로 결정했습니다.
There was a problem hiding this comment.
@unifolio0, 알겠습니다! 가상계좌 결제 기능을 제공하지 않는다면 WAITING_FOR_DEPOSIT 상태를 enum에서 제거하는 것이 맞습니다. 비즈니스 요구사항을 반영한 적절한 결정입니다.
✏️ Learnings added
Learnt from: unifolio0
Repo: samhap-soft/kokomen-backend PR: 341
File: src/main/java/com/samhap/kokomen/payment/domain/TosspaymentsStatus.java:4-10
Timestamp: 2026-03-03T06:01:32.009Z
Learning: kokomen-backend 프로젝트는 가상계좌 결제 기능을 제공하지 않으므로, TosspaymentsStatus enum에 WAITING_FOR_DEPOSIT 상태가 필요하지 않습니다.
Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.
src/main/java/com/samhap/kokomen/payment/service/PaymentFacadeService.java
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Code Review
이 PR은 환불 요청에 멱등성 키를 도입하여 중복 환불을 방지하고, PaymentFacadeService의 cancelPayment 메서드에 분산 락을 적용하는 중요한 개선 사항을 포함하고 있습니다. TosspaymentsStatus 열거형에 한국어 주석을 추가하여 가독성을 높였으며, TosspaymentsClient 및 관련 테스트 코드도 새로운 idempotencyKey 파라미터에 맞춰 성공적으로 업데이트되었습니다. 전반적으로 결제 시스템의 안정성과 신뢰성을 향상시키는 좋은 변경입니다.
| public enum TosspaymentsStatus { | ||
| READY, | ||
| IN_PROGRESS, | ||
| WAITING_FOR_DEPOSIT, |
| public void cancelPayment(CancelRequest request) { | ||
| TosspaymentsPaymentCancelRequest tosspaymentsPaymentCancelRequest = new TosspaymentsPaymentCancelRequest( | ||
| request.cancelReason()); | ||
| String idempotencyKey = UUID.randomUUID().toString(); |
There was a problem hiding this comment.
cancelPayment 메서드에서 idempotencyKey를 UUID.randomUUID().toString()으로 생성하고 있습니다. 이는 각 취소 요청마다 새로운 멱등성 키를 생성하게 됩니다. 만약 네트워크 오류 등으로 인해 동일한 논리적 취소 요청을 재시도해야 하는 경우, 매번 새로운 멱등성 키가 생성되어 토스페이먼츠에서 이를 별개의 요청으로 처리할 수 있습니다. 멱등성 키의 목적이 동일한 요청을 여러 번 보내도 한 번만 처리되도록 하는 것이라면, 특정 paymentKey에 대한 동일한 취소 시도에 대해서는 동일한 멱등성 키를 재사용하는 것이 더 적절할 수 있습니다. 예를 들어, paymentKey와 함께 취소 시도에 대한 고유한 식별자를 조합하여 멱등성 키를 생성하거나, 첫 요청 시 생성된 멱등성 키를 저장하고 재시도 시 재사용하는 방식을 고려해볼 수 있습니다.
There was a problem hiding this comment.
♻️ Duplicate comments (1)
src/main/java/com/samhap/kokomen/payment/service/PaymentFacadeService.java (1)
146-156:⚠️ Potential issue | 🟠 Major환불 멱등성 키를 랜덤 생성하면 재시도 시 중복 취소 위험이 남습니다.
Line 146의
UUID.randomUUID()는 동일 환불 재요청마다 다른 키를 생성합니다. 이 경우 외부 결제사에서 “새 취소 요청”으로 처리될 수 있어, PR 목표(중복 환불 방지)와 충돌합니다. 동일 취소 작업에는 결정적 멱등키를 사용해 주세요.🔧 제안 수정안
+import java.nio.charset.StandardCharsets; import java.util.UUID; @@ - String idempotencyKey = UUID.randomUUID().toString(); + String idempotencyKey = UUID.nameUUIDFromBytes( + ("cancel:" + request.paymentKey()).getBytes(StandardCharsets.UTF_8) + ).toString();🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/main/java/com/samhap/kokomen/payment/service/PaymentFacadeService.java` around lines 146 - 156, Replace the random idempotency key generation (UUID.randomUUID()) with a deterministic key derived from immutable request fields so retries produce the same key: compute idempotencyKey from request.paymentKey() plus a stable refund identifier (e.g., request.refundId() or paymentKey+amount+timestamp-initial) hashed/encoded, initialize that idempotencyKey before calling tosspaymentsConfirmRetryTemplate.execute, and pass it into tosspaymentsClient.cancelPayment(...) so cancelPayment and the retry logic use the same idempotencyKey across attempts.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@src/main/java/com/samhap/kokomen/payment/service/PaymentFacadeService.java`:
- Around line 146-156: Replace the random idempotency key generation
(UUID.randomUUID()) with a deterministic key derived from immutable request
fields so retries produce the same key: compute idempotencyKey from
request.paymentKey() plus a stable refund identifier (e.g., request.refundId()
or paymentKey+amount+timestamp-initial) hashed/encoded, initialize that
idempotencyKey before calling tosspaymentsConfirmRetryTemplate.execute, and pass
it into tosspaymentsClient.cancelPayment(...) so cancelPayment and the retry
logic use the same idempotencyKey across attempts.
ℹ️ Review info
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (1)
src/main/java/com/samhap/kokomen/payment/service/PaymentFacadeService.java
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/test/java/com/samhap/kokomen/payment/service/PaymentFacadeServiceTest.java (1)
278-368: 🧹 Nitpick | 🔵 Trivial결제 취소 재시도 테스트가 누락되었습니다.
cancelPayment에RetryTemplate이 도입되었으나, 결제 승인(confirmPayment)처럼 재시도 시나리오에 대한 테스트가 없습니다. 다음 케이스에 대한 테스트 추가를 권장합니다:
- 5xx 에러 후 재시도 성공
- 네트워크 에러 후 재시도 성공
- 409 (IDEMPOTENT_REQUEST_PROCESSING) 후 재시도 성공
- 재시도 소진 후 예외 발생
💡 테스트 예시
`@Test` void 결제_취소_시_5xx_에러_후_재시도에_성공한다() { // given TosspaymentsPayment payment = TosspaymentsPaymentFixtureBuilder.builder() .paymentKey("payment_key") .build(); payment.updateState(PaymentState.COMPLETED); tosspaymentsPaymentRepository.save(payment); TosspaymentsPaymentResult paymentResult = TosspaymentsPaymentResultFixtureBuilder.builder() .tosspaymentsPayment(payment) .build(); tosspaymentsPaymentResultRepository.save(paymentResult); HttpServerErrorException serverError = mock(HttpServerErrorException.class); when(tosspaymentsClient.cancelPayment(any(), any(), any())) .thenThrow(serverError) .thenReturn(createCancelSuccessResponse()); // when paymentFacadeService.cancelPayment(new CancelRequest("payment_key", "단순 변심")); // then verify(tosspaymentsClient, times(2)).cancelPayment(any(), any(), any()); TosspaymentsPayment updatedPayment = tosspaymentsPaymentRepository.findByPaymentKey("payment_key").orElseThrow(); assertThat(updatedPayment.getState()).isEqualTo(PaymentState.CANCELED); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/test/java/com/samhap/kokomen/payment/service/PaymentFacadeServiceTest.java` around lines 278 - 368, Add missing retry tests for cancelPayment to cover retry behavior introduced by RetryTemplate: create tests in PaymentFacadeServiceTest that use TosspaymentsPaymentFixtureBuilder/TosspaymentsPaymentResultFixtureBuilder to persist a COMPLETED payment, then stub tosspaymentsClient.cancelPayment to first throw (HttpServerErrorException or ResourceAccessException or HttpClientErrorException with status 409 and IDEMPOTENT_REQUEST_PROCESSING) and then return a successful TosspaymentsPaymentResponse; assert paymentFacadeService.cancelPayment succeeds, verify tosspaymentsClient.cancelPayment was called twice (verify(..., times(2))). Also add tests that stub repeated failures to exhaust retries and assert the appropriate InternalServerErrorException is thrown with the expected PaymentServiceErrorMessage. Ensure tests reference tosspaymentsPaymentRepository/tosspaymentsPaymentResultRepository to validate state and result fields after success.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/main/java/com/samhap/kokomen/payment/service/PaymentFacadeService.java`:
- Around line 151-159: The cancel call is reusing
tosspaymentsConfirmRetryTemplate which ties confirm and cancel retry behavior
together; if cancel needs a different retry policy, create a separate
RetryTemplate (e.g., tosspaymentsCancelRetryTemplate) and use it for the cancel
invocation instead of tosspaymentsConfirmRetryTemplate in the block that calls
tosspaymentsClient.cancelPayment(request.paymentKey(),
tosspaymentsPaymentCancelRequest, idempotencyKey); otherwise, add a comment near
tosspaymentsConfirmRetryTemplate explaining intentional reuse so future
maintainers know the choice.
---
Outside diff comments:
In
`@src/test/java/com/samhap/kokomen/payment/service/PaymentFacadeServiceTest.java`:
- Around line 278-368: Add missing retry tests for cancelPayment to cover retry
behavior introduced by RetryTemplate: create tests in PaymentFacadeServiceTest
that use
TosspaymentsPaymentFixtureBuilder/TosspaymentsPaymentResultFixtureBuilder to
persist a COMPLETED payment, then stub tosspaymentsClient.cancelPayment to first
throw (HttpServerErrorException or ResourceAccessException or
HttpClientErrorException with status 409 and IDEMPOTENT_REQUEST_PROCESSING) and
then return a successful TosspaymentsPaymentResponse; assert
paymentFacadeService.cancelPayment succeeds, verify
tosspaymentsClient.cancelPayment was called twice (verify(..., times(2))). Also
add tests that stub repeated failures to exhaust retries and assert the
appropriate InternalServerErrorException is thrown with the expected
PaymentServiceErrorMessage. Ensure tests reference
tosspaymentsPaymentRepository/tosspaymentsPaymentResultRepository to validate
state and result fields after success.
ℹ️ Review info
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (2)
src/main/java/com/samhap/kokomen/payment/service/PaymentFacadeService.javasrc/test/java/com/samhap/kokomen/payment/service/PaymentFacadeServiceTest.java
| TosspaymentsPaymentResponse response = tosspaymentsConfirmRetryTemplate.execute( | ||
| context -> { | ||
| if (context.getRetryCount() > 0) { | ||
| log.warn("토스페이먼츠 환불 승인 재시도 {}회차, paymentKey = {}", | ||
| context.getRetryCount(), request.paymentKey()); | ||
| } | ||
| return tosspaymentsClient.cancelPayment(request.paymentKey(), | ||
| tosspaymentsPaymentCancelRequest, idempotencyKey); | ||
| }); |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
RetryTemplate 재사용은 적절하나, 네이밍 불일치에 주의하세요.
tosspaymentsConfirmRetryTemplate을 취소 로직에도 재사용하고 있습니다. 재시도 정책이 confirm과 cancel에 동일하게 적용되어야 한다면 문제없지만, 향후 두 작업의 재시도 정책을 분리해야 할 경우 별도 템플릿이 필요할 수 있습니다.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/main/java/com/samhap/kokomen/payment/service/PaymentFacadeService.java`
around lines 151 - 159, The cancel call is reusing
tosspaymentsConfirmRetryTemplate which ties confirm and cancel retry behavior
together; if cancel needs a different retry policy, create a separate
RetryTemplate (e.g., tosspaymentsCancelRetryTemplate) and use it for the cancel
invocation instead of tosspaymentsConfirmRetryTemplate in the block that calls
tosspaymentsClient.cancelPayment(request.paymentKey(),
tosspaymentsPaymentCancelRequest, idempotencyKey); otherwise, add a comment near
tosspaymentsConfirmRetryTemplate explaining intentional reuse so future
maintainers know the choice.
closed #337
작업 내용
스크린샷
참고 사항