ZSMQ 를 이용해서 5분만에 메시징 플랫폼을 구성해봅시다.
예제는 다음과 같은 상황을 구현합니다.
- order-service 에서 두가지 이벤트를 발행합니다.
ORDER-CONFIRMED
ORDER-CANCELED
- delivery-service 에서는 두가지 이벤트를 consume 합니다
ORDER-CONFIRMED
의 payload 는 객체 형태입니다.ORDER-CANCELED
의 payload 는 String 형태입니다.
구성 순서는 README 에 존재하는 quick start 를 그대로 따릅니다.
- run messaging server and dashboard
- gradle dependency
- configure property
- just U.S.E it
우선 도커를 이용해서 messaging 서버와 dashboard 를 실행시킵니다.
잘 실행된 것을 확인합니다.
gradle 의존성을 추가하기 위해서 두개의 spring application 을 생성해줍니다.
그리고 각각의 build.gradle
에서 의존성을 추가합니다.
version 은 release note 를 확인해주세요
두 애플리케이션의 용도는 서로 다릅니다.
- order-service (produce)
- delivery-service (consume)
order-service 는 메시지를 발행하는 애플리케이션입니다.
다음과 같이 application.yml
설정하세요
zsmq.listening
을 false 로 준다는 것은 메시지 리스너 스레드를 실행시키지 않겠다는 뜻입니다.
간단한 Order 객체를 정의하고 Order 객체를 delivery-service
로 전달할 것입니다.
@Value(staticConstructor = "of")
public class Order {
String orderId;
String address;
int price;
}
그리고 간단한 message publisher 를 구현해줍니다.
@Component
@RequiredArgsConstructor
public class MessagePublisher {
private final ZolaQueueMessageTemplate template;
public void sendConfirmedMessage(Order order) {
template.convertAndSend("ORDER-CONFIRMED", order);
}
public void sendCanceledMessage(String orderId) {
template.convertAndSend("ORDER-CANCELED", orderId);
}
}
ZolaQueueMessageTemplate
를 이용해서 convert 와 send 를 쉽게 수행할 수 있습니다.
객체 형식으로 전달할 수도 있고 단순 문자열 형식으로 전달할 수 있습니다.
@RestController
@RequiredArgsConstructor
public class OrderController {
private static final Order[] SAMPLE_ORDERS = {
Order.of(UUID.randomUUID().toString(), "Seoul", 125_000_000),
Order.of(UUID.randomUUID().toString(), "New York", 25_602_900),
Order.of(UUID.randomUUID().toString(), "singapore", 5_120_000),
Order.of(UUID.randomUUID().toString(), "tokyo", 9_000_000),
};
private final MessagePublisher publisher;
@GetMapping("/orders/{index}/confirm")
public boolean confirm(@PathVariable int index) {
try {
Order order = SAMPLE_ORDERS[index];
publisher.sendConfirmedMessage(order);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
@GetMapping("/orders/{index}/cancel")
public boolean cancel(@PathVariable int index) {
try {
String orderId = SAMPLE_ORDERS[index].getOrderId();
publisher.sendCanceledMessage(orderId);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
}
간단한 controller 를 구현해줍시다.
2개의 api 가 존재합니다.
orders/{index}/confirm
: 객체를 publishorders/{index}/cancel
: 문자열을 publish
이제 message 를 produce 하는 쪽은 모든 준비가 끝났습니다.
delivery-service
는 메시지를 consume 할 것이기 때문에 다음과 같이 yml 에 리스닝 스레드를 활성화시켜줘야 합니다.
zsmq.listening
를 true 로 설정하세요.
두개의 큐를 consuming 할 다음 두 processor 를 만들어주세요.
order-service
의 orders/{index}/cancel
가 호출되면 발행되는 queue 를 consume 합니다.
@Component
@ZolaConsumer
@Slf4j
public class OrderCanceledProcessor {
@ZolaMessageListener(queueName="ORDER-CANCELED", deletionPolicy = DeletionPolicy.ALWAYS)
public void listen(String message) {
log.info("order was canceled id: [{}]", message);
}
}
@ZolaMessageListener
를 사용할 때 메서드의 파라미터는 하나의 String 타입 이어야 합니다.
해당 매개변수로 consume 한 데이터를 전달합니다.
order-service
의 orders/{index}/confirm
가 호출되면 발행되는 queue 를 consume 합니다.
@Component
@ZolaConsumer
@Slf4j
public class OrderConfirmedProcessor {
@ZolaMessageListener(queueName="ORDER-CONFIRMED", deletionPolicy = DeletionPolicy.ALWAYS)
public void listen(String message) {
log.info("json : {}", message);
Order order = ZolaJsonSerializer.getInstance().deserialize(message, Order.class);
log.info("order was confirmed : id : {}, address: {}, price: {}", order.getOrderId(), order.getAddress(), order.getPrice());
}
}
Object 를 publish 한다면 json 형태로 데이터를 받아옵니다.
ZolaJsonSerializer
를 사용하면 json 을 쉽게
이제 모든 개발이 끝났습니다.
실행 결과를 확인해봅시다
우선 큐를 만들어야 합니다.
localhost:8290
으로 실행되는 dashboard 에 접속하세요.
우리는 2개의 큐를 생성해야 합니다. 오른쪽의 탭에서 QUEUE 생성 메뉴를 클릭하고 큐를 추가하세요
두개의 큐를 모두 추가해줍니다.
그리고 order-service
와 delivery-service
를 실행시켜주세요
그리고 order-service
에 api 를 전송해봅시다.
그럼 아래와 같이 로그가 찍히는 것을 확인할 수 있습니다.
하나는 json 형태 그대로, 다른 하나는 객체에서 꺼내온대로 잘 출력되었네요,
이제 나머지 cancel 도 호출하면 동일하게 결과가 나올 것입니다.