728x90
반응형

Kafka에 대한 설정 및 Producer와 Consumer의 예제에 대해서 알아보았다. 그럼 이 코드들이 잘 동작하는지는 어떻게 확인해야할까?

실제 서비스들 간의 메세지 전송 및 결과를 확인하기 위해서는 테스트 환경을 구축하여 서비스를 띄운 후에 테스트 해보는 것이 가장 정확하다. Docker compose로 Kafka broker와 Zookeeper를 띄우고 Bootstarp address에 Kafka broker 주소를 넣어준 뒤 서비스를 띄워서 테스트를 하면된다. 

 

하지만, 이러한 환경은 귀찮은 면이 있다. 항상 테스트를 위해서 서비스를 띄워두는 것은 리소스 낭비이다. 그래서 Kafka의 메세지 전송을 테스트 할 수 있는 환경이 필요하다. Spring boot 환경에서는 이를 테스트 할 수 있는 라이브러리를 제공하고 있다. 

아래의 라이브러리가 그것이며, 이름은 Spring kafka test library 이다. 

<dependency>
    <groupId>org.springframework.kafka</groupId>
    <artifactId>spring-kafka-test</artifactId>
    <scope>test</scope>
</dependency>

 

위의 Configuration을 추가하면 Embedded kafka 를 사용할 수 있게 되고, 이 환경을 통해서 Message 전송을 임의로 만들 수 있게 된다. 

단, Container 환경에서 Embedded kafka로 테스트를 진행하면 정상적으로 진행되지 않다. 
현재, 나의 환경이 Jenkins를 Kubernetes 내부에 띄우고 Pod agent로 Docker Image build 및 Release Job을 수행하고 있고, 이때 Unit test를 수행하여 코드의 안정성을 확인하고 있다. 하지만, Embedded kafka관련 Test는 수행하고 못하고 있다. 

 

Test 예제

application-test.yaml

Embedeed kafka를 사용하기 위해서는 Embedded kafka에서 띄우는 서버를 사용하여야 한다. 

# kafka
kafka:
  bootstrap:
    addresses: ${spring.embedded.kafka.brokers:localhost:9092}

 

Essential Configuration (JUnit5)

Embedded kafka를 사용하기 위해서는 필수적으로 넣어주어야 하는 Configuration 이 있다. 

우선 @EmbeddedKafka annotation으로 Embedded Kafka를 추가해 준다. 그리고 이 Embedded kafka가 동작하기 위해서는 Integration Test 환경으로 수행되어야 한다. 그 말은 Spring 의 Dependency가 사용되는 환경에서 수행되어야 하기 때문에 @SpringbootTest annotation이 추가되어야 하고, 그와 더불어 @ExtendWith(SpringExtension.class)가 추가되어야 정상적인 동작이 된다. 이러한 셋팅은 JUnit5 기반으로 테스트 될때이며 JUnit4는 그 방법이 다르다. 

@Slf4j
@Tag("embedded-kafka-test")
@SpringBootTest
@ExtendWith(SpringExtension.class)
@EmbeddedKafka
@AutoConfigureMockMvc
@TestPropertySource(properties = "spring.config.location=classpath:application-test.yaml")
public class JwtTokenMessageServiceImplTest {
...
}

 

Kafka Broker Configuration

Embedded Kafka의 Broker를 셋팅해주는 부분이다. @Autowired annotation으로 Dependency Injection을 해주면 된다. 

Broker count는 2개, Partition은 2개로 설정해 주었다. 마지막은 설정과 동시에 생성할 Topic인데, Topic이 여러 개 일 때에는 뒤쪽으로 ,(콤마)로 구분하여 계속 넣어주면 된다. 

Intellij를 사용한다면 이 부분에서 @Autowired 로 Dependency Injection시 Dependecy를 찾을 수 없다는 Inspection Message를 받을 수 있다. 이 부부은 Intellij의 문제로 난 이 Inspection의 level을 warning으로 바꾸었다. 

2022.02.05 - [Tool/IntelliJ] - [Intellij] @Autowired inspection 오류 무시하는 방법

