<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>밴쿠버 코로노의 개발일지</title>
    <link>https://corono.tistory.com/</link>
    <description>1인 개발 환경 구성 및 개발관련 Tip을 공유하는 공간</description>
    <language>ko</language>
    <pubDate>Sat, 4 Jul 2026 18:14:41 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>coolexplorer</managingEditor>
    <image>
      <title>밴쿠버 코로노의 개발일지</title>
      <url>https://tistory1.daumcdn.net/tistory/5165807/attach/bc0e3819f46b495daffe8218de897975</url>
      <link>https://corono.tistory.com</link>
    </image>
    <item>
      <title>[Powershell] Auto-suggestion 셋팅하기</title>
      <link>https://corono.tistory.com/40</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;회사업무로 인해 Powershell을 사용하게 되면서 원래 사용하던 zsh과 같은 생산성을 가지기 위해서 Auto suggestion이 필요했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 Auto suggestion이란 내가 Shell을 사용하였던 command를 기준으로 shell 창에 추천을 해주는 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;530&quot; data-origin-height=&quot;34&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yjJs3/btrz3RaW3Vh/BDlzcQpgjwBxsvJRF7afkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yjJs3/btrz3RaW3Vh/BDlzcQpgjwBxsvJRF7afkk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yjJs3/btrz3RaW3Vh/BDlzcQpgjwBxsvJRF7afkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyjJs3%2Fbtrz3RaW3Vh%2FBDlzcQpgjwBxsvJRF7afkk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;530&quot; height=&quot;34&quot; data-origin-width=&quot;530&quot; data-origin-height=&quot;34&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Auto Suggestion 셋팅방법&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Pre-requisites&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Powershell 5.1 or higher&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Installation&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 먼저 해당 기능을 사용하기 위해서는 `PSReadLine` 모듈을 설치해야 한다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1650560499967&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ Install-Module PSReadLine -RequiredVersion 2.1.0&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. Initialization&lt;/p&gt;
&lt;pre id=&quot;code_1650560519626&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Import-Module PSReadLine
Set-PSReadLineOption -PredictionSource History&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Powershell Profile에 추가&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Shell이 열릴 때마다 해당 기능을 사용하기 위해서는 Powershell Profile에 넣어두면 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Powershell Profile 셋팅방법&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음 Powershell을 사용하면 Profile 설정이 되어 있지 않는 경우가 대부분이다. 그것을 확인하는 방법은 아래 명령어를 실행하는 것이다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1650560654506&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ Test-path $profile
False&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 False가 나오면 없는 것이다. 없는 경우 아래 `New-Item`으로 Profile 파일을 만들자.&lt;/p&gt;
&lt;pre id=&quot;code_1650560769306&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ New-item &amp;ndash;type file &amp;ndash;force $profile
&amp;lt;ㅛyour Document path&amp;gt;\Powershell\Microsoft.PowerShell_profile.ps1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 기능을 사용하기 위해서는 Policy 설정도 필요하다. Powershell을 닫기 전에 아래 명령어를 실행하자.&lt;/p&gt;
&lt;pre id=&quot;code_1650561002881&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ Set-ExecutionPolicy RemoteSigned&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 설정은 파일이 로컬 컴퓨터에 있지 않고 원격 파일 서버에 있을 때&amp;nbsp; 반드시 디지털 서명이 되어 있어야 한다는 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래의 내용을 파일에 추가한다.&lt;/p&gt;
&lt;pre id=&quot;code_1650560836983&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Import-Module PSReadLine
Set-PSReadLineOption -PredictionSource History&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Shell/Powershell</category>
      <category>autosuggestion</category>
      <category>devops를알아가자</category>
      <category>PowerShell</category>
      <category>windows잘모르는바보</category>
      <category>밴쿠버코로노의개발일지</category>
      <author>coolexplorer</author>
      <guid isPermaLink="true">https://corono.tistory.com/40</guid>
      <comments>https://corono.tistory.com/40#entry40comment</comments>
      <pubDate>Fri, 22 Apr 2022 02:13:53 +0900</pubDate>
    </item>
    <item>
      <title>[groovy] Hostname(or Domain name) 으로 IP address 얻기</title>
      <link>https://corono.tistory.com/39</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;grooy script에서 HostName 또는 Domain name으로 Ip address를 확인하고 싶은 경우가 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럴 경우에는 InetAddress.getByName()을 사용하면 Host IP 와 name을 가진 InetAddress Structure를 리턴한다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1645862407293&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def hostname = 'google.com'
