Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,16 @@ dependencies {
testImplementation "org.testcontainers:junit-jupiter" // JUnit 5 연동
testImplementation 'org.testcontainers:jdbc'
testImplementation 'de.flapdoodle.embed:de.flapdoodle.embed.mongo:4.11.0'
testImplementation "org.testcontainers:mongodb"


//Slack
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'com.slack.api:slack-api-client:1.43.0'

//AWS
implementation "software.amazon.awssdk:eventbridge"
implementation platform('software.amazon.awssdk:bom:2.20.83')
}

tasks.named('test') {
Expand Down
Empty file modified gradlew
100644 → 100755
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
import store.slackjudge.batch.common.CalculateSnapShotDate;

Expand All @@ -16,6 +17,7 @@
@Slf4j
@Component
@RequiredArgsConstructor
@Profile("!test")
public class SlackJudgeBatchRunner implements CommandLineRunner {
private final JobLauncher jobLauncher;
private final Job slackJudgeBatch;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.transaction.PlatformTransactionManager;
import store.slackjudge.batch.tasklet.*;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
import org.springframework.batch.core.annotation.BeforeJob;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
import store.slackjudge.batch.common.CalculateSnapShotDate;
import store.slackjudge.batch.infra.aws.EventBridgePublisher;
import store.slackjudge.batch.infra.slack.SlackNotificationService;

import java.time.Duration;
Expand All @@ -23,6 +25,7 @@ public class BatchJobListener {
private final BatchLogger logger;
private final SlackNotificationService notificationService;
private final CalculateSnapShotDate calculateSnapShotDate;
private final EventBridgePublisher eventBridgePublisher;

/*==========================
*
Expand Down Expand Up @@ -57,7 +60,7 @@ public void beforeJob(JobExecution jobExecution) {
* @parm jobExecution : Job 실행 중에 발생 정보 저장 객체
* @return
* @author kimdoyeon
* @version 1.0.0
* @version 1.1.0
* @date 25. 12. 17.
*
==========================**/
Expand Down Expand Up @@ -88,6 +91,7 @@ public void afterJob(JobExecution jobExecution) {
);
LocalDateTime occurredTime=calculateSnapShotDate.now();

String status="";
//배치 종료 slack 알림 추가
if (jobExecution.getStatus().isUnsuccessful()) {
//fail 예외 객체 없으면 기본 값 => Batch failed 출력
Expand All @@ -97,9 +101,14 @@ public void afterJob(JobExecution jobExecution) {

//배치 실패 slack 알림 전송
notificationService.notifyBatchFailed(occurredTime, reason);
status="FAILED";
} else {
//배치 성공 slack 알림 전송
notificationService.notifyBatchSuccess(durationMs, total, newUser, updated, failedUser,occurredTime);
status="SUCCESS";
}

//배치 종료 시 AWS EventBridge 전송
eventBridgePublisher.publishBatchSuccessCompleteEvent(String.valueOf(jobExecution.getJobInstance().getInstanceId()),status);
}
}
14 changes: 14 additions & 0 deletions src/main/java/store/slackjudge/batch/config/EventBridgeConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package store.slackjudge.batch.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import software.amazon.awssdk.services.eventbridge.EventBridgeClient;

@Configuration
public class EventBridgeConfig {
@Bean
public EventBridgeClient eventBridgeClient(){
return EventBridgeClient.builder().build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package store.slackjudge.batch.infra.aws;

import java.io.Serializable;

public record BatchEventDetail(
String jobId,
String status
) implements Serializable {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package store.slackjudge.batch.infra.aws;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;
import software.amazon.awssdk.services.eventbridge.EventBridgeClient;
import software.amazon.awssdk.services.eventbridge.EventBridgeClientBuilder;
import software.amazon.awssdk.services.eventbridge.model.PutEventsRequest;
import software.amazon.awssdk.services.eventbridge.model.PutEventsRequestEntry;

@Service
@RequiredArgsConstructor
public class EventBridgePublisher {
private final EventBridgeClient bridgeClientBuilder;
private final ObjectMapper mapper;

@Value("${aws.eventbridge.source}")
private String source;

@Value("${aws.eventbridge.detail-type}")
private String detailType;

public void publishBatchSuccessCompleteEvent(String jobId, String status) {
try {
String detail = mapper.writeValueAsString(new BatchEventDetail(jobId, status));
PutEventsRequestEntry eventsRequestEntry = PutEventsRequestEntry.builder()
.source(source)
.detailType(detailType)
.detail(detail)
.build();

PutEventsRequest request = PutEventsRequest.builder()
.entries(eventsRequestEntry)
.build();

bridgeClientBuilder.putEvents(request);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}

}

}
7 changes: 6 additions & 1 deletion src/main/resources/batch.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,9 @@ spring:
initialize-schema: always
job:
enabled: false
name: 'SlackJudge Batch Worker #1'
name: 'SlackJudge Batch Worker #1'

aws:
eventbridge:
source: com.slackJudge.batch
detail-type: Batch Finished
24 changes: 24 additions & 0 deletions src/test/java/store/slackjudge/batch/MongoContainer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package store.slackjudge.batch;

import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.testcontainers.containers.MongoDBContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;

@Testcontainers
@ActiveProfiles("test")
public class MongoContainer {
@Container
static final MongoDBContainer mongo=new MongoDBContainer("mongo:6.0")
.withReuse(true);

@DynamicPropertySource
static void mongoProperties(DynamicPropertyRegistry registry){
registry.add(
"spring.data.mongodb.uri",
mongo::getReplicaSetUrl
);
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,16 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest;
import org.springframework.context.annotation.Import;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.testcontainers.containers.MongoDBContainer;
import store.slackjudge.batch.MongoContainer;
import store.slackjudge.batch.SlackjudgeApplication;
import store.slackjudge.batch.infra.mongo.document.SnapShotId;
import store.slackjudge.batch.infra.mongo.document.UserSolvedSnapShotDocument;
Expand All @@ -26,10 +30,9 @@

@ContextConfiguration(classes = SlackjudgeApplication.class)
@DataMongoTest
@ExtendWith(SpringExtension.class)
@DirtiesContext
@Import(MongoAutoConfiguration.class)
@ActiveProfiles("test")
class UserSolvedSnapShotRepositoryTest {
class UserSolvedSnapShotRepositoryTest extends MongoContainer {
@Autowired
private UserSolvedSnapShotRepository repository;

Expand Down
5 changes: 5 additions & 0 deletions src/test/resources/application-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,8 @@ slack:
logging:
level:
root: WARN

aws:
eventbridge:
enabled: false
region: ap-northeast-2
Loading