From 0becd8ae978a8d643b5b1a26c0a9cf225fa05813 Mon Sep 17 00:00:00 2001 From: JeongHoon Lee Date: Mon, 7 Jul 2025 02:52:26 +0900 Subject: [PATCH 1/3] chore: Rename S3 event listener phase from BEFORE_COMMIT to AFTER_COMMIT --- .../file/adapter/outbound/s3/ProfileImageUpdateListener.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/fontory/fontorybe/file/adapter/outbound/s3/ProfileImageUpdateListener.java b/src/main/java/org/fontory/fontorybe/file/adapter/outbound/s3/ProfileImageUpdateListener.java index ecfc80f..46c254b 100644 --- a/src/main/java/org/fontory/fontorybe/file/adapter/outbound/s3/ProfileImageUpdateListener.java +++ b/src/main/java/org/fontory/fontorybe/file/adapter/outbound/s3/ProfileImageUpdateListener.java @@ -28,8 +28,8 @@ void init() { profileImagePrefix = s3Config.getPrefix(FileType.PROFILE_IMAGE); } - @TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT) - public void beforeCommit(ProfileImageUpdatedEvent event) { + @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT) + public void afterCommit(ProfileImageUpdatedEvent event) { s3.copyObject(CopyObjectRequest.builder() .sourceBucket(profileImageBucketName) .sourceKey(profileImagePrefix + "/" + event.getTempKey()) From 57b713fa42a7a36323aeb04fa68f4faf34ee5072 Mon Sep 17 00:00:00 2001 From: JeongHoon Lee Date: Mon, 7 Jul 2025 02:54:30 +0900 Subject: [PATCH 2/3] =?UTF-8?q?fix:=20Add=20try=E2=80=93catch=20around=20S?= =?UTF-8?q?3=20copy/delete=20in=20afterCommit=20listener?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Log errors with tempKey and fixedKey - Rethrow exception so @AfterThrowing aspect can pick it up --- .../s3/ProfileImageUpdateListener.java | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/fontory/fontorybe/file/adapter/outbound/s3/ProfileImageUpdateListener.java b/src/main/java/org/fontory/fontorybe/file/adapter/outbound/s3/ProfileImageUpdateListener.java index 46c254b..17b58cc 100644 --- a/src/main/java/org/fontory/fontorybe/file/adapter/outbound/s3/ProfileImageUpdateListener.java +++ b/src/main/java/org/fontory/fontorybe/file/adapter/outbound/s3/ProfileImageUpdateListener.java @@ -30,17 +30,23 @@ void init() { @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT) public void afterCommit(ProfileImageUpdatedEvent event) { - s3.copyObject(CopyObjectRequest.builder() - .sourceBucket(profileImageBucketName) - .sourceKey(profileImagePrefix + "/" + event.getTempKey()) - .destinationBucket(profileImageBucketName) - .destinationKey(profileImagePrefix + "/" + event.getFixedKey()) - .build()); + try { + s3.copyObject(CopyObjectRequest.builder() + .sourceBucket(profileImageBucketName) + .sourceKey(profileImagePrefix + "/" + event.getTempKey()) + .destinationBucket(profileImageBucketName) + .destinationKey(profileImagePrefix + "/" + event.getFixedKey()) + .build()); - s3.deleteObject(DeleteObjectRequest.builder() - .bucket(profileImageBucketName) - .key(profileImagePrefix + "/" + event.getTempKey()) - .build()); + s3.deleteObject(DeleteObjectRequest.builder() + .bucket(profileImageBucketName) + .key(profileImagePrefix + "/" + event.getTempKey()) + .build()); + } catch (Exception e) { + log.error("Error while copying/deleting profile image to s3: tempKey={}, fixedKey={}", + event.getTempKey(), event.getFixedKey(), e); + throw e; + } } @TransactionalEventListener(phase = TransactionPhase.AFTER_ROLLBACK) From 3989d23ae085ef70de505a079c84eaca626eba0e Mon Sep 17 00:00:00 2001 From: JeongHoon Lee Date: Mon, 7 Jul 2025 03:10:07 +0900 Subject: [PATCH 3/3] =?UTF-8?q?fix:=20Wrap=20sendToDiscord=20in=20try?= =?UTF-8?q?=E2=80=93catch=20to=20log=20notification=20failures?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Catch RestTemplate/IO errors and log warning - Prevent async exceptions from bubbling up --- .../DiscordExceptionLoggingAspect.java | 34 +++++++++++-------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/src/main/java/org/fontory/fontorybe/common/adapter/outbound/DiscordExceptionLoggingAspect.java b/src/main/java/org/fontory/fontorybe/common/adapter/outbound/DiscordExceptionLoggingAspect.java index 5280b43..ed397da 100644 --- a/src/main/java/org/fontory/fontorybe/common/adapter/outbound/DiscordExceptionLoggingAspect.java +++ b/src/main/java/org/fontory/fontorybe/common/adapter/outbound/DiscordExceptionLoggingAspect.java @@ -156,24 +156,28 @@ private String buildStackTrace(Throwable ex) { */ @Async protected void sendToDiscord(String payloadJson, String fullStackTrace) { - byte[] stackTraceBytes = fullStackTrace.getBytes(StandardCharsets.UTF_8); - ByteArrayResource stackTraceResource = new ByteArrayResource(stackTraceBytes) { - @Override - public String getFilename() { - return "stacktrace.txt"; - } - }; + try { + byte[] stackTraceBytes = fullStackTrace.getBytes(StandardCharsets.UTF_8); + ByteArrayResource stackTraceResource = new ByteArrayResource(stackTraceBytes) { + @Override + public String getFilename() { + return "stacktrace.txt"; + } + }; - LinkedMultiValueMap multipartBody = new LinkedMultiValueMap<>(); - multipartBody.add("payload_json", payloadJson); - multipartBody.add("file", stackTraceResource); + LinkedMultiValueMap multipartBody = new LinkedMultiValueMap<>(); + multipartBody.add("payload_json", payloadJson); + multipartBody.add("file", stackTraceResource); - HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.MULTIPART_FORM_DATA); + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.MULTIPART_FORM_DATA); - HttpEntity> requestEntity = - new HttpEntity<>(multipartBody, headers); + HttpEntity> requestEntity = + new HttpEntity<>(multipartBody, headers); - restTemplate.postForEntity(discordWebhookUrl, requestEntity, String.class); + restTemplate.postForEntity(discordWebhookUrl, requestEntity, String.class); + } catch (Exception e) { + log.warn("Exception occured while sending stacktrace to Discord: {}", e); + } } } \ No newline at end of file