println InetAddress.getByName(hostname).address.collect { it &amp;amp; 0xFF }.join('.')&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>groovy</category>
      <category>get IP address from host name</category>
      <category>Groovy</category>
      <category>ip address</category>
      <category>ip주소얻기</category>
      <category>밴쿠버코로노의개발일지</category>
      <author>coolexplorer</author>
      <guid isPermaLink="true">https://corono.tistory.com/39</guid>
      <comments>https://corono.tistory.com/39#entry39comment</comments>
      <pubDate>Sat, 26 Feb 2022 17:07:01 +0900</pubDate>
    </item>
    <item>
      <title>[bash] print되는 string에 컬러 넣기</title>
      <link>https://corono.tistory.com/38</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://gist.github.com/vratiu/9780109&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://gist.github.com/vratiu/9780109&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1645662415377&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Git shell coloring&quot; data-og-description=&quot;Git shell coloring. GitHub Gist: instantly share code, notes, and snippets.&quot; data-og-host=&quot;gist.github.com&quot; data-og-source-url=&quot;https://gist.github.com/vratiu/9780109&quot; data-og-url=&quot;https://gist.github.com/vratiu/9780109&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/gkkKl/hyNv5sa1Fz/hh1DdahqjieaokYnepi2TK/img.png?width=1280&amp;amp;height=640&amp;amp;face=0_0_1280_640&quot;&gt;&lt;a href=&quot;https://gist.github.com/vratiu/9780109&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://gist.github.com/vratiu/9780109&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/gkkKl/hyNv5sa1Fz/hh1DdahqjieaokYnepi2TK/img.png?width=1280&amp;amp;height=640&amp;amp;face=0_0_1280_640');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Git shell coloring&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Git shell coloring. GitHub Gist: instantly share code, notes, and snippets.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;gist.github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;script src=&quot;https://gist.github.com/vratiu/9780109.js&quot;&gt;&lt;/script&gt;
