<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Felicia Faye</title>
    <description>The latest articles on DEV Community by Felicia Faye (@meikefelicia).</description>
    <link>https://dev.to/meikefelicia</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F856051%2Fa0f490b1-9437-49e3-89ea-6c1dad78f6e8.jpg</url>
      <title>DEV Community: Felicia Faye</title>
      <link>https://dev.to/meikefelicia</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/meikefelicia"/>
    <language>en</language>
    <item>
      <title>Resilient microservices with Quarkus and Kotlin - All threads together</title>
      <dc:creator>Felicia Faye</dc:creator>
      <pubDate>Mon, 25 Jul 2022 10:13:47 +0000</pubDate>
      <link>https://dev.to/meikefelicia/resilient-microservices-with-quarkus-and-kotlin-all-threads-together-1e3h</link>
      <guid>https://dev.to/meikefelicia/resilient-microservices-with-quarkus-and-kotlin-all-threads-together-1e3h</guid>
      <description>&lt;p&gt;The second part of this series was all about theory - we had a closer look at some helpful resilience design patterns. Now it's time to take some action 💪. Let's finally bring all threads together and see how we can realize this with &lt;strong&gt;Quarkus&lt;/strong&gt; and &lt;strong&gt;Kotlin&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjel9jdg4kc3cwciarxop.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjel9jdg4kc3cwciarxop.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Do you still remember the shocking scenario for all of this? We are doomed cause we live in an area with &lt;strong&gt;poisonous snakes&lt;/strong&gt; and must rely on our own service to be warned about the dangerous animals in time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx8tni8ntjafgx7pe1ugc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx8tni8ntjafgx7pe1ugc.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let me introduce you to the &lt;strong&gt;Snake Alarm Detection Fulfilment Scenario&lt;/strong&gt; where we are going to handle this in a resilient way.&lt;/p&gt;

&lt;p&gt;Imagine small snake detector boxes, which can magically detect snakes passing by. Sometimes the detectors have false positives with cute and harmless lizards. To handle these false positives the snake detector boxes can also send a photo of the detected animal via REST endpoint so it can be evaluated, for example, by means of machine learning. When we are sure that it's a snake, we want to send a push notifications to all mobile devices in that area. Sadly, we have to use an external service for the push notifications and this is pretty expensive. We have two options here: one service, which is very expensive and 100% reliable but a little bit slow and another services, which is much cheaper and faster, but not so reliable at all.&lt;/p&gt;

&lt;p&gt;The plan is to build a robust roundtrip from a) detecting a "snake or lizard" with the box to b) sending a warning push notification to everyone in the area. Ideally the push notification goes out fast and we do not spend that much money on sending those push notifications.&lt;/p&gt;

&lt;p&gt;Let's try: the snake detector box could make a POST request to a SnakeAlarmEndpoint. This could trigger a SnakeAlarmRepository to emit an event into an AMQP messaging channel named &lt;strong&gt;snake-alarm-out&lt;/strong&gt;. Then we subscribe to those events in another &lt;strong&gt;snake-alarm-in&lt;/strong&gt; channel to be able to scale independently. Given the illustration below, you can see our SnakeAlarmProcessor, which can process new SnakeAlarms coming in from the AMQP channel &lt;strong&gt;snake-alarms-in&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3c0lqlphmie5xnaga9py.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3c0lqlphmie5xnaga9py.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The SnakeAlarmProcessor itself calls the LizardCheck to verify that we have a snake and not a lizard coming in.&lt;br&gt;
The LizardCheck has a runtime between 0,2s and 1,06s. Having the runtime measured, we can configure our SnakeAlarmProcessor call to the LizardCheck with a &lt;strong&gt;timeout&lt;/strong&gt; of 1s and a maximum of 3 &lt;strong&gt;retries&lt;/strong&gt; to make most calls succeed in an acceptable time.&lt;/p&gt;

