오늘 열심히 새로운 프로젝트를 위한 분석설계 작업을 하던 중 옆 동료들과 잠시 머리도 식힐겸 이야기를 하다가 연동 시스템에서 HTTP 요청 시 Spring Boot 기반의 Multi Instance 서버들이 해당 요청을 Broadcast 받은 것 처럼 각 Instance 의 State 들을 업데이트 해야 하는 요건이 생겨 논의하고 있다는걸 알게 되었다.
머리 식히러 왔어서 자리를 피하고 싶었으나.. 최소한의 Effort 로 구현하고 싶고, Message Broker 나 Redis 같은 IMDB, Zookeper 등을 사용하지 않았으면 좋겠다 하고, NoSQL DB 로 MongoDB 를 사용하고 있으나 DB Polling 으로 인해 부하를 주고싶지 않다고 하고..
잠시 생각하던 중 MongoDB 에서 Collection 의 변경이 일어나면 이 이벤트를 Listen 할 수 있는 기능이 생각나서 해당 기능을 사용해서 구현해보는게 어떤가 이야기 했다.
말이 나온김에 ChatGPT 를 통해 Sample Code 를 만들어 보라 시켜봤다.
GPT
write a pub sub example springboot java code using mongodb
ChatGPT 놈의 조언
Here is an example of a basic implementation of the publish-subscribe pattern in a Spring Boot application using MongoDB as the message broker:
@Service
public class PublisherService {
private final MongoTemplate mongoTemplate;
@Autowired
public PublisherService(MongoTemplate mongoTemplate) {
this.mongoTemplate = mongoTemplate;
}
public void publishMessage(String message) {
mongoTemplate.save(new Message(message));
}
}
@Document
class Message {
private String message;
public Message(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
}
@Service
public class SubscriberService {
private final MongoTemplate mongoTemplate;
@Autowired
public SubscriberService(MongoTemplate mongoTemplate) {
this.mongoTemplate = mongoTemplate;
}
@PostConstruct
public void subscribe() {
mongoTemplate.getDb().getCollection("message").watch().forEach((Consumer<ChangeStreamDocument<Document>>) changeStreamDocument -> {
Message message = mongoTemplate.getConverter().read(Message.class, changeStreamDocument.getFullDocument());
System.out.println("Received message: " + message.getMessage());
});
}
}
이녀석 초반에는 무늬만 pub sub 같은 코드를 내놓더니만 몇번 심도있는(?) 대화를 해주고 난 이후에는 Collection 의 watch() 로 ChangeStreamDocument 를 사용해 Event 를 Listen 하는 제대로 되어보이는 코드를 내어준다. 한번 테스트 해보자.
테스트 코드
package mongo.account;
import lombok.Getter;
import lombok.Setter;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
@Getter
@Setter
@Document(collection = "account")
public class Account {
@Id
private String id;
private String userName;
private String email;
}
@Repository
public interface AccountRepository extends MongoRepository<Account, String> {
Account findAccountByUserName(String userName);
List<Account> findAccountsByUserName(String userName);
@Query(value = "distinct('userName')", fields = "userName")
List<String> findDistinct();
}
@Service
@RequiredArgsConstructor
@Slf4j
public class AccountSubscriber {
private final MongoTemplate mongoTemplate;
@PostConstruct
public void subscribe() {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
log.info("Registering Subscriber");
mongoTemplate.getDb().getCollection("account").watch()
.forEach((Consumer<ChangeStreamDocument<Document>>) changeStreamDocument -> {
Account account = mongoTemplate.getConverter().read(Account.class, changeStreamDocument.getFullDocument());
log.info("[{}] userName : {}", changeStreamDocument.getOperationType(), account!=null?account.getUserName():null);
});
log.info("Subscriber Registered");
}
});
t.start();
}
}
@Bean
@Order(1)
public ApplicationRunner applicationRunner() {
return args -> {
Account account = new Account();
account.setUserName("joon");
account.setEmail("abcdef@naver.com");
accountRepository.insert(account);
log.info("Done");
List<Account> result = accountRepository.findAccountsByUserName("joon");
log.info("result 1 : {}", result.size());
// .... 생략 ...
accountRepository.deleteAll();
};
}
실행결과
오늘도 chatGPT 가 나름 참고할만한 코드를 잘 만들어주었다.
물론 그대로 갖다 붙여넣는다고 원하는 동작을 하지는 못한다 (뭐 이러면 개발자 죽어야지..). watch() 에서 blocking 되기땜에 thread 로 빼주는 코드를 추가해주는 센스까지는 아직 chatGPT 가 못내주기는 하다마는 그래도 이게 어디냐..
구글링 해서 찾을수도 있지만 chatGPT 를 썼을 때에는 좀더 "덜 읽어도" 된다는게 좋은것 같다
'AI 응용 > 개발자의 AI' 카테고리의 다른 글
티스토리의 댓글 테러, ChatGPT 와 CoPilot 과 함께 처리 #3 (2) | 2024.06.08 |
---|---|
티스토리의 댓글 테러, ChatGPT 와 CoPilot 과 함께 처리 #2 (4) | 2024.06.07 |
티스토리의 댓글 테러, ChatGPT 와 CoPilot 과 함께 처리 #1 (0) | 2024.06.07 |
AICC 솔루션 개발을 하려면 뭘 고려해야하나? (0) | 2023.01.28 |