...
@Autowired
private EmbeddedKafkaBroker embeddedKafkaBroker = new EmbeddedKafkaBroker(
        2,
        true,
        2,
        JwtTokenTopic.TOPIC_CREATE_JWT_TOKEN
);
...

 

Producer configuration

Producer configuration은 간단하다. Produecer Property는 Default 셋팅으로 설정하였다. 그리고 Key Serializer는 String, Value Serialilzer는 Json으로 설정하였다. 이 부분의 서비스에서 사용하는 설정과 동일하게 하면 된다. 

private Producer<String, Object> configEmbeddedKafkaProducer() {
    Map<String, Object> producerProperties = new HashMap<>(KafkaTestUtils.producerProps(embeddedKafkaBroker));
    return new DefaultKafkaProducerFactory<>(producerProperties, new StringSerializer(), new JsonSerializer<>()).createProducer();
}

 

Consumer Configuration

Consumer의 설정은 복잡하다. 왜냐하면 Kafka의 Consumer의 설정에서 보았듯이 KafkaLinstener의 설정이 추가되어야 하기 때문이다. Embedded Kafka도 마찬가지로 Produer가 보내는 메세지가 Topic에 들어오면 Listener가 해당 메세지를 처리하도록 해야하기 때문이다. 

 

1) 우선 Consumer Property 셋팅을 한다. 기본 셋팅을 가지고 가되, Auto commit만 false로 셋팅하였다. 나의 코드에서 Commit을 수동을 하고 있다. 

2) ConsumerFactory를 만들고, Container Property를 topic과 함께 생성하고, KafkaMessageListenerContainer를 만든다. 

3) CusumerRecord를 순차적으로 저장시키고, 순차적으로 처리하기 위해, BlockingQueue로 선언한다. 

4) 이후, 생성된 KafkaMessageListenerContainer에 Listener 함수를 추가한다. 이 함수에서는 Log로 Message를 출력하고, BlockQueue에 record를 추가한다. 이 record를 필요한 시점에 뽑아서 확인한다.

private KafkaMessageListenerContainer<String, String> container;

private BlockingQueue<ConsumerRecord<String, String>> records;

private void configEmbeddedKafkaConsumer(String topic) {
    Map<String, Object> consumerProperties = new HashMap<>(KafkaTestUtils.consumerProps("auth", "false", embeddedKafkaBroker));

    DefaultKafkaConsumerFactory<String, String> consumerFactory = new DefaultKafkaConsumerFactory<>(consumerProperties);

    ContainerProperties containerProperties = new ContainerProperties(topic);
    container = new KafkaMessageListenerContainer<>(consumerFactory, containerProperties);

    records = new LinkedBlockingDeque<>();

    container.setupMessageListener((MessageListener<String, String>) record -> {
                LOGGER.debug("test-listener received message='{}'",
                        record.value());
                records.add(record);
    });
    container.start();

    ContainerTestUtils.waitForAssignment(container, embeddedKafkaBroker.getPartitionsPerTopic());
}

 

전체 Configuration 부분 코드

@Slf4j
@SpringBootTest
@ExtendWith(SpringExtension.class)
@EmbeddedKafka
@AutoConfigureMockMvc
@TestPropertySource(properties = "spring.config.location=classpath:application-test.yaml")
public class JwtTokenMessageServiceImplTest {
    @Autowired
    private JwtTokenMessageService jwtTokenMessageService;

    @MockBean
    private JwtTokenProvider jwtTokenProvider;

    @Autowired
    private EmbeddedKafkaBroker embeddedKafkaBroker = new EmbeddedKafkaBroker(
            2,
            true,
            2,
            JwtTokenTopic.TOPIC_CREATE_JWT_TOKEN
    );

    private KafkaMessageListenerContainer<String, String> container;

    private BlockingQueue<ConsumerRecord<String, String>> records;

    @BeforeEach
    void setUp() {}