&lt;p&gt;Finally we call the push notification service. The primary service of choice will be tried first, but fails with a probability of 50% and has an &lt;strong&gt;average response time&lt;/strong&gt; of 1s. We give that a maximum of 2 &lt;strong&gt;retries&lt;/strong&gt;. After that we call the secondary service of choice as a &lt;strong&gt;fallback&lt;/strong&gt;, which has a probability of ~100% and a response time of 3s. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sample output of the running result&lt;/strong&gt;&lt;br&gt;
Here you find the output of the final result. Try to see where we had a false positive and where not. Where did we use the expensive push notification service? It's all written in the logs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;2022-07-24 16:03:53,936 INFO  [de.fay.sna.SnakeAlarmProcessor] (vert.x-eventloop-thread-0) Received an alarm for snake alarm fulfillment: [SnakeItems(id=1, imageASCIIArtString=e--==--==--)], False positive - Successfully verified a lizard
2022-07-24 16:03:53,994 DEBUG [io.sma.rea.mes.amqp] (vert.x-eventloop-thread-2) SRMSG16211: Sending AMQP message to address `snake-alarms`
2022-07-24 16:03:54,000 FINE  [pro.trace] (vert.x-eventloop-thread-0) IN: CH[0] : Disposition{role=RECEIVER, first=1, last=1, settled=true, state=Accepted{}, batchable=false}
2022-07-24 16:03:54,001 FINE  [pro.trace] (vert.x-eventloop-thread-0) IN: CH[0] : Transfer{handle=0, deliveryId=1, deliveryTag=\x00, messageFormat=0, settled=false, more=false, rcvSettleMode=null, state=null, resume=false, aborted=false, batchable=false}[\x00Ss\xd0\x00\x00\x00)\x00\x00\x00\x07@@\xa1\x0csnake-alarms@@@\xa3\x10application/json\x00Su\xa0\x9c{"snakes":[{"id":"1","imageASCIIArtString":"e--==--==--"}],"snakeVerification":"Snake could also be a lizard :-)","estimatedPushNotificationTimestamp":null}]
2022-07-24 16:03:54,460 DEBUG [io.sma.rea.mes.amqp] (vert.x-eventloop-thread-2) SRMSG16211: Sending AMQP message to address `snake-alarms`
2022-07-24 16:03:54,463 FINE  [pro.trace] (vert.x-eventloop-thread-0) IN: CH[0] : Transfer{handle=0, deliveryId=2, deliveryTag=\x01, messageFormat=0, settled=false, more=false, rcvSettleMode=null, state=null, resume=false, aborted=false, batchable=false}[\x00Ss\xd0\x00\x00\x00)\x00\x00\x00\x07@@\xa1\x0csnake-alarms@@@\xa3\x10application/json\x00Su\xa0\x9c{"snakes":[{"id":"1","imageASCIIArtString":"e--==--==--"}],"snakeVerification":"Snake could also be a lizard :-)","estimatedPushNotificationTimestamp":null}]
2022-07-24 16:03:54,464 FINE  [pro.trace] (vert.x-eventloop-thread-0) IN: CH[0] : Disposition{role=RECEIVER, first=2, last=2, settled=true, state=Accepted{}, batchable=false}
2022-07-24 16:03:54,579 INFO  [de.fay.sna.SnakeAlarmProcessor] (vert.x-eventloop-thread-0) Received an alarm for snake alarm fulfillment: [SnakeItems(id=1, imageASCIIArtString=e--==--==--)], False positive - Successfully verified a lizard
2022-07-24 16:03:54,937 INFO  [de.fay.sna.SnakeAlarmProcessor] (vert.x-eventloop-thread-0) Received an alarm for snake alarm fulfillment: [SnakeItems(id=1, imageASCIIArtString=e--==--==--)], False positive - Successfully verified a lizard
2022-07-24 16:03:56,180 DEBUG [io.sma.rea.mes.amqp] (vert.x-eventloop-thread-2) SRMSG16211: Sending AMQP message to address `snake-alarms`
2022-07-24 16:03:56,185 FINE  [pro.trace] (vert.x-eventloop-thread-0) IN: CH[0] : Disposition{role=RECEIVER, first=3, last=3, settled=true, state=Accepted{}, batchable=false}
2022-07-24 16:03:56,186 FINE  [pro.trace] (vert.x-eventloop-thread-0) IN: CH[0] : Transfer{handle=0, deliveryId=3, deliveryTag=\x00, messageFormat=0, settled=false, more=false, rcvSettleMode=null, state=null, resume=false, aborted=false, batchable=false}[\x00Ss\xd0\x00\x00\x00)\x00\x00\x00\x07@@\xa1\x0csnake-alarms@@@\xa3\x10application/json\x00Su\xa0\x9c{"snakes":[{"id":"1","imageASCIIArtString":"e--==--==--"}],"snakeVerification":"Snake could also be a lizard :-)","estimatedPushNotificationTimestamp":null}]
2022-07-24 16:03:56,618 DEBUG [io.sma.rea.mes.amqp] (vert.x-eventloop-thread-2) SRMSG16211: Sending AMQP message to address `snake-alarms`
2022-07-24 16:03:56,622 FINE  [pro.trace] (vert.x-eventloop-thread-0) IN: CH[0] : Transfer{handle=0, deliveryId=4, deliveryTag=\x01, messageFormat=0, settled=false, more=false, rcvSettleMode=null, state=null, resume=false, aborted=false, batchable=false}[\x00Ss\xd0\x00\x00\x00)\x00\x00\x00\x07@@\xa1\x0csnake-alarms@@@\xa3\x10application/json\x00Su\xa0\x9c{"snakes":[{"id":"1","imageASCIIArtString":"e--==--==--"}],"snakeVerification":"Snake could also be a lizard :-)","estimatedPushNotificationTimestamp":null}]
2022-07-24 16:03:56,625 FINE  [pro.trace] (vert.x-eventloop-thread-0) IN: CH[0] : Disposition{role=RECEIVER, first=4, last=4, settled=true, state=Accepted{}, batchable=false}
2022-07-24 16:03:57,105 DEBUG [io.sma.rea.mes.amqp] (vert.x-eventloop-thread-2) SRMSG16211: Sending AMQP message to address `snake-alarms`
2022-07-24 16:03:57,110 FINE  [pro.trace] (vert.x-eventloop-thread-0) IN: CH[0] : Disposition{role=RECEIVER, first=5, last=5, settled=true, state=Accepted{}, batchable=false}
2022-07-24 16:03:57,111 FINE  [pro.trace] (vert.x-eventloop-thread-0) IN: CH[0] : Transfer{handle=0, deliveryId=5, deliveryTag=\x02, messageFormat=0, settled=false, more=false, rcvSettleMode=null, state=null, resume=false, aborted=false, batchable=false}[\x00Ss\xd0\x00\x00\x00)\x00\x00\x00\x07@@\xa1\x0csnake-alarms@@@\xa3\x10application/json\x00Su\xa0\x9c{"snakes":[{"id":"1","imageASCIIArtString":"e--==--==--"}],"snakeVerification":"Snake could also be a lizard :-)","estimatedPushNotificationTimestamp":null}]
2022-07-24 16:03:57,219 INFO  [de.fay.sna.SnakeAlarmProcessor] (vert.x-eventloop-thread-0) Received an alarm for snake alarm fulfillment: [SnakeItems(id=1, imageASCIIArtString=e--==--==--)], False positive - Successfully verified a lizard
2022-07-24 16:03:57,534 DEBUG [io.sma.rea.mes.amqp] (vert.x-eventloop-thread-2) SRMSG16211: Sending AMQP message to address `snake-alarms`
2022-07-24 16:03:57,538 FINE  [pro.trace] (vert.x-eventloop-thread-0) IN: CH[0] : Disposition{role=RECEIVER, first=6, last=6, settled=true, state=Accepted{}, batchable=false}
2022-07-24 16:03:57,539 FINE  [pro.trace] (vert.x-eventloop-thread-0) IN: CH[0] : Transfer{handle=0, deliveryId=6, deliveryTag=\x00, messageFormat=0, settled=false, more=false, rcvSettleMode=null, state=null, resume=false, aborted=false, batchable=false}[\x00Ss\xd0\x00\x00\x00)\x00\x00\x00\x07@@\xa1\x0csnake-alarms@@@\xa3\x10application/json\x00Su\xa0\x9c{"snakes":[{"id":"1","imageASCIIArtString":"e--==--==--"}],"snakeVerification":"Snake could also be a lizard :-)","estimatedPushNotificationTimestamp":null}]
2022-07-24 16:03:58,039 INFO  [de.fay.sna.SnakeAlarmProcessor] (vert.x-eventloop-thread-0) Received an alarm for snake alarm fulfillment: [SnakeItems(id=1, imageASCIIArtString=e--==--==--)], False positive - Successfully verified a lizard
2022-07-24 16:03:58,041 INFO  [de.fay.sna.SnakeAlarmProcessor] (vert.x-eventloop-thread-0) Received an alarm for snake alarm fulfillment: [SnakeItems(id=1, imageASCIIArtString=e--==--==--)], Danger - Successfully verified a snake
2022-07-24 16:03:58,052 INFO  [de.fay.sna.PushNotificationService] (vert.x-eventloop-thread-0) Push notification estimated in 3 sec
2022-07-24 16:03:58,420 INFO  [de.fay.sna.SnakeAlarmProcessor] (vert.x-eventloop-thread-0) Received an alarm for snake alarm fulfillment: [SnakeItems(id=1, imageASCIIArtString=e--==--==--)], False positive - Successfully verified a lizard
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Postman&lt;/strong&gt; &lt;br&gt;
This is an exemplary POST request we are going to use to fire up our services. If we make the request right, we should receive a &lt;strong&gt;202 Accepted&lt;/strong&gt; response. You will find this as a Postman collection in the &lt;a href="https://github.com/feliciafaye/resist-part-3" rel="noopener noreferrer"&gt;Github&lt;/a&gt; sources.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F79dw9auusqh5q4f0dqsf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F79dw9auusqh5q4f0dqsf.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Snake alarm endpoint&lt;/strong&gt; &lt;br&gt;
Our endpoint calls the SnakeAlarmRepository to take care of everything.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"snake-alarm"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SnakeAlarmEndpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;snakeAlarmRepository&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;SnakeAlarmRepository&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@POST&lt;/span&gt;
    &lt;span class="nd"&gt;@Consumes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MediaType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;APPLICATION_JSON&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nd"&gt;@Produces&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MediaType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;TEXT_PLAIN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;suspend&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;snakeAlarm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;SnakeAlarmRequest&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;snakeAlarmRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;alarm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;snakes&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;true&lt;/span&gt;  &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;accepted&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="k"&gt;false&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;serverError&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The SnakeAlarmRepository emits the alarm without verification using an AMQP messaging channel named &lt;strong&gt;snake-alarms-out&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@ApplicationScoped&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SnakeAlarmRepository&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;pushNotificationService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;PushNotificationService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nd"&gt;@Channel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"snake-alarms-out"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;snakeAlarmEmitter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Emitter&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SnakeAlarm&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;,&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Logger&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;suspend&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;alarm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SnakeItems&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;):&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;snakeAlarm&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SnakeAlarm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;snakes&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;snakeVerification&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Snake could also be a lizard :-)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;estimatedPushNotificationTimestamp&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;snakeAlarmEmitter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;snakeAlarm&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;await&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="k"&gt;true&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Level&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SEVERE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Error while sending snake alarm"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;false&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Application Properties&lt;/strong&gt;&lt;br&gt;
