'pubsub'에 해당되는 글 1건

오늘 열심히 새로운 프로젝트를 위한 분석설계 작업을 하던 중 옆 동료들과 잠시 머리도 식힐겸 이야기를 하다가 연동 시스템에서 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 를 썼을 때에는 좀더 "덜 읽어도" 된다는게 좋은것 같다

반응형
블로그 이미지

Good Joon

IT Professionalist Since 1999

,