    private void configEmbeddedKafkaConsumer(String topic) {
        Map<String, Object> consumerProperties = new HashMap<>(KafkaTestUtils.consumerProps("auth", "false", embeddedKafkaBroker));

        DefaultKafkaConsumerFactory<String, String> consumerFactory = new DefaultKafkaConsumerFactory<>(consumerProperties);

        ContainerProperties containerProperties = new ContainerProperties(topic);
        container = new KafkaMessageListenerContainer<>(consumerFactory, containerProperties);

        records = new LinkedBlockingDeque<>();

        container.setupMessageListener((MessageListener<String, String>) record -> {
                    LOGGER.debug("test-listener received message='{}'",
                            record.value());
                    records.add(record);
        });
        container.start();

        ContainerTestUtils.waitForAssignment(container, embeddedKafkaBroker.getPartitionsPerTopic());
    }

    private Producer<String, Object> configEmbeddedKafkaProducer() {
        Map<String, Object> producerProperties = new HashMap<>(KafkaTestUtils.producerProps(embeddedKafkaBroker));
        return new DefaultKafkaProducerFactory<>(producerProperties, new StringSerializer(), new JsonSerializer<>()).createProducer();
    }

    @AfterEach
    void tearDown() {
        container.stop();
    }
}

 

Producer Test Code예제

void testCreateMessageForJwtTokenCache() throws InterruptedException, JsonProcessingException {
	// Consumer 생성
    configEmbeddedKafkaConsumer(JwtTokenTopic.TOPIC_CREATE_JWT_TOKEN);
	
    Account account = TestAccountBuilder.accountWithToken();
	
    // 전송할 테스트 메세지 생성
    JwtTokenMessage.CreateMessage createMessage = JwtTokenMessage.CreateMessage.from(account, null);
    String expectedMessage = objectMapper.writeValueAsString(createMessage);

	// 확인하지 않을 함수에 대한 Mocking
    when(jwtTokenProvider.getExpiredDate(any())).thenReturn(null);

	// Embedded kafka로 Message 전송
    jwtTokenMessageService.creteJwtTokenCache(account);

	// BlockingQueue에 메세지를 가져옴. 10초 동안 메세지가 들어오지 않으면 Error 발생
    ConsumerRecord<String, String> record = records.poll(10, TimeUnit.SECONDS);
    
    
	// 수신한 메세지 확인
    assertThat(record).isNotNull();
    assertThat(record.value()).isEqualTo(expectedMessage);
    assertThat(record).has(key(null));
}

 

Consumer Test Code 예제

void testCreateMessageForJwtTokenCache() {
	// 전송할 메세지 생성
    JwtTokenMessage.CreateMessage createMessage = new JwtTokenMessage.CreateMessage();
    createMessage.setAccountId(1L);
    createMessage.setJwtToken("test-jwtToken");
    createMessage.setExpiration(120L);

	// 메세지를 사용하여 ProducerRecord를 생성한다.
    ProducerRecord<String, Object> producerRecord = new ProducerRecord<>(JwtTokenTopic.TOPIC_CREATE_JWT_TOKEN, createMessage);
    // 메세지 전송
    producer.send(producerRecord);
    producer.flush();

	// Mocking
    when(jwtTokenService.create(any())).thenReturn(TestJwtTokenBuilder.defaultJwtToken());

	// Consumer가 메세지를 잘 받아서 Listener가 수행되는지를 확인 (Listener의 특정 Function이 수행되는지를 확인)
    verify(jwtTokenService, timeout(10000L).times(1)).create(any());
}

 

이 정도면 간단한 메세지 전송 여부는 확인이 가능하다. 

728x90
반응형
728x90
반응형

오늘은 캐나다 College 에 대해 이해하는 포스트를 써보고자 한다.

 

유학 후 이민을 오는 사람들 