That's where we need to configure our loosely coupled AMPQ messaging channels, which will run using a Docker image (a sample Docker file is provided in the &lt;a href="https://github.com/feliciafaye/resist-part-3" rel="noopener noreferrer"&gt;Github&lt;/a&gt; sources).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;quarkus.log.level=DEBUG
quarkus.log.category."org.jboss.resteasy".min-level=DEBUG
# The AMQP broker location and credentials
amqp-host=localhost
amqp-port=5672
amqp-username=quarkus
amqp-password=quarkus
# Configure snake alarm messaging
mp.messaging.incoming.snake-alarms-in.connector=smallrye-amqp
mp.messaging.incoming.snake-alarms-in.address=snake-alarms
mp.messaging.outgoing.snake-alarms-out.connector=smallrye-amqp
mp.messaging.outgoing.snake-alarms-out.address=snake-alarms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When we receive a message from this channel, the SnakeAlarmProcessor checks if it really is a snake by using the LizardCheck.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@ApplicationScoped&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SnakeAlarmProcessor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;pushNotificationService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;PushNotificationService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;lizardCheck&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;LizardCheck&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Logger&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Incoming&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"snake-alarms-in"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;suspend&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;processSnakeAlarm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;snakeAlarm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;SnakeAlarm&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;isVerifiedSnake&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lizardCheck&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;checkSnakeAlarmValid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;snakeAlarm&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;verificationResultText&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isVerifiedSnake&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="s"&gt;"Danger - Successfully verified a snake"&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="s"&gt;"False positive - Successfully verified a lizard"&lt;/span&gt;

        &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"Received an alarm for snake alarm fulfillment: ${snakeAlarm.snakes}, $verificationResultText"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isVerifiedSnake&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;pushNotificationService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;announcePrimaryPushNotificationService&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The LizardCheck has often timeouts. Therefor we have configured &lt;strong&gt;timeout&lt;/strong&gt; and &lt;strong&gt;retry&lt;/strong&gt; options by using annotations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@ApplicationScoped&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LizardCheck&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Timeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;unit&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ChronoUnit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SECONDS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nd"&gt;@Retry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;maxRetries&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;suspend&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;checkSnakeAlarmValid&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nextBoolean&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nextLong&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1060&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The PushNotificationServices has a method to announce each notification services. The first method has the second method has a fallback. If the &lt;strong&gt;fallback&lt;/strong&gt; is used, we have a &lt;strong&gt;max retry&lt;/strong&gt; of two attempts for that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@ApplicationScoped&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PushNotificationService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Logger&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Fallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fallbackMethod&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"announceSecondaryPushNotificationService"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;announcePrimaryPushNotificationService&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;fail&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nextBoolean&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fail&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Can't reach primary push notification service"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"Push notification estimated in 1 sec"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Calendar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getInstance&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;apply&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Calendar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SECOND&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}.&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Retry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;maxRetries&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;announceSecondaryPushNotificationService&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"Push notification estimated in 3 sec"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Calendar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getInstance&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;apply&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Calendar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SECOND&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}.&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's re-check the logs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;2022-07-24 16:03:53,936 INFO  [de.fay.sna.SnakeAlarmProcessor] (vert.x-eventloop-thread-0) Received an alarm for snake alarm fulfillment: [SnakeItems(id=1, imageASCIIArtString=e--==--==--)], False positive - Successfully verified a lizard