&lt;pre id=&quot;code_1645662516249&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ __msg = &quot;message&quot;
$ echo -e &quot;\033[0;31m${__msg}\033[0m&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Shell/Bash</category>
      <category>bash</category>
      <category>bashtips</category>
      <category>밴쿠버코로노의개발일지</category>
      <author>coolexplorer</author>
      <guid isPermaLink="true">https://corono.tistory.com/38</guid>
      <comments>https://corono.tistory.com/38#entry38comment</comments>
      <pubDate>Thu, 24 Feb 2022 09:29:02 +0900</pubDate>
    </item>
    <item>
      <title>[bash] declare 란?</title>
      <link>https://corono.tistory.com/37</link>
      <description>&lt;blockquote data-ke-style=&quot;style2&quot;&gt;declare: declare [-afFirtx] [-p] [name[=value] ...] &lt;br /&gt;&lt;br /&gt;Declare variables and/or give them attributes. If no NAMEs are given, then display the values of variables instead. The -p option will display the attributes and values of each NAME. &lt;br /&gt;&lt;br /&gt;The flags are: &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;-a to make NAMEs arrays (if supported) &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;-f to select from among function names only &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;-F to display function names (and line number and source file name if debugging) without definitions. &amp;nbsp;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;-i to make NAMEs have the `integer' attribute. &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;-r to make NAMEs readonly &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;-t to make NAMEs have the `trace' attribute &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; -x to make NAMEs export. &lt;br /&gt;&lt;br /&gt;Variables with the integer attribute have arithmetic evaluation (see `let') done when the variable is assigned to. &lt;br /&gt;&lt;br /&gt;When displaying values of variables, -f displays a function's name and definition. The -F option restricts the display. to function name only. &lt;br /&gt;&lt;br /&gt;Using `+' instead of `-' turns off the given attribute instead. When used in a function, makes NAMEs local, as with the `local' command.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;bash script의 Variable의 경우 보통 type 없이 생성하고 사용한다. 하지만 declare로 선언할 경우 type과 접근권한을 설정해줄 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-a : Array&lt;/p&gt;
&lt;pre id=&quot;code_1645660422353&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ declare -a os_name=(Ubuntu Mint Kubuntu lubuntu Debian)
$ echo ${os_name[@]}
$ declare -A os_family
$ os_family[&quot;Redhat&quot;]=&quot;Fedora&quot;
$ os_family[&quot;Arch&quot;]=&quot;Manjaro&quot;
$ os_family[&quot;Debian&quot;]=&quot;Ubuntu&quot;
$ echo ${os_family[@]}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-f : Select Function name&lt;/p&gt;
&lt;pre id=&quot;code_1645660399967&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ function hello_world(){ echo &quot;Linux Geeks&quot;; }
$ declare -f hello_world                                                                                  SIGINT(2) &amp;crarr;  108  15:53:10 
hello_world () {
	echo &quot;Linux Geeks&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-i : Integer attribute&lt;/p&gt;
&lt;pre id=&quot;code_1645660460085&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ declare -i num=10
$ echo $num
10&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-x : Export attribute&lt;/p&gt;
&lt;pre id=&quot;code_1645660613007&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ declare -x name=declareTest
$ sh -c &amp;ldquo;echo $name&amp;rdquo;
declareTest&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-r : Readonly attribute&lt;/p&gt;
&lt;pre id=&quot;code_1645660715008&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ declare -r num=10
$ num=11
-bash: no: readonly variable&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Shell/Bash</category>
      <category>Shell</category>
      <category>공부공부</category>
      <category>밴쿠버코로노의개발일지</category>
      <author>coolexplorer</author>
      <guid isPermaLink="true">https://corono.tistory.com/37</guid>
      <comments>https://corono.tistory.com/37#entry37comment</comments>
      <pubDate>Thu, 24 Feb 2022 08:57:17 +0900</pubDate>
    </item>
    <item>
      <title>[Powershell] Environment Variable 확인 및 추가하기</title>
      <link>https://corono.tistory.com/36</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;Environment Variable 확인하기&lt;/h4&gt;
&lt;pre id=&quot;code_1645656166153&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;PS /&amp;gt; $ENV:VAULT_TOKEN
s.uns3Mtn&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Environment Variable 설정하기&lt;/h4&gt;
&lt;pre id=&quot;code_1645656225135&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;PS /&amp;gt; $ENV:VAULT_TOKEN = &quot;s.uns3Mtnlbq...&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Shell/Powershell</category>
      <category>PowerShell</category>
      <category>기억하기</category>
      <category>밴쿠버코로노의개발일지</category>
      <author>coolexplorer</author>
      <guid isPermaLink="true">https://corono.tistory.com/36</guid>
      <comments>https://corono.tistory.com/36#entry36comment</comments>
      <pubDate>Thu, 24 Feb 2022 07:44:16 +0900</pubDate>
    </item>
    <item>
      <title>Software lifecycle 에서 Day 0 / Day 1 / Day 2의 의미</title>
      <link>https://corono.tistory.com/35</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;IT 분야에서 Day 0 / 1 / 2 는 각각 다른 Phase 를 설명한다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;Day 0 is the very first day of training, when recruits enter their formative stage. In software development, it represents the design phase, during which project requirements are specified and the architecture of the solution is decided.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Day 0 : Design phase 를 말한다. 요구사항을 분석하고 Architecture를 결정하는 구간이다.&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;Day 1 involves developing and deploying software that was designed in the Day 0 phase. In this phase we create not only the application itself, but also its infrastructure, network, external services and implement the initial configuration of it all.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Day 1 : 개발과 배포 단계를 포함하는 단계이다. 이 단계에서는 Application만을 개발하는 것이 아니라 Infra, network 와 그 외의 외부 서비스들까지 구현하고 셋팅하는 단계이다.&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;Day 2 is the time when the product is shipped or made available to the customer. Here, most of the effort is focused on maintaining, monitoring and optimizing the system. Analyzing the behavior of the system and reacting correctly are of crucial importance, as the resulting feedback loop is applied until the end of the application&amp;rsquo;s life.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Day 2 : Application (Product)의 개발이 완료되고 고객들이 이용가능한 환경을 구성하는 단계이다. 배포 이후의 Maintance 까지 포함하고, 배포 이후에 시스템을 Optimizing 하는 부분도 포함된다. Application의 수명이 다할 때까지 운영 관리되는 기간이라고 생각하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Software Development</category>
      <category>day012</category>
      <category>밴쿠버코로노의개발일지</category>
      <category>용어정리</category>
      <author>coolexplorer</author>
      <guid isPermaLink="true">https://corono.tistory.com/35</guid>
      <comments>https://corono.tistory.com/35#entry35comment</comments>
      <pubDate>Wed, 23 Feb 2022 11:30:57 +0900</pubDate>
    </item>
    <item>
      <title>[일상] 밴쿠버에서 한국 치킨을 시켜보자. 도대체 얼마야?</title>
      <link>https://corono.tistory.com/34</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;코로나라는 녀석이 생기고 대면하는 것이 꺼려지면서 가장 급격하게 발전한 것 중에 하나가 배달음식이다. 한국에서도 배달의 민족이나 요기요, 쿠팡 이츠 등의 배달 시장이 급성장한 것과 같이 캐나다에서도 배달음식 시장이 점점 커지고 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 큰 배달업체는 Uber Eats이고 그 외에는 Skip the dish, Door Dash 등의 업체들이 그 뒤를 따르고 있다. 나도 이곳에서 배달음식을 종종 이용하곤 한다. 아내의 음식 준비시간의 한국에 비해 많이 늘어났는데, 이 곳 학교에서 급식을 주고 있지 않아 매일 도시락을 싸야하는 것에 부담을 많이 느끼고 있다. 가끔 도와주고 있긴 하지만 어쩌다 한번씩 이지 많은 부담을 덜어주고 있지 못하고 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 가끔식 배달음식을 먹으면서 그 부담을 덜어주려고 하는데, 사실 한국에 비교해서 이 곳의 배달음식 비용은 상당히 비싸다. 우선 레트토랑에서 파는 음식의 값이 한국에 비싸고, 특히나 한식의 경우에는 많이 많이 비싸다. 그리고 배달료 자체도 한국보다 비싸며, 배달시에도 배달팁이 추가된다. 캐나다도 미국과 같은 팁의 나라라고 하지만 배달료가 있는데, 팁까지 주게 되면 음식 하나를 더 시켰지만 못 받는 느낌이다. ㅋㅋ 다른 한편으로는 몸으로 하는 일에 대한 서비스 비용을 지불한다는 면에서는 이해가 되는 부분이기도 하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 이곳에서 생활을 하게 되면 팁이라는 것이 점점 일상화가 되고 모든 가격에 팁을 포함해서 계산을 하게 된다. 이곳의 문화이고 그것을 포함한 금액이 이곳의 물가라고 생각하고 살아가야 할 것 같다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼, 중요한 것은 도대체! 얼마나 비싸나? 이곳에서 비싸다고 하는 한국 치킨을 시켰을 때 기준으로 가격을 공개해보겠다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 심호흡을 하자. 놀랄테니 말이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근에 시킨 치킨은 bbq 치킨이다. 아, 밴쿠버에도 bbq가 들어와 있고, 이곳의 치킨들에 비교했을 때 맛도 중상급이라 할 수 있다. 하지만 가격은 비싼편이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;치킨가격&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;bbq의 황금올리브치킨, 여기에서는 Golden Fried Chicken 인데 반마리씩 판다. 음.. 왜그럴까? 모르겠다. ㅋㅋ&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 반마리가 $19 이다. 한국 돈으로 17,882원이다. 거의 18000원이다. (다시 생각해도 비싸다.) 알다시피 반마리로 4인 가족의 입에 풀칠도 못한다. 그래서 2개 시켰다. 그래서 치킨가격만 $38.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;381&quot; data-origin-height=&quot;321&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xzjo7/btrtIkdaphV/OhaivXtfR4StRRkFmJbEQK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xzjo7/btrtIkdaphV/OhaivXtfR4StRRkFmJbEQK/img.png&quot; data-alt=&quot;이게 반마리양이다.&amp;amp;nbsp;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xzjo7/btrtIkdaphV/OhaivXtfR4StRRkFmJbEQK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fxzjo7%2FbtrtIkdaphV%2FOhaivXtfR4StRRkFmJbEQK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;381&quot; height=&quot;321&quot; data-origin-width=&quot;381&quot; data-origin-height=&quot;321&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;이게 반마리양이다.&amp;nbsp;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;떡볶이&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;bbq에서 떡볶이도 팔았다. 검색을 좀 해보니 맛있다고 하길래 한번 시켜보았다. 정확한 양을 몰라서 가격을 보고 양이 좀 많겠지 하고 시켰다. 양이 적었다. 속았다. 맛은 있었다. 그런데 아까웠다. 떡뽁이 가격 $13. (다시는 안 시킬 것 같다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구글에 찾아보니 사진이 있었다. 이거 봤으면 안시켰을텐데 ㅋㅋ&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;397&quot; data-origin-height=&quot;462&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4vNpf/btrtMJo9msi/XvjKOGX5XiyFzAsKpbMkjK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4vNpf/btrtMJo9msi/XvjKOGX5XiyFzAsKpbMkjK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4vNpf/btrtMJo9msi/XvjKOGX5XiyFzAsKpbMkjK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4vNpf%2FbtrtMJo9msi%2FXvjKOGX5XiyFzAsKpbMkjK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;397&quot; height=&quot;462&quot; data-origin-width=&quot;397&quot; data-origin-height=&quot;462&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Fries &amp;amp; Dip&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리 애들이 감자튀김을 좋아한다. 그래서 시키는 김에 하나 시켰다. 보통 후라이드만 시킬 때에는 양념소스도 하나시키는데 감자튀김과 함께 Dip 소스를 시킬 수 있어서 선택했다. 이것이 $8.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Coke&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;목 막히니까 콜라 2개. $5.58&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Delivery Fee&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배달비 $4.55. 업체에 따라 얼마이상 시키면 배달비 무료가 있지만 여기는 아니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;GST&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 비용에는 세금에 제외된 금액이다. 합계 금액에서 배달비가 계산된다. $3.46&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Courier Tip&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것은 배달하는 사람에게 주는 Tip이다. 이 금액이 없거나 적으면 내 음식은 어떻게 될지 아무도 모른다. ㅋㅋㅋ 보통 10~15% 정도 준다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Total 금액 : $84.37&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비싸다. 많이 비싸다. 캐나다는 식당에서 먹거나 배달을 먹으면 이렇게 비싸다. ㅎㅎㅎ 한국과 비교를 안해야하지만 한국을 떠나온지 이제 7개월 정도 밖에 안되니 비교를 할 수 밖에 없다. 그래도 가족들이 맛있게 잘 먹었으니 괜찮다. 열심히 돈 벌면 되지.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아, 이 금액은 캐나다에서 한식을 시켰으니 더 비싸다는 것을 반드시 기억하자. 그런데 그나마 먹을만한 음식이 한식이다. 다른 것은 비용대비 효율이 극히 좋지 않다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;혹시 캐나다로 오실 분들은 이런 캐나다의 물가를 꼭 기억하길 바란다.&amp;nbsp;&lt;/p&gt;</description>
      <category>캐나다 일상/일상</category>
      <category>밴쿠버코로노의개발일지</category>
      <category>비싼배달음식</category>
      <category>캐나다배달음식</category>
      <category>캐나다에서한국치킨</category>
      <category>캐나다일상</category>
      <author>coolexplorer</author>
      <guid isPermaLink="true">https://corono.tistory.com/34</guid>
      <comments>https://corono.tistory.com/34#entry34comment</comments>
      <pubDate>Sun, 20 Feb 2022 15:06:42 +0900</pubDate>
    </item>
    <item>
      <title>[Spring boot] Spring WebMVC(Servlet) 와 Spring Webflux의 차이</title>
      <link>https://corono.tistory.com/33</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 Spring MVC(Sevlet)과 Webflux의 차이에 대해서 간략하게 정리해 보고자 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근 API Gateway를 만들기 위해 Spring Cloud Gateway를 사용하였는데, 이 환경이 Webflux로 작성되어 있어서 기존에 내가 사용한 Spring MVC의 Servelt과 어떠한 차이가 있는지 궁금해서 이런저런 포스트를 찾아보았고, 이해한 내용을 정리해두고자 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리의 서비스가 Concurrent하게 동작하기 위헤서는 서버 내부에서 동시성을 보장하는 기술이 필요하다. 간단하게 우리는 Thread라고 하는 녀석을 여러 개 만들어서 이것을 사용하여 여러 작업을 동시에 처리하게 할 수 있다. 이것은 Spring MVC에서 채택하고 있는 방법이고 이를 위해서 Thread pool를 만들어서 이 많은 Thread를 관리한다. Spring boot web에서 Request가 들어오면 해당 Request를 처리하기 위해서 Thread하나가 사용된다고 보면 될 것 같다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그에 반해, 적은 Thread 갯수로 이를 수행할 수 있는 방법이 존재한다. Thread 갯수보다 더 많은 작업이 있더라도 각 작업은 굉장히 적은 시간으로 쪼개어 하나씩 수행하도록 하는 방법이다. 이것을 Event-loop 방식이라하고, 이 방법을 채택해서 유명해 진 것이 우리가 아는 Node.js 이다. JavaScript의 거의 대부분의 수행은 메인 스레드 하나에서 실행된다. 그래서 Node.js는 싱글스레드 기반이라고 얘기하곤 한다.&amp;nbsp;Spring Webflux는 이러한 컨셉을 가져와서 만들 것이라고 보면 된다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;578&quot; data-origin-height=&quot;348&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/O21XR/btrtB9uWygu/rceHK1X7xQGVSfix9LKq20/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/O21XR/btrtB9uWygu/rceHK1X7xQGVSfix9LKq20/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/O21XR/btrtB9uWygu/rceHK1X7xQGVSfix9LKq20/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FO21XR%2FbtrtB9uWygu%2FrceHK1X7xQGVSfix9LKq20%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;578&quot; height=&quot;348&quot; data-origin-width=&quot;578&quot; data-origin-height=&quot;348&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Webflux는 위에서 보는 것과 같이 기존 Servelt과 동일한 라이브리러리 이외에 Non-servlet으로 구현이 가능한 Netty와 Undertow 라이브러리를 가지고 있다. 이것으로 Non-blocking한 동작을 가능하게 한다. 둘다 동일하게 @Controller annotation을 사용하지만 내부적으로 수행되는 것은 다르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 언제 Servlet을 사용하고 언제 Reactive를 사용해야 할까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring boot의 Rossen&amp;nbsp;Stoyanchev는 현재의 서비스가 Servlet으로 잘 구동되고 있다면 굳이 바꿀 필요가 없다고 말한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 Blocking Dependency를 사용하는 경우에는 Servlet이 더 어울린다. 그리고 Servlet API를 사용하게 된다면 Servlet이 더 어울린다. 왜나하면 Servlet API를 사용하는 순간 Blocking으로 바뀌게 되기 때문이다. 아래 그림을 보면 이해가 될 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;613&quot; data-origin-height=&quot;312&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cZXum9/btrtydSJrAz/BnF5uj93iM82Jdya5gurHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cZXum9/btrtydSJrAz/BnF5uj93iM82Jdya5gurHk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cZXum9/btrtydSJrAz/BnF5uj93iM82Jdya5gurHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcZXum9%2FbtrtydSJrAz%2FBnF5uj93iM82Jdya5gurHk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;613&quot; height=&quot;312&quot; data-origin-width=&quot;613&quot; data-origin-height=&quot;312&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Servlet에서 Reactive를 사용하는 방법도 있다. 예를 들어 Microservice 환경에서 Restful API 요청이 들어왔을 때 다른 Service로 요청을 보내거나 데이터를 받아올 때 사용하면 좋을 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Reactive가 반드시 Servlet 보다 빠른 것은 아니지만 Scalibility를 중시허가나 Resource를 효율적으로 사용하고 싶은 경우에는 고려하면 좋은 것임에는 틀림없다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;미래의 나를 위해...&lt;/p&gt;</description>
      <category>Java/Spring boot</category>
      <category>spring boot</category>
      <category>Spring Webflux</category>
      <category>spring webmvc</category>
      <category>springboot공부</category>
      <category>밴쿠버코로노의개발일지</category>
      <author>coolexplorer</author>
      <guid isPermaLink="true">https://corono.tistory.com/33</guid>
      <comments>https://corono.tistory.com/33#entry33comment</comments>
      <pubDate>Fri, 18 Feb 2022 13:03:12 +0900</pubDate>
    </item>
    <item>
      <title>캐나다 College 학비는 얼마일까?</title>
      <link>https://corono.tistory.com/32</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;유학 후 이민을 올 때 궁금해하는 부분 중 하나는 학비는 얼마나 할까? 일 것이다. 학비는 학교마다 다르고 지역마다 다르기 때문에 보통 얼마정도이다 라고 얘기를 해주기는 어렵다. 하지만, 한 학교의 학비를 알 수 있으면 어느 정도의 Budget은 결정할 수 있을 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서! 내가 다니고 있는 학교의 한 학기 학비가 어떻게 이루워져 있는지 공유 해보고자 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;학비는 시간이 지날 수록 올라가고 있다는 것을 느낀다. 물가상승에 따른 상승이라고 봐야할까? 참, 물가도 엄청 올랐다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Fall 2021 Tuition Fees of Douglas College&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 2021년 가을학기의 학비이다. 4과목 12 Credit 기준의 첫 학기의 비용이다. 아래에 자세하게 항목 하나씩 알아보자.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;958&quot; data-origin-height=&quot;440&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ctkY2x/btrtCURvyJb/Jc1NFhnwooJCCuPfEdJCw1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ctkY2x/btrtCURvyJb/Jc1NFhnwooJCCuPfEdJCw1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ctkY2x/btrtCURvyJb/Jc1NFhnwooJCCuPfEdJCw1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FctkY2x%2FbtrtCURvyJb%2FJc1NFhnwooJCCuPfEdJCw1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;958&quot; height=&quot;440&quot; data-origin-width=&quot;958&quot; data-origin-height=&quot;440&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Tuition Fees (수업료)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 Tuition Fees는 내가 등록한 &lt;b&gt;수업의 Credit 기준으로 책정&lt;/b&gt;되는 수업료이다. 내가 첫 학기에 12학점을 들었으니까 &lt;b&gt;1학점당 $612 (CAD)&lt;/b&gt; 이다. 현재 환율 942원 기준으로 &lt;b&gt;약 57만원 정도&lt;/b&gt;이다. 한 과목이 보통 3학점이므로 &lt;b&gt;과목당 160만원 정도&lt;/b&gt;이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것은 국제학생 (International Student)의 비용이다. 만약 &lt;b&gt;영주권 이나 시민권&lt;/b&gt;을 가지고 있다면 학비는 많이 줄어든다. 여기 친구에게 물어보니 &lt;b&gt;$330~$400 정도이니 약 4배 이상 저렴&lt;/b&gt;해진다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;역시 학교는 국제학생을 통해서 돈을 버는가보다. 아까운 내 돈.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Other Fees&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 부분을 먼저 얘기하는 이유는 수업과 관련이 있는 비용이기 때문이다. 수업을 듣다보면 Lab 이나 Tutorial 수업을 추가적으로 신청해야하는 경우가 있다. 수학, 물리, 컴퓨터 등의 Science 관련 수업에 보통 있는데 수업 이외의 별도 수업으로 보통 우리 대학을 생각하면 조교가 들어와서 문제를 나눠주고 푸는 등의 실습 위주의 학습을 한다. 이 수업의 성적이 관련된 본 수업에 포함된다. 보통 10% 정도이기 때문에 거의 필수적으로 들어야 한다고 보면 된다. 그 비용이 Other Fees로 추가된다. 이때 2개의 Tutorial 추가된 금액으로 보면 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Student's Union Fee (학생회비)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한국 학교에서도 보는 학생회비이다. 한국과 비슷하게 얘네들이 뭐하고 있는지는 잘 모르겠다. 하지만 다양한 활동 들이 학교 로비에서 진행된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Other Student Activity Fee&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이건 잘 몰라서 학교 사이트에서 찾아봤다. 일종의 부대비용 같은 느낌이다. 난 아무것도 안하는데 돈을 내는 그런 거.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1434&quot; data-origin-height=&quot;788&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcRKbU/btrtE2henPY/clJ7qQiY0syYYYFLUnrhZ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcRKbU/btrtE2henPY/clJ7qQiY0syYYYFLUnrhZ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcRKbU/btrtE2henPY/clJ7qQiY0syYYYFLUnrhZ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbcRKbU%2FbtrtE2henPY%2FclJ7qQiY0syYYYFLUnrhZ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1434&quot; height=&quot;788&quot; data-origin-width=&quot;1434&quot; data-origin-height=&quot;788&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Registration &amp;amp; Services Fee&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;학교 등록, 수업 신청, 학생증 발행, Class Advisor 등등의 학생을 위한 활동 들을 하기 때문에 우리는 서비스 비용을 줘야 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Medical &amp;amp; Dental Fee (실비보험 비용)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BC 주에는 MSP라는 일종의 의료보험이 있다. 하지만 이 의료보험이 커버하는 영역이 우리나라처럼 광범위하지 않다. 하지만, 기본적은 진료 및 검사 등은 무료로 받을 수 있다. 예를 들면, 둘째 딸이 지속적인 복통으로 이곳에서 피검사, 소변검사, X-ray를 찍은 적이 있는 이 모든 비용이 무료였다. 그리고, 응급실에 가서 치료를 받을 경우도 무료인 것으로 알고 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만, 이러한 기본적인 것을 제외한 치료비용은 상상을 초월할 정도로 비싸다. 그래서 우리나라의 실비보험 같은 것을 학생 신분으로 들 수 있다. 그리고 그것을 가족까지 확장하여 받을 수 있다. 나는 이 보험을 가족을 모두 추가(3명 추가)하였는데 저 위의 비용에 $650 가량을 추가로 내었다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 보험으로 Refund을 받은 적이 있는데 큰 아이의 마지막 유치를 뽑고 실란트를 하는 비용으로 $250 가량 들었는데 80%를 돌려받았다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보면 알겠지만 생각보다 많이 비싸다. 하지만 College의 비용이 University 비용보다 저렴하다는 것을 꼭 기억하자. 대학을 이쪽으로 오거나 학위에 욕심이 있는 사람이라면 더 총알을 만들어서 오도록 하자.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유학 후 이민을 준비하는 사람에게 도움이 되길.&amp;nbsp;&lt;/p&gt;</description>
      <category>캐나다 일상/College</category>
      <category>국제학생학비</category>
      <category>밴쿠버코로노의개발일지</category>
      <category>캐나다컬리지</category>
      <category>캐나다컬리지학비</category>
      <category>캐나다학비</category>
      <author>coolexplorer</author>
      <guid isPermaLink="true">https://corono.tistory.com/32</guid>
      <comments>https://corono.tistory.com/32#entry32comment</comments>
      <pubDate>Fri, 18 Feb 2022 04:21:00 +0900</pubDate>
    </item>
    <item>
      <title>[Spring boot &amp;amp; Kafka] Kafka Unit test 예제</title>
      <link>https://corono.tistory.com/31</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Kafka에 대한 설정 및 Producer와 Consumer의 예제에 대해서 알아보았다. 그럼 이 코드들이 잘 동작하는지는 어떻게 확인해야할까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 서비스들 간의 메세지 전송 및 결과를 확인하기 위해서는 테스트 환경을 구축하여 서비스를 띄운 후에 테스트 해보는 것이 가장 정확하다. Docker compose로 Kafka broker와 Zookeeper를 띄우고 Bootstarp address에 Kafka broker 주소를 넣어준 뒤 서비스를 띄워서 테스트를 하면된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만, 이러한 환경은 귀찮은 면이 있다. 항상 테스트를 위해서 서비스를 띄워두는 것은 리소스 낭비이다. 그래서 Kafka의 메세지 전송을 테스트 할 수 있는 환경이 필요하다. Spring boot 환경에서는 이를 테스트 할 수 있는 라이브러리를 제공하고 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래의 라이브러리가 그것이며, 이름은 Spring kafka test library 이다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1644948724344&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.springframework.kafka&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;spring-kafka-test&amp;lt;/artifactId&amp;gt;
    &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 Configuration을 추가하면 Embedded kafka 를 사용할 수 있게 되고, 이 환경을 통해서 Message 전송을 임의로 만들 수 있게 된다.&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;단, Container 환경에서 Embedded kafka로 테스트를 진행하면 정상적으로 진행되지 않다.&amp;nbsp;&lt;br /&gt;현재, 나의 환경이 Jenkins를 Kubernetes 내부에 띄우고 Pod agent로 Docker Image build 및 Release Job을 수행하고 있고, 이때 Unit test를 수행하여 코드의 안정성을 확인하고 있다. 하지만, Embedded kafka관련 Test는 수행하고 못하고 있다.&amp;nbsp;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Test 예제&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;application-test.yaml&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Embedeed kafka를 사용하기 위해서는 Embedded kafka에서 띄우는 서버를 사용하여야 한다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1644952702595&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# kafka
kafka:
  bootstrap:
    addresses: ${spring.embedded.kafka.brokers:localhost:9092}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Essential Configuration (JUnit5)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Embedded kafka를 사용하기 위해서는 필수적으로 넣어주어야 하는 Configuration 이 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 &lt;b&gt;@EmbeddedKa&lt;/b&gt;fka annotation으로 Embedded Kafka를 추가해 준다. 그리고 이 Embedded kafka가 동작하기 위해서는 Integration Test 환경으로 수행되어야 한다. 그 말은 Spring 의 Dependency가 사용되는 환경에서 수행되어야 하기 때문에 &lt;b&gt;@SpringbootTest&lt;/b&gt; annotation이 추가되어야 하고, 그와 더불어 &lt;b&gt;@ExtendWith(SpringExtension.class)&lt;/b&gt;가 추가되어야 정상적인 동작이 된다. 이러한 셋팅은 JUnit5 기반으로 테스트 될때이며 JUnit4는 그 방법이 다르다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1644949649264&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Slf4j
@Tag(&quot;embedded-kafka-test&quot;)
@SpringBootTest
@ExtendWith(SpringExtension.class)
@EmbeddedKafka
@AutoConfigureMockMvc
@TestPropertySource(properties = &quot;spring.config.location=classpath:application-test.yaml&quot;)
public class JwtTokenMessageServiceImplTest {
...
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Kafka Broker Configuration&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Embedded Kafka의 Broker를 셋팅해주는 부분이다. @Autowired annotation으로 Dependency Injection을 해주면 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Broker count는 2개, Partition은 2개로 설정해 주었다. 마지막은 설정과 동시에 생성할 Topic인데, Topic이 여러 개 일 때에는 뒤쪽으로 ,(콤마)로 구분하여 계속 넣어주면 된다.&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;Intellij를 사용한다면 이 부분에서 @Autowired 로 Dependency Injection시 Dependecy를 찾을 수 없다는 Inspection Message를 받을 수 있다. 이 부부은 Intellij의 문제로 난 이 Inspection의 level을 warning으로 바꾸었다.&amp;nbsp;&lt;br /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://corono.tistory.com/25&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2022.02.05 - [Tool/IntelliJ] - [Intellij] @Autowired inspection 오류 무시하는 방법&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre id=&quot;code_1644949684272&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;...
@Autowired
private EmbeddedKafkaBroker embeddedKafkaBroker = new EmbeddedKafkaBroker(
        2,
        true,
        2,
        JwtTokenTopic.TOPIC_CREATE_JWT_TOKEN
);
...&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Producer configuration&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Producer configuration은 간단하다. Produecer Property는 Default 셋팅으로 설정하였다. 그리고 Key Serializer는 String, Value Serialilzer는 Json으로 설정하였다. 이 부분의 서비스에서 사용하는 설정과 동일하게 하면 된다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1644950359438&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;private Producer&amp;lt;String, Object&amp;gt; configEmbeddedKafkaProducer() {
    Map&amp;lt;String, Object&amp;gt; producerProperties = new HashMap&amp;lt;&amp;gt;(KafkaTestUtils.producerProps(embeddedKafkaBroker));
    return new DefaultKafkaProducerFactory&amp;lt;&amp;gt;(producerProperties, new StringSerializer(), new JsonSerializer&amp;lt;&amp;gt;()).createProducer();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Consumer Configuration&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Consumer의 설정은 복잡하다. 왜냐하면 Kafka의 Consumer의 설정에서 보았듯이 KafkaLinstener의 설정이 추가되어야 하기 때문이다. Embedded Kafka도 마찬가지로 Produer가 보내는 메세지가 Topic에 들어오면 Listener가 해당 메세지를 처리하도록 해야하기 때문이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) 우선 Consumer Property 셋팅을 한다. 기본 셋팅을 가지고 가되, Auto commit만 false로 셋팅하였다. 나의 코드에서 Commit을 수동을 하고 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) ConsumerFactory를 만들고, Container Property를 topic과 함께 생성하고, KafkaMessageListenerContainer를 만든다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3) CusumerRecord를 순차적으로 저장시키고, 순차적으로 처리하기 위해, BlockingQueue로 선언한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4) 이후, 생성된 KafkaMessageListenerContainer에 Listener 함수를 추가한다. 이 함수에서는 Log로 Message를 출력하고, BlockQueue에 record를 추가한다. 이 record를 필요한 시점에 뽑아서 확인한다.&lt;/p&gt;