유학 후 이민을 오는 대상은 젊은 학생들이 당연히 가장 많다. 고등학교를 졸업하고 바로 유학을 와서 공부를 하는 경우도 있고, 대학을 나온 후에 캐나다에 정착을 위해 다른 전공을 찾아서 오는 사람들도 있다. 그리고, 캐나다에 직업을 바로 구하지 못해서 가족과 함께 이민을 오면서 학교를 찾는 경우가 있다. 난 이 경우에 속한다. 

 

 부부 중 한명이 학업을 진행하게 되면 나머지 한 명에게는 오픈 워크퍼밋이 나오게 되어 한명은 일을 하고 한명을 학교를 다니게 된다. 이 오픈 퍼밋이 스터디 퍼밋과 묶여 있다보니, 영주권이 나올 때까지는 학업을 진행을 해야 한다. 그렇다 보니 가족을 데리고 오게 되는 30~50대의 부모들은 늦은 나이에 공부를 하게 되는 어려움에 직면하게 된다. 

 

 하지만 가장의 입장에서 수입 비해 지출이 많아질 수 밖에 이 시기에 스트레스를 받지 않고 공부를 하기란 쉽지 않다. 만약, 사회 초년생부터 꾸준히 일을 하면서 돈을 벌어왔다면 더 그럴 것이다. 나도 대학 졸업 후 쉼없이 일을 했고, 그 소득으로 가정을 꾸려왔기 때문에 돈을 벌지 않고 공부하는 것이 엄청난 스트레스로 다가왔다. 그리고, 외국인 학생의 학비가 너무 비싸다. 

 

  뭐, 이미 유학 후 이민이라는 것을 결정하고 실행하신 분이라면 자금적인 부분에 대해서 고민을 많이 하고 학교 생활동안 지낼 수 있는 여윳돈을 준비해서 올 것이기 때문에 이것은 사람의 성격에 따라 다를 수 있을 것 같다. 

 

학교생활의 가장 첫인상

  그럼 학교 생활은 어떨까? 난 40대가 막 시작하는 시점에서 넘어왔고 학교를 지금도 다니고 있지만, 가장 처음 나를 힘들게 했던 것은 일명 `현타` 였다. 유학 후 이민을 준비하면서 많은 캐나다 관련 커뮤니티에 들어가서 많은 경험담들을 봐서 당연히 캐나다 컬리지에 들어가게 되면 나랑 같은 사람들이 많을 줄 알았다. 하지만! 주위에 애들이 다들 어리다. ㅎㅎㅎ 보통 20살 정도 차이가 나니 그들 중에 앉아 있다보면 난 여기서 뭐하는거지? 라는 생각을 하게 된다. 누군가는 젊은 친구들과 어울려서 지내면 좋지 않냐 라고 하는데, 어느 정도 어려야지 ㅎㅎㅎ

 

 한번은 처음와서 친하게 된 현지 학생이 있는데 다음에 같이 술한잔 하러가자 하니 대답을 잘 못했다. 우줄쭈물하길래 물어보니 미성년자라고 했다. ㅎㅎㅎㅎㅎ. 한국은 보통 1학년에는 성인인데 여기는 빠르게 학교를 오면 만으로 17살이었다. 허허허.

 

학교 공부는 어떨까?

 커뮤니터의 경험담의 패혜인가.. 처음 공부가 아주 쉬울줄 알았다. 전공자체가 내가 대학때 들었던 전공이었고, 대학교 1, 2학년 수업이니 쉽게 적응할 줄 알았다. 그리고, 여기 컬리지 학생들이 공부를 많이 하지 않는다라고 들은 적도 있어서 마음을 놓고 있었다. (이건, 뭐 흔한 오해 중에 하나이다.) 그런데!! 그런데!! 와서 공부를 시작했는데 학생들의 수업 참여도가 장난이 아니다. 

수업 중에 질문은 언제든 자신이 이해가 안되면 물어보는데, 그 횟수가 장난아니다. 그리고 더 황당한 거는 수업을 잘 이해하고 있는데 이 친구들이 하는 질문을 이해하기 어려웠다. 교수님의 답변은 이해하는데 말이다. 영어가 문제다. 영어를 정말 열심히 준비하고 오길 바란다. 

 