2022-07-24 16:03:53,994 DEBUG [io.sma.rea.mes.amqp] (vert.x-eventloop-thread-2) SRMSG16211: Sending AMQP message to address `snake-alarms`
2022-07-24 16:03:54,000 FINE  [pro.trace] (vert.x-eventloop-thread-0) IN: CH[0] : Disposition{role=RECEIVER, first=1, last=1, settled=true, state=Accepted{}, batchable=false}
2022-07-24 16:03:54,001 FINE  [pro.trace] (vert.x-eventloop-thread-0) IN: CH[0] : Transfer{handle=0, deliveryId=1, deliveryTag=\x00, messageFormat=0, settled=false, more=false, rcvSettleMode=null, state=null, resume=false, aborted=false, batchable=false}[\x00Ss\xd0\x00\x00\x00)\x00\x00\x00\x07@@\xa1\x0csnake-alarms@@@\xa3\x10application/json\x00Su\xa0\x9c{"snakes":[{"id":"1","imageASCIIArtString":"e--==--==--"}],"snakeVerification":"Snake could also be a lizard :-)","estimatedPushNotificationTimestamp":null}]
2022-07-24 16:03:54,460 DEBUG [io.sma.rea.mes.amqp] (vert.x-eventloop-thread-2) SRMSG16211: Sending AMQP message to address `snake-alarms`
2022-07-24 16:03:54,463 FINE  [pro.trace] (vert.x-eventloop-thread-0) IN: CH[0] : Transfer{handle=0, deliveryId=2, deliveryTag=\x01, messageFormat=0, settled=false, more=false, rcvSettleMode=null, state=null, resume=false, aborted=false, batchable=false}[\x00Ss\xd0\x00\x00\x00)\x00\x00\x00\x07@@\xa1\x0csnake-alarms@@@\xa3\x10application/json\x00Su\xa0\x9c{"snakes":[{"id":"1","imageASCIIArtString":"e--==--==--"}],"snakeVerification":"Snake could also be a lizard :-)","estimatedPushNotificationTimestamp":null}]
2022-07-24 16:03:54,464 FINE  [pro.trace] (vert.x-eventloop-thread-0) IN: CH[0] : Disposition{role=RECEIVER, first=2, last=2, settled=true, state=Accepted{}, batchable=false}
2022-07-24 16:03:54,579 INFO  [de.fay.sna.SnakeAlarmProcessor] (vert.x-eventloop-thread-0) Received an alarm for snake alarm fulfillment: [SnakeItems(id=1, imageASCIIArtString=e--==--==--)], False positive - Successfully verified a lizard
2022-07-24 16:03:54,937 INFO  [de.fay.sna.SnakeAlarmProcessor] (vert.x-eventloop-thread-0) Received an alarm for snake alarm fulfillment: [SnakeItems(id=1, imageASCIIArtString=e--==--==--)], False positive - Successfully verified a lizard
2022-07-24 16:03:56,180 DEBUG [io.sma.rea.mes.amqp] (vert.x-eventloop-thread-2) SRMSG16211: Sending AMQP message to address `snake-alarms`
2022-07-24 16:03:56,185 FINE  [pro.trace] (vert.x-eventloop-thread-0) IN: CH[0] : Disposition{role=RECEIVER, first=3, last=3, settled=true, state=Accepted{}, batchable=false}
2022-07-24 16:03:56,186 FINE  [pro.trace] (vert.x-eventloop-thread-0) IN: CH[0] : Transfer{handle=0, deliveryId=3, deliveryTag=\x00, messageFormat=0, settled=false, more=false, rcvSettleMode=null, state=null, resume=false, aborted=false, batchable=false}[\x00Ss\xd0\x00\x00\x00)\x00\x00\x00\x07@@\xa1\x0csnake-alarms@@@\xa3\x10application/json\x00Su\xa0\x9c{"snakes":[{"id":"1","imageASCIIArtString":"e--==--==--"}],"snakeVerification":"Snake could also be a lizard :-)","estimatedPushNotificationTimestamp":null}]
2022-07-24 16:03:56,618 DEBUG [io.sma.rea.mes.amqp] (vert.x-eventloop-thread-2) SRMSG16211: Sending AMQP message to address `snake-alarms`
2022-07-24 16:03:56,622 FINE  [pro.trace] (vert.x-eventloop-thread-0) IN: CH[0] : Transfer{handle=0, deliveryId=4, deliveryTag=\x01, messageFormat=0, settled=false, more=false, rcvSettleMode=null, state=null, resume=false, aborted=false, batchable=false}[\x00Ss\xd0\x00\x00\x00)\x00\x00\x00\x07@@\xa1\x0csnake-alarms@@@\xa3\x10application/json\x00Su\xa0\x9c{"snakes":[{"id":"1","imageASCIIArtString":"e--==--==--"}],"snakeVerification":"Snake could also be a lizard :-)","estimatedPushNotificationTimestamp":null}]
2022-07-24 16:03:56,625 FINE  [pro.trace] (vert.x-eventloop-thread-0) IN: CH[0] : Disposition{role=RECEIVER, first=4, last=4, settled=true, state=Accepted{}, batchable=false}
2022-07-24 16:03:57,105 DEBUG [io.sma.rea.mes.amqp] (vert.x-eventloop-thread-2) SRMSG16211: Sending AMQP message to address `snake-alarms`
2022-07-24 16:03:57,110 FINE  [pro.trace] (vert.x-eventloop-thread-0) IN: CH[0] : Disposition{role=RECEIVER, first=5, last=5, settled=true, state=Accepted{}, batchable=false}
2022-07-24 16:03:57,111 FINE  [pro.trace] (vert.x-eventloop-thread-0) IN: CH[0] : Transfer{handle=0, deliveryId=5, deliveryTag=\x02, messageFormat=0, settled=false, more=false, rcvSettleMode=null, state=null, resume=false, aborted=false, batchable=false}[\x00Ss\xd0\x00\x00\x00)\x00\x00\x00\x07@@\xa1\x0csnake-alarms@@@\xa3\x10application/json\x00Su\xa0\x9c{"snakes":[{"id":"1","imageASCIIArtString":"e--==--==--"}],"snakeVerification":"Snake could also be a lizard :-)","estimatedPushNotificationTimestamp":null}]
2022-07-24 16:03:57,219 INFO  [de.fay.sna.SnakeAlarmProcessor] (vert.x-eventloop-thread-0) Received an alarm for snake alarm fulfillment: [SnakeItems(id=1, imageASCIIArtString=e--==--==--)], False positive - Successfully verified a lizard
2022-07-24 16:03:57,534 DEBUG [io.sma.rea.mes.amqp] (vert.x-eventloop-thread-2) SRMSG16211: Sending AMQP message to address `snake-alarms`
2022-07-24 16:03:57,538 FINE  [pro.trace] (vert.x-eventloop-thread-0) IN: CH[0] : Disposition{role=RECEIVER, first=6, last=6, settled=true, state=Accepted{}, batchable=false}
2022-07-24 16:03:57,539 FINE  [pro.trace] (vert.x-eventloop-thread-0) IN: CH[0] : Transfer{handle=0, deliveryId=6, deliveryTag=\x00, messageFormat=0, settled=false, more=false, rcvSettleMode=null, state=null, resume=false, aborted=false, batchable=false}[\x00Ss\xd0\x00\x00\x00)\x00\x00\x00\x07@@\xa1\x0csnake-alarms@@@\xa3\x10application/json\x00Su\xa0\x9c{"snakes":[{"id":"1","imageASCIIArtString":"e--==--==--"}],"snakeVerification":"Snake could also be a lizard :-)","estimatedPushNotificationTimestamp":null}]
2022-07-24 16:03:58,039 INFO  [de.fay.sna.SnakeAlarmProcessor] (vert.x-eventloop-thread-0) Received an alarm for snake alarm fulfillment: [SnakeItems(id=1, imageASCIIArtString=e--==--==--)], False positive - Successfully verified a lizard
2022-07-24 16:03:58,041 INFO  [de.fay.sna.SnakeAlarmProcessor] (vert.x-eventloop-thread-0) Received an alarm for snake alarm fulfillment: [SnakeItems(id=1, imageASCIIArtString=e--==--==--)], Danger - Successfully verified a snake
2022-07-24 16:03:58,052 INFO  [de.fay.sna.PushNotificationService] (vert.x-eventloop-thread-0) Push notification estimated in 3 sec
2022-07-24 16:03:58,420 INFO  [de.fay.sna.SnakeAlarmProcessor] (vert.x-eventloop-thread-0) Received an alarm for snake alarm fulfillment: [SnakeItems(id=1, imageASCIIArtString=e--==--==--)], False positive - Successfully verified a lizard
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If it is "Danger - Successfully verified a snake" or "False positive - Successfully verified a lizard" inside the log: we always know if we verified a snake. The push notifications are estimated with 1 second for the faster and less reliable primary version and with 3 seconds in case the secondary fallback version succeeds within the two retries.&lt;/p&gt;