&lt;pre id=&quot;code_1644950657252&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;private KafkaMessageListenerContainer&amp;lt;String, String&amp;gt; container;

private BlockingQueue&amp;lt;ConsumerRecord&amp;lt;String, String&amp;gt;&amp;gt; records;

private void configEmbeddedKafkaConsumer(String topic) {
    Map&amp;lt;String, Object&amp;gt; consumerProperties = new HashMap&amp;lt;&amp;gt;(KafkaTestUtils.consumerProps(&quot;auth&quot;, &quot;false&quot;, embeddedKafkaBroker));

    DefaultKafkaConsumerFactory&amp;lt;String, String&amp;gt; consumerFactory = new DefaultKafkaConsumerFactory&amp;lt;&amp;gt;(consumerProperties);

    ContainerProperties containerProperties = new ContainerProperties(topic);
    container = new KafkaMessageListenerContainer&amp;lt;&amp;gt;(consumerFactory, containerProperties);

    records = new LinkedBlockingDeque&amp;lt;&amp;gt;();

    container.setupMessageListener((MessageListener&amp;lt;String, String&amp;gt;) record -&amp;gt; {
                LOGGER.debug(&quot;test-listener received message='{}'&quot;,
                        record.value());
                records.add(record);
    });
    container.start();

    ContainerTestUtils.waitForAssignment(container, embeddedKafkaBroker.getPartitionsPerTopic());
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;전체 Configuration 부분 코드&lt;/h4&gt;
&lt;pre id=&quot;code_1644949057060&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Slf4j
@SpringBootTest
@ExtendWith(SpringExtension.class)
@EmbeddedKafka
@AutoConfigureMockMvc
@TestPropertySource(properties = &quot;spring.config.location=classpath:application-test.yaml&quot;)
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&amp;lt;String, String&amp;gt; container;

    private BlockingQueue&amp;lt;ConsumerRecord&amp;lt;String, String&amp;gt;&amp;gt; records;

    @BeforeEach
    void setUp() {}

    private void configEmbeddedKafkaConsumer(String topic) {
        Map&amp;lt;String, Object&amp;gt; consumerProperties = new HashMap&amp;lt;&amp;gt;(KafkaTestUtils.consumerProps(&quot;auth&quot;, &quot;false&quot;, embeddedKafkaBroker));

        DefaultKafkaConsumerFactory&amp;lt;String, String&amp;gt; consumerFactory = new DefaultKafkaConsumerFactory&amp;lt;&amp;gt;(consumerProperties);

        ContainerProperties containerProperties = new ContainerProperties(topic);
        container = new KafkaMessageListenerContainer&amp;lt;&amp;gt;(consumerFactory, containerProperties);

        records = new LinkedBlockingDeque&amp;lt;&amp;gt;();

        container.setupMessageListener((MessageListener&amp;lt;String, String&amp;gt;) record -&amp;gt; {
                    LOGGER.debug(&quot;test-listener received message='{}'&quot;,
                            record.value());
                    records.add(record);
        });
        container.start();

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

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

    @AfterEach
    void tearDown() {
        container.stop();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Producer Test Code예제&lt;/p&gt;
&lt;pre id=&quot;code_1644951349320&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;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&amp;lt;String, String&amp;gt; record = records.poll(10, TimeUnit.SECONDS);
    
    
	// 수신한 메세지 확인
    assertThat(record).isNotNull();
    assertThat(record.value()).isEqualTo(expectedMessage);
    assertThat(record).has(key(null));
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Consumer Test Code 예제&lt;/p&gt;
&lt;pre id=&quot;code_1644951562897&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void testCreateMessageForJwtTokenCache() {
	// 전송할 메세지 생성
    JwtTokenMessage.CreateMessage createMessage = new JwtTokenMessage.CreateMessage();
    createMessage.setAccountId(1L);
    createMessage.setJwtToken(&quot;test-jwtToken&quot;);
    createMessage.setExpiration(120L);

	// 메세지를 사용하여 ProducerRecord를 생성한다.
    ProducerRecord&amp;lt;String, Object&amp;gt; producerRecord = new ProducerRecord&amp;lt;&amp;gt;(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());
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 정도면 간단한 메세지 전송 여부는 확인이 가능하다.&amp;nbsp;&lt;/p&gt;</description>
      <category>Java/Spring Kafka</category>
      <category>embeddedkafka</category>
      <category>Kafka</category>
      <category>springboot</category>
      <category>밴쿠버경주김씨의개발일지</category>
      <author>coolexplorer</author>
      <guid isPermaLink="true">https://corono.tistory.com/31</guid>
      <comments>https://corono.tistory.com/31#entry31comment</comments>
      <pubDate>Wed, 16 Feb 2022 04:00:16 +0900</pubDate>
    </item>
  </channel>
</rss>