그리고, Computer Science 같이 공학쪽 전공을 선택할 계획이라면 고등수학을 공부하고 오는 것을 추천한다. 보통 Computer Science는 필수 수학 수업이 있고, 게임쪽으로 공부를 한다면 Physics (물리) 수업도 들어야 하는데 이걸 영어로 듣는 것은 쉽지 않다. 처음 Calculus 1 (미분) 수업을 듣는데 삼각함수, 로그, 지수 등의 기본 개념이 기억이 나지 않아서 개강 첫 주는 새벽까지 기본 수학 공부를 했었다. (유투브에 영상 올려주신 수학선생님들 최고!) 그러니 좀 따라갈 만 했다.

 

그 외 영어 관련 필수 수업 (Academic Writing)이 있는데, 내가 학교 다닐때 논술이 있긴 했지만 그렇게 엄청난 비중을 차지하던 시기가 아니라서 작문에 대한 어려움은 기본적으로 가지고 있었다. 난 뼈속가지 이과이니까. 그런데 이 영어 수업에 제출해야하는 에세이가 4가지다. 그리고 수업 중에 팀 액티비티를 하는데 영어로 짧은 시간에 내용을 이해하고 작문을 해야하는데 도저히 할 수가 없었다. 팀원들에게 도움이 전혀 안되는 그런 외국인 학생이었다. 꿔다 놓은 보리자루 처럼 앉아 있을 때에는 참 기분이 처참했다. 

 

학교 공부의 반전

하지만, 그렇게 두려워 하거나 슬퍼할 필요는 없다. 나도 잘 하고 있으니, 열심히 하면 잘할 수 있다. 우리처럼 고등학교 때 야자까지 하면서 공부를 해 본 사람이라면 잘 따라 갈 수 있다. 어렵다면 시간을 조금 더 투자하자. 이 어려운 시간이 영원하진 않을 테니. 그리고 1학기에 비해서 2학기가 더 편해지고 3학기 때는 더 편해질 거니까. 그리고, 어려운 필수 과목들은 1학년 때 보통 끝나는 것 같다. 그 다음은 전공수업이니 할만하다. 

 

그리고 학교생활을 하면서 느낀 가장 큰 반전은 수업시간에 엄청 참여하면서 열심히 하는 친구들의 시험 성적은 으흠?? 생각보다 낮다. 내가 그 친구들의 성적을 일부러 본 것은 아닌데, 한 수학 수업에서 정말 질문을 열심히 하던 친구가 있었다. 정말 공부 열심히 하는 모범생이었다. 그런데 첫번째 시험이 끝나고 친구에게 자신의 점수를 자랑하는데 39점 만점에 28점인가 그랬다. 응??? 38점이어야 하는거 아니니?? 그런데 이 친구. 너무나 행복해 한다. 이렇게 많이 받을 줄 몰랐다라나.. 보통 교수님이 시험의 반평균을 알려주는데 보통 100점 만점으로 환산했을 때 50~60점 정도다. 그러니, 이 친구들이 열심히 한다고 너무 겁먹지 말자. 

 

영어로 대화

사람마다 차이가 있겠지만, 난 학교에서 영어로 말할 기회가 그렇게 많지 않다. 수업 자체가 보통 한 방향으로 많은 정보가 넘어오는 방식이기도 하고, 수업이 끝나면 바로 집으로 가기 때문이기도 하다. 요즘 같이 코로나 시대에서는 어디가서 놀기도 그렇다. 그렇다 보니 영어로 대화할 수 있는 기회가 너무 없어서 영어가 늘지를 않는다. 처음에는 이런 저런 활동을 많이 해야지 했는데 학교와 가족을 챙기다보면 그럴 시간이 별로 없다. 그리고 1학기 때에는 알바를 했더니 더 없더라. 그래서 다시 유투브를 보면서 영어공부를 하고 있다. 뭐가 이상하다. ㅎㅎ

나이대가 맞는 외국인 친구를 구하기가 어렵다. 그런데 여기 친구들도 학교 친구들이 쭉 이어져 오는 경우가 대부분이고, 사회생활을 하면서 친구 사기귀 어렵다고 한다. 이것도 고민이다. 

 

 