&lt;p&gt;Adding resilience to Quarkus using Kotlin is quite easy, cause most of it can be done by using annotations and loose coupling.&lt;/p&gt;

&lt;p&gt;If you want to try the resilience example from above, you can find it on &lt;a href="https://github.com/feliciafaye/resist-part-3" rel="noopener noreferrer"&gt;Github&lt;/a&gt;. Have phun and stay curious.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Epilog&lt;/strong&gt;&lt;br&gt;
Snakes are cool animals. The snake detector is just a fun fiction and does not have the intent to support fears when it comes to wild animals. Next time I'll choose a scenario helping animals :) - cause we should protect all of them. Buy the way: Tardigrades and ants are good examples for very resilient animals!&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>quarkus</category>
      <category>resilience</category>
      <category>microservices</category>
    </item>
    <item>
      <title>Resilient microservices with Quarkus and Kotlin - Design Patterns</title>
      <dc:creator>Felicia Faye</dc:creator>
      <pubDate>Tue, 05 Jul 2022 11:25:30 +0000</pubDate>
      <link>https://dev.to/meikefelicia/resilient-microservices-with-quarkus-and-kotlin-design-patterns-i8o</link>
      <guid>https://dev.to/meikefelicia/resilient-microservices-with-quarkus-and-kotlin-design-patterns-i8o</guid>
      <description>&lt;p&gt;In the first part of the series, we took a closer look on why it is a good strategy to choose Quarkus in combination with Kotlin. Do you also remember the snake scenario? We wanted to create more resilient microservices then expected by default - just to make sure that we're save most of the time. &lt;/p&gt;