오늘은 학교 생활을 가지고 이런저런 얘기를 해봤다. 그냥 생각나는데로 적은 것이라 재미가 없을 것 같다. 내가 다시 봐도 재미가 없다. 흠...

그래도 조금의 정보를 얻을 수 있었다면 다행일 것 같다. 

728x90
반응형

'캐나다 일상 > College' 카테고리의 다른 글

캐나다 College 학비는 얼마일까?  (0) 2022.02.18
728x90
반응형

2022.02.09 - [Java/Spring boot] - [Spring boot & Kafka] Kafka Producer Service 예제

 

[Spring boot & Kafka] Kafka Producer Service 예제

2022.02.04 - [Java/Spring boot] - [Spring boot] Kafka 설정하기 [Spring boot] Kafka 설정하기 나의 프로젝트에서 가장 복잡한 부분을 차지하게 될 메세지 브로커의 설정에 대해서 알아보도록 하겠다. kafka가..

corono.tistory.com

 

이번엔 Kafka Consumer Service를 작성해 보겠다. 위의 포스트에서 사용한 KafkaTempalate.send() 와 ReplykafkaTemplate.sendAndReceive()의 대응되는 부분을 작성해보겠다. 

 

Kafka Consumer는 KafkaListener를 등록하고 Topic의 partition에 message가 오기를 기다린다. Message가 Topic 의 Partition으로 전달이 되면 Listener의 event가 전달되어 Listener로 등록된 함수를 실행하게 된다. 

 

Consumer의 설정은 앞쪽 Kafka Configuration 포스트에서 작성되어 있다. 

2022.02.04 - [Java/Spring boot] - [Spring boot] Kafka 설정하기

 

[Spring boot] Kafka 설정하기

나의 프로젝트에서 가장 복잡한 부분을 차지하게 될 메세지 브로커의 설정에 대해서 알아보도록 하겠다. kafka가 어떤 것인지는 아래 포스트에서 간략하게 확인할 수 있다. 2022.01.09 - [Infrastructure/

corono.tistory.com

 

Consumer 가 있는 Service에서는 Listener 함수부분만 설명하도록 하겠다. 

 

Consumer Service code

Kafka Consumer를 위한 Listener는 @kafkaListener annotation으로 등록한다. 

@KafkaListenr annotation으로 등록되는 Listner에는 몇가지 정보가 등록된다. 이 Listener가 수행되게 되는 Topic을 지정해주고, GroupID, ContainerFactory를 지정해준다. GroupId는 Topic을 Consume하는 Consumer들의 모임이다. 아래의 그림을 보면 이해가 빠를 것이다. 

출처 :&nbsp;https://lankydan.dev/intro-to-kafka-consumer-groups

Topic에 여러 Consumer Group이 붙을 수 있고 이 Group 모두 Message를 다 받을 수 있다. 만약 Group에 Consumer가 추가되게 되면 Rebalancing을 통하 모든 Consumer에게 메세지가 전달될 수 있게 한다. 

 

ContainerFactory를 설정파일에서 Bean으로 등록한 ListenerContainerFactory를 넣어준다. 

public class JwtTokenMessageServiceImpl implements JwtTokenMessageService {
    private final JwtTokenService jwtTokenService;
    private final ObjectMapper objectMapper;
    private final ModelMapper modelMapper;

    @Override
    @KafkaListener(
            topics = JwtTokenTopic.TOPIC_CREATE_JWT_TOKEN,
            groupId = "${kafka.consumer.groupId}",
            containerFactory = "kafkaJwtTokenListenerContainerFactory")
    public void listenCreateJwtTokenCache(ConsumerRecord<String, String> record, Acknowledgment ack) throws JsonProcessingException {
        LOGGER.debug("received message from '{}' : {}", record.topic(), record.value());

        JwtTokenMessage.CreateMessage createMessage = objectMapper.readValue(record.value(), JwtTokenMessage.CreateMessage.class);
        JwtToken jwtToken = jwtTokenService.create(modelMapper.map(createMessage, JwtToken.class));

        LOGGER.debug("created JwtToken Cache '{}' : {}", jwtToken.getId(), jwtToken.getJwtToken());

        ack.acknowledge();
    }

    @Override
    @KafkaListener(
            topics = JwtTokenTopic.TOPIC_REQUEST_JWT_TOKEN,
            groupId = "${kafka.consumer.groupId}",
            containerFactory = "kafkaJwtTokenListenerContainerFactory")
    @SendTo(JwtTokenTopic.TOPIC_REPLY_JWT_TOKEN)
    public JwtTokenMessage.JwtTokenInfo listenRetrieveJwtTokenCache(ConsumerRecord<String, String> record, Acknowledgment ack) throws JsonProcessingException {
        LOGGER.debug("received message from '{}' : {}", record.topic(), record.value());

        JwtTokenMessage.RequestMessage retrieveMessage = objectMapper.readValue(record.value(), JwtTokenMessage.RequestMessage.class);
        JwtToken jwtToken = jwtTokenService.getToken(retrieveMessage.getAccountId());
        ack.acknowledge();

        LOGGER.debug("requested JwtToken Cache '{}' : {}", jwtToken.getId(), jwtToken.getJwtToken());

        return JwtTokenMessage.JwtTokenInfo.from(jwtToken, modelMapper);
    }
 }

 

첫번째 listenCreateJwtTokenCache() 함수는 kafkaTemplate.send()에 대한 동작을 수행한다. 메세지가 들어올 경우 메세지를 미리 정의된 Object로 mapping 해준 후 Redis에 JwtToken 값을 생성한다. 그리고 ack.acknowlege() 함수로 Producer에게 메세지를 받았다는 응답을 전달한다.  ack.acknowlege() 함수는 Auto-Commit 설정을 false로 하였을 경우 명시적으로 호출해 주어야 한다.

 

두번째 listenRetrieveJwtTokenCache() 함수는 ReplyingKafkaTemplate.sendAndReceive() 에 대한 응답이다. 첫번째 Listener와 다른 점은 @SendTo annotation이 붙어 있고 Return type이 void가 아닌 것이다. @SendTo annotation은 이 Listener는 응답을 보낸다는 것을 나타내고 어떤 Topic으로 그 응답을 보낼지를 정의한다. 그리고 Return type은 Producer쪽으로 보내질 응답의 type을 정의해 준다. 

 

Listener 설정은 크게 어렵지 않고 너무나 직관적이다. 

 

설정 이후 메세지 처리에 집중하면 될 정도로 간단하게 되어 있다. 

728x90
반응형
728x90
반응형

제목 자체가 좀 자극적이다. 한국에 있는 많은 사람들이 외국에서의 생활을 동경한다. 나도 그랬으니까. 

오늘은 내가 왜 캐나다로 오게 되었고 어떠한 준비를 하였나 간단하게 공유해볼까 한다. 

 

Trigger

예전부터 해외에서 생활을 싶었는데, 한 마디의 말이 날 움직이게 만들었다. 어느날 장모님께서 "해외에서 한번 살아보는 것이 어때? 아이들에게 좋을 것 같은데?" 그러면서 한때 방송에 나왔던 캐나다 용접공의 다큐멘터리를 알려주셨다. 이 일을 계기로, 한국에서의 나의 목표는 캐나다로 이민을 가는 것이 되었다. 

 

이민을 위한 준비 - 직장

목표가 정해졌을 때쯤 난 제조업에서 Software Engineer를 하고 있었다. 펌웨어 프로그래머로 시작하여 Software Quality Engineer로 전형하면서 Test Automation으로 관심을 가지게 되었다. 이 때쯤 캐나다에서 IT 관련 잡이 많고 IT 관련 직종이라면 이민의 성공률이 높다는 얘기를 들었지만, 캐나다에서 펌웨어 관련된 직업이 많지 않았다. 이때 내가 사회초년생때 전자회사를 택했을까를 후회했다. 

 

그러던 찰나, 이민에 대한 목표를 설정한 시점에서 한 스카우터에게서 Job Description이 오게된다. 캐나다에 지사가 있는 게임회사의 Software Quality Engineer 자리였다. 뭔가 운명같은 느낌을 받으면서 지원을 하게 되었다. 미국계 게임회사였기 때문에 영어가 필요하였는데 그렇게 잘할 필요가 없었고, 마침 IELTS 공부를 하고 있던터라 이 성적으로 어필을 하였고, 취업에 성공하게 된다. 

 

회사를 옮기고, 일을 시작하면서 나 자신의 실력이 많이 부족하다는 것을 많이 느꼈다. Industry를 변경하게 된 것도 있지만 그간 Software  개발을 위한 자기계발이 너무 안되어 있다는 생각이 많이 느꼈다. 그래서 열심히 일했다. 많이 배우려고 했고, 어려운 Role도 맡아서 하고, 개발팀과 친하게 지내면서 많이 배웠다. 그렇게 배우고 실력을 키우다보니 어느덧 4년의 시간이 지났고, 애들이 커가고 있었기 때문에 적응을 위해 결심을 해야 했다. 

 

그래서 회사를 그만두고, 유학 후 이민으로 캐나다로 옮기게 되었다. 

 

이민을 위한 준비 - 영어 

결론적으로 지금도 영어를 잘 못한다. 영어는 어렵다. 잘 늘지 않는다. 

처음 캐나다 이민을 목표로 하고 가장 먼저 알아본 것이 유학 후 이민이었다. 이 유학 후 이민은 캐나다 컬리지에서 일정기간 학교를 다녀서 졸업을 하면 Post Graduation Work Permit이 나오고 이걸로 취업 후에 영주권을 받고 쭉 지내게되는 코스다. 그리고 학교를 들어가기 위해서는 영어 성적이 필요하다. 각 College마다 기준이 되는 성적이 있고, 그 공인점수가 있어야 바로 입학이 가능하다. 

하지만, 영어 점수가 모자를 경우에도 방법은 있다. ELL코스라고 각 학교마다 영어 코스가 있고 내부 영어코스를 이수하면 입학할 수 있는 자격이 부여된다. 이 코스는 시작하는 영어 수준에 따라 기간이 다르다. 결국은 영어 성적이 필요하다. 

내가 처음 컬리지를 준비할 때에는 IELTS로 Overall Lv 6가 보통이었는데 이제 Each Lv 6가 요구되는 것 같다. 날이 갈 수록 어려워진다. 

2021년 1월 학기를 목표로 준비하다가 코로나로 9월학기로 연기 했었는데 1월학기에는 그냥 입학이 가능했지만 9월학기에 기준이 올라 성적을 추가로 만들어야 했다. 다행이 성적을 만들어서 영어코스 없이 입학이 가능했다. 

 

입학을 위한 영어공부 말고, 일상회화에 대한 공부를 얘기해보자면, 캐나다 이민을 결심하면서 부터 회사에서 지원하는 전화영어를 꾸준히 하려고 했고, 영어 관련 유투브를 많이 보았다. 1만시간의 법칙이라는 것을 약간 믿는 편이라 잘 되지 않더라도 많은 양의 영어를 귀로 들을 려고 했고, 한마디라도 해보려고 했다. 하지만 지금 현시점에서 크게 달라진 것 없다. ㅎㅎ

 

하지만, 계속 영어를 옆에 두는 것이 중요하다. 

 

현재의 내모습

너무 내용이 길어지면 지루하니 결론부터 얘기하겠다. 

현재 나는 유학생 신분으로 밴쿠버의 한 College에서 2학기를 수강중이다.

학교 생활은 생각보다 쉽지 않은데 이것은 나중에 다른 포스트로 공유해볼까한다. 

 

하지만 유학생 신분이 오래갈 것 같진 않다.

1학기 때부터 몇몇 회사들과 면접을 보았은데 한 회사에서 오퍼를 받아서 LMIA를 진행 중에 있고, 5월쯤부터 일할 것 같다.

면접에 대한 얘기도 다른 포스트에 써보겠다. 

 

아직 캐나다에서 지낸 날이 짧지만 이런 저런 정보를 공유해보고자 한다. 

 

728x90
반응형

+ Recent posts