&lt;p&gt;A good starting point for the resilience aspects are &lt;strong&gt;resilience design patterns&lt;/strong&gt;. Most of them have the intention to reduce down times and speed up start up times, so that for example containers running in a cluster have a good uptime and can recover rapidly &lt;strong&gt;⚡︎&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Resilience design patterns can be grouped into four main sections:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Isolation&lt;/li&gt;
&lt;li&gt;Loose Coupling&lt;/li&gt;
&lt;li&gt;Supervision&lt;/li&gt;
&lt;li&gt;Latency Control&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Isolation&lt;/strong&gt; patterns are focused on stuff like parameter checking, bulkheads and shed loads. &lt;strong&gt;Loose Coupling&lt;/strong&gt; stands for async communication, idempotency and an event-driven architecture. &lt;strong&gt;Supervision&lt;/strong&gt; patterns deal with monitoring, escalation and error handling, while &lt;strong&gt;latency control&lt;/strong&gt; is about retry, fallback and timeout mechanisms including patterns like circuit breakers and fan in/out strategies.&lt;/p&gt;

&lt;p&gt;We are mainly going to have a closer look to the latency control patterns, but also check out some of the other sections, which help us to build services more resilient.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QHm_Y6kN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/18natqgxckym1odo6xyf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QHm_Y6kN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/18natqgxckym1odo6xyf.png" alt="Image description" width="880" height="305"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First, there is the &lt;strong&gt;retry pattern&lt;/strong&gt;, where we would simply retry what failed before. In case of our snake scenario imagine a snake detector service, which needs to call a push notification service, which isn't very reliable.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GhRovU4W--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4zwmhzh704zeav15dvsa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GhRovU4W--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4zwmhzh704zeav15dvsa.png" alt="Image description" width="880" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As a solution we could just retry until we succeed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_0XvkHb5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yblvx104mgt9itowdkfr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_0XvkHb5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yblvx104mgt9itowdkfr.png" alt="Image description" width="880" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This strategy is suitable for issues like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;temporary network issues and packet loss&lt;/li&gt;
&lt;li&gt;internal server errors of the target system&lt;/li&gt;
&lt;li&gt;no or slow response times of the target system&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But wait .. what if the target system is already overloaded? Sometimes, it can be a bad idea to just increase the number of calls to ensure everything is working and even then, it is still not guaranteed.&lt;/p&gt;

&lt;p&gt;So, let's better check another option: the &lt;strong&gt;fallback pattern&lt;/strong&gt;, which uses another alternative option in case of a failure. In our case as we rely on an external push notification service. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--04EAdkLV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0fbl5smxugz2lnxl67m4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--04EAdkLV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0fbl5smxugz2lnxl67m4.png" alt="Image description" width="880" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can just call an alternative service, which is maybe more expensive, but also more reliable in terms of service. Sometimes it also valid to have no fallback as fallback. E.g., when a shopping order service should do an external fraud check, but the fraud check is not that important, that the shop should reject orders for at least smaller amounts of money to ensure a great shopping experience. But in our case, we must ensure that we successfully call a push notification service.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kaM9zwT0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/daf3cb2uzi4zrsdtx92s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kaM9zwT0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/daf3cb2uzi4zrsdtx92s.png" alt="Image description" width="880" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, there is also the &lt;strong&gt;timeout pattern&lt;/strong&gt;. This is quite well known from the HTTP world - especially used by HTTPS. It describes the process of waiting for a certain time to get a successful answer, but then give up actively. In scenarios where we cannot be sure that the call made it through or when we deal with slow servers it can be very helpful to configure and finetune the communication timeout values on a service level.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mh6qLxvq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/soigv1s3gagkv4d81b24.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mh6qLxvq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/soigv1s3gagkv4d81b24.png" alt="Image description" width="880" height="281"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;However, finding the right value can be difficult: we want the timeout to be long enough for slower responses, but giving up actively after a certain while. Tracking failure statistics can help to finetune the proper timeout values.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Circuit breakers&lt;/strong&gt; are another pattern from the latency control family. They are inspired by the electrical breakers and do quite the same: they can sit between two components and control the throughput by being either open, half-open or closed.&lt;/p&gt;

&lt;p&gt;The open state means that the circuit breaker itself is open and active and therefor all requests are blocked and cannot pass like in the illustration below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mJ2sRx_q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/prwcmk2u2qjcsq5ilopc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mJ2sRx_q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/prwcmk2u2qjcsq5ilopc.png" alt="Image description" width="880" height="313"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A circuit breaker is half-open, when only a certain number of requests are allowed to pass.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8W4THW0R--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/95nplbtbbx1q9en0xm85.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8W4THW0R--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/95nplbtbbx1q9en0xm85.png" alt="Image description" width="880" height="313"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When the circuit breaker is closed, all requests go through without any restrictions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NssKHmzk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wgkpyi34fbap1x0sj5d5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NssKHmzk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wgkpyi34fbap1x0sj5d5.png" alt="Image description" width="880" height="313"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This concept can help to protect systems from shutting down due to overload. It is especially helpful in combination with the retry, fallback and timeout patterns.&lt;/p&gt;

&lt;p&gt;Another very helpful pattern is called &lt;strong&gt;fan in / fan out&lt;/strong&gt; and it is also a good example to demonstrate why we want loose coupling. Without loose coupling it would be complicated to apply fan in / fan out, because we need independent components for this: the pattern is about scaling workers or pods for producing and consuming independently. So, in this case &lt;strong&gt;fan in&lt;/strong&gt; means that if producers are too slow and consumers are fast, the producers should be scaled up and maybe the consumers should also be slowed down. &lt;strong&gt;Fan out&lt;/strong&gt; means that when producers are fast and consumers are slow, we want to scale up our consumers and additionally maybe have less producers. This way a system can handle different system loads for example at different day times by scaling workers up and down.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XwscRVfz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1zilukj0vvp9axd4rkwb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XwscRVfz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1zilukj0vvp9axd4rkwb.png" alt="Image description" width="880" height="431"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, after we've seen some helpful design patterns in theory, it's time to evaluate how we can realize them with Quarkus and Kotlin to build microservices more robust: we'll see that in part 3.&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>quarkus</category>
      <category>patterns</category>
      <category>programming</category>
    </item>
    <item>
      <title>Resilient microservices with Quarkus and Kotlin - Introduction</title>
      <dc:creator>Felicia Faye</dc:creator>
      <pubDate>Thu, 26 May 2022 10:39:00 +0000</pubDate>
      <link>https://dev.to/meikefelicia/resilient-microservices-with-quarkus-and-kotlin-introduction-1cil</link>
      <guid>https://dev.to/meikefelicia/resilient-microservices-with-quarkus-and-kotlin-introduction-1cil</guid>
      <description>&lt;p&gt;Stable microservices are not always literally essential for survival, but imagine you live in an area where there are poisonous snakes, and you have many many detectors in your backyard warning you about them. The detectors are communicating via a Wifi connection and REST interface with your server - so this communication should be really robust.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpf84qrp92mh5l2wgi608.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpf84qrp92mh5l2wgi608.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How would you write the code for the server-side microservice?&lt;br&gt;
Which technologies and languages would you use?&lt;/p&gt;

&lt;p&gt;In this series I'll show how to implement resilient microservices using Kotlin and Quarkus. This is the first part of the series giving a short introduction to the technologies we are going to use and why they are a good choice implementing the stated scenario.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why Kotlin?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwu8ngt95oorhz5t8z4kn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwu8ngt95oorhz5t8z4kn.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First of all, let's see why we can benefit from using Kotlin as a primary language. Kotlin had its first official 1.0 release in 2016. Already then it had many improvements over the current state of Java at that time like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Build-in null safety&lt;/li&gt;
&lt;li&gt;Data classes&lt;/li&gt;
&lt;li&gt;Native support for functional programming&lt;/li&gt;
&lt;li&gt;Extension functions&lt;/li&gt;
&lt;li&gt;Smart casts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;just to name a few. Here is a small example of Kotlin in use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="c1"&gt;// non null property&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="c1"&gt;// Int instead of int; no usage of primitives. &lt;/span&gt;
    &lt;span class="c1"&gt;// But compiled to Javas int           &lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
    &lt;span class="c1"&gt;// nullable property              &lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;     
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;user&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="c1"&gt;// named parameters&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"John Smith"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
    &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// destructuring of data classes&lt;/span&gt;
&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="py"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;age&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;description&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;    

&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;descriptionToPrint&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;
        &lt;span class="c1"&gt;// null safe access to description with ?.&lt;/span&gt;
        &lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;let&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"the following description: $it"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; 
        &lt;span class="c1"&gt;// fallback value for a null description &lt;/span&gt;
        &lt;span class="o"&gt;?:&lt;/span&gt; &lt;span class="s"&gt;"no description"&lt;/span&gt;    

&lt;span class="c1"&gt;// String builder&lt;/span&gt;
&lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$name is $age old and $descriptionToPrint"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    
&lt;span class="c1"&gt;// prints: John Smith is 30 old and no description&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On top of that there are many more features available to play around with. Since its early releases the language kept on evolving and new features were added. Most importantly &lt;strong&gt;Coroutines&lt;/strong&gt; and &lt;strong&gt;Flow&lt;/strong&gt; as well as more recent entries into the language like&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Value classes&lt;/li&gt;
&lt;li&gt;Contracts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;or one of the newest additions &lt;strong&gt;&lt;a href="https://www.youtube.com/watch?v=GISPalIVdQY" rel="noopener noreferrer"&gt;Context Receivers&lt;/a&gt;&lt;/strong&gt;, still in an experimental development phase. On top of that it fits quite nicely into my personal ecosystem, which is driven by the facts that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I'm mainly a mobile developer&lt;/li&gt;
&lt;li&gt;I have a strong interest on cross-platform solutions&lt;/li&gt;
&lt;li&gt;I like the Android platform the most&lt;/li&gt;
&lt;li&gt;Most apps work better with a dedicated backend for frontend, so I write those too.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Kotlin provides everything needed for this.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In the native world, Kotlin gained a lot of tracking with the announcement of Google to make it a first class citizen for Android development and later on the leading language, mostly replacing Java in that area.&lt;br&gt;&lt;br&gt;
More recently Kotlin also introduced a solution for cross-platform development in Kotlin Multiplatform, which enabled Kotlin to run the the same code across Android, iOS, Web and Desktop.&lt;br&gt;&lt;br&gt;
Since Java is still strong in the area of backend development many of the frameworks used there are either able to be used with Kotlin or have additional support for Kotlin's unique features. Such frameworks for example are Quarkus, Spring Boot or Micronaut. Also already matured frameworks that are native to Kotlin, like Ktor, are available for developers to choose from.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why Quarkus?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcioskwrd73imz5hr64ta.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcioskwrd73imz5hr64ta.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's have a closer look on Quarkus and why it can help us to fulfil our requirements. What is Quarkus? It provides an easy approach to create a scalable backend on an enterprise level.&lt;/p&gt;

&lt;p&gt;Generally speaking it's a Cloud Native Java stack, which is built with many mature and well known (open source) Java libraries, frameworks and standards. So instead of learning everything new, we can use for example Vert.x, Camel, Hibernate and RESTEasy. In case of standards we can find MicroProfile and selected specifications from Jakarta EE. Dependency injection uses the well known CDI. Looking at annotations, we can use JAX-RS annotations when defining REST endpoints. On one hand JPA annotations can be used to map persistent entities. On the other hand JTA annotations are there to declare transaction boundaries with Hibernate. Last but not least there is SmallRye to configure, secure and monitor our application.&lt;/p&gt;

&lt;p&gt;They say it's&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;supersonic subatomic Java&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Puh Java what?!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Instead of Java only, it also works well with GraalVM and &lt;strong&gt;Kotlin&lt;/strong&gt; YAY!&lt;/p&gt;

&lt;p&gt;We will have a closer look on how to do this, later.&lt;/p&gt;
&lt;h3&gt;
  
  
  What's the idea behind Quarkus?
&lt;/h3&gt;

&lt;p&gt;The idea behind Quarkus is to optimize Java for cloud native environments.&lt;/p&gt;

&lt;p&gt;This is done by several &lt;strong&gt;optimizations during build time&lt;/strong&gt;, a &lt;strong&gt;failed startup intention&lt;/strong&gt; and the fact that it has &lt;strong&gt;Vert.x underneath&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Sounds quite good when running apps in containers!&lt;/p&gt;

&lt;p&gt;What does Quarkus to optimize the build time? During build time Quarkus removes everything which is not needed. Additionally dependency injections are analysed and already injected at compile time - so we could say it is &lt;em&gt;hard wired&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;With their fast startup intention, Quarkus realizes very fast start up times, which is ideal for cloud native environments: when &lt;strong&gt;scaling up&lt;/strong&gt; for launching more containers or in a &lt;strong&gt;Recovery&lt;/strong&gt; scenario for restarting containers.&lt;/p&gt;

&lt;p&gt;Additionally because Quarkus has Vert.x underneath, it relies on the &lt;strong&gt;reactor pattern&lt;/strong&gt;, so it can handle a lot of requests with ease. Good for us when a lot of requests are coming in.&lt;/p&gt;
&lt;h3&gt;
  
  
  From my perspective
&lt;/h3&gt;

&lt;p&gt;Quarkus offers hot reload, which is not self evident in the Java world, but feels like state of the art nowadays. I usually use it on a daily bases, so it is pretty important to me.&lt;/p&gt;

&lt;p&gt;Quarkus has an active and supportive community, where we can contribute and exchange information rapidly. Having a feature request yourself to e.g. enhance Kotlin support? Just talk to them and in the best case offer a PR yourself. You will surely be heard.&lt;/p&gt;

&lt;p&gt;With a long history of writing Java backends, Quarkus makes me also feel at home with their alignment to the JEE specs (Annotations, Extensions, Frameworks, Libraries ...) and especially with RESTeasy. This even does not cause any performance disadvantages, as everything is mapped to Quarkus cloud native at build time. But in contrast to JEE approach to handle annotation processing during runtime, Quarkus is performing these operations during build time which drastically improves the performance of the quarkus app.&lt;br&gt;
If that is not enough, you are still able to compile Quarkus to a native binary which improves the performance even more.&lt;/p&gt;
&lt;h4&gt;
  
  
  Imperative and reactive
&lt;/h4&gt;

&lt;p&gt;Quarkus gives us the freedom to implement our application in an imperative style, which is well known from JEE, but it also allows to use a more reactive approach - leveraging the power of Kotlin Flows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Imperative (REST endpoint)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"greeting"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GreetingEndpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;greetingService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;GreetingService&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@GET&lt;/span&gt;
    &lt;span class="nd"&gt;@Produces&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MediaType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;TEXT_PLAIN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;greeting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@QueryParam&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"username"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; 
            &lt;span class="n"&gt;greetingService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Reactive (Server sent events)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@GET&lt;/span&gt;
&lt;span class="nd"&gt;@Produces&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MediaType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SERVER_SENT_EVENTS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@RestSseElementType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MediaType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;TEXT_PLAIN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;Flow&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;flow&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;emitAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;asFlow&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Easy project setup through code generation
&lt;/h4&gt;

&lt;p&gt;Getting started is quite easy by visiting &lt;a href="https://code.quarkus.io/" rel="noopener noreferrer"&gt;https://code.quarkus.io/&lt;/a&gt;. As a first step start searching for &lt;strong&gt;Kotlin&lt;/strong&gt; and select the related checkbox.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm5jg6iubwrzvsofamfvx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm5jg6iubwrzvsofamfvx.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After that go searching for &lt;strong&gt;RESTeasy-reactive&lt;/strong&gt; and make sure that the related checkbox is also selected.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxmfje7nb3q3ejoo4icv9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxmfje7nb3q3ejoo4icv9.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nice! Our app is ready for download.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq9cw32dfg08gyg0csele.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq9cw32dfg08gyg0csele.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we can start writing our first endpoint.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"greeting"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GreetingEndpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;greetingService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;GreetingService&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@GET&lt;/span&gt;
    &lt;span class="nd"&gt;@Produces&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MediaType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;TEXT_PLAIN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;greeting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@QueryParam&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"username"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; 
            &lt;span class="n"&gt;greetingService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code sample above gives us a &lt;strong&gt;GET endpoint&lt;/strong&gt; with a &lt;strong&gt;query parameter&lt;/strong&gt; for the &lt;strong&gt;username&lt;/strong&gt; and produces a &lt;strong&gt;greeting response&lt;/strong&gt; message with media type &lt;strong&gt;TEXT_PLAIN&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;To make it run just execute&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;quarkus dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;in your command line. Use a rest client like postman to test the response.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft4votl08xjntpv697kf3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft4votl08xjntpv697kf3.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  But how to make this resilient?
&lt;/h2&gt;

&lt;p&gt;We'll see that in &lt;strong&gt;Part 2&lt;/strong&gt; by highlighting the &lt;strong&gt;resilience design patterns&lt;/strong&gt; that do the most to reduce recovery times and down times - stay tuned.&lt;/p&gt;

&lt;p&gt;In the meantime, if you want to try my welcome example from above, you can find it on &lt;a href="https://github.com/feliciafaye/resist-part-1" rel="noopener noreferrer"&gt;Github&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>quarkus</category>
      <category>microservices</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
