<?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: Kevin Wu</title>
    <description>The latest articles on DEV Community by Kevin Wu (@transienterror).</description>
    <link>https://dev.to/transienterror</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%2F307156%2F372bac07-69d2-4253-9c89-3aa43afe1447.jpeg</url>
      <title>DEV Community: Kevin Wu</title>
      <link>https://dev.to/transienterror</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/transienterror"/>
    <language>en</language>
    <item>
      <title>Serverless Design Principles</title>
      <dc:creator>Kevin Wu</dc:creator>
      <pubDate>Fri, 25 Mar 2022 05:15:48 +0000</pubDate>
      <link>https://dev.to/transienterror/serverless-design-principles-4jl7</link>
      <guid>https://dev.to/transienterror/serverless-design-principles-4jl7</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Serverless is becoming more and more popular these days. It has always&lt;br&gt;
been an interesting space for me because I\'m interested in the&lt;br&gt;
stateless functional style of programming. I started working on Lambda&lt;br&gt;
functions essentially as my first project as an SDE at Amazon back in&lt;br&gt;
2017, worked with one of our purely serverless data storage services at&lt;br&gt;
Amazon Fashion, eventually made my way to the actual Lambda backend&lt;br&gt;
team, and now at Microsoft I find myself working with Azure Functions&lt;br&gt;
again. Obviously, Lambda has not really existed for &lt;em&gt;that&lt;/em&gt; long, so I&lt;br&gt;
think I\'ve basically maxed out on possible number of years of&lt;br&gt;
Serverless experience. I hope to highlight some of the more interesting&lt;br&gt;
differences between more \"classic\" design with servers and serverless&lt;br&gt;
design.&lt;/p&gt;
&lt;h2&gt;
  
  
  Motivations
&lt;/h2&gt;

&lt;p&gt;I wanted to start with why we would use Lambda/Functions over classic&lt;br&gt;
VMs or Kubernetes clusters. The original motivation for Lambda was&lt;br&gt;
mostly to save costs, but later on we noticed some efficiencies that&lt;br&gt;
could only be realized at Lambda scale.&lt;/p&gt;
&lt;h3&gt;
  
  
  Saving costs
&lt;/h3&gt;

&lt;p&gt;There are a lot of web services out there that generally serve less than&lt;br&gt;
1 transaction per second, but were still costing a lot in VM usage. The&lt;br&gt;
idea was that there should be an efficient way for us to schedule a lot&lt;br&gt;
of these web services on the same hardware so that we can save a lot of&lt;br&gt;
money.&lt;/p&gt;
&lt;h3&gt;
  
  
  Efficiencies at scale, minimizing resource contention with data
&lt;/h3&gt;

&lt;p&gt;After running Lambda for a while, Lambda realized there were ways that&lt;br&gt;
we could schedule work really efficiently. Lambda has the data to&lt;br&gt;
analyze different workflows to see what their bottleneck resource is,&lt;br&gt;
and schedule them such that the functions would not have to contend for&lt;br&gt;
the same resource at the same time. For example, it would be optimal to&lt;br&gt;
schedule a memory-heavy workflow with a compute-heavy workflow, so they&lt;br&gt;
are much less likely to contend for the same resources. There is an&lt;br&gt;
excellent talk by Marc Brooker about this you can find here&lt;br&gt;
&lt;a href="https://youtu.be/xmacMfbrG28?t=1310"&gt;https://youtu.be/xmacMfbrG28?t=1310&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  It\'s just easier
&lt;/h3&gt;

&lt;p&gt;I\'d be remiss if I didn\'t include this, but a lot of the time, Lambda&lt;br&gt;
and its ilk are just the easiest services to set up, requiring little&lt;br&gt;
knowledge of server infrastructure, and that makes it much easier to use&lt;br&gt;
to a broad audience. Last year, I threw together a demo of a bookstore&lt;br&gt;
to give a talk on design for the CS department at my alma mater, and it&lt;br&gt;
was just easier to use API Gateway backed by Lambda and DynamoDB, so I&lt;br&gt;
didn\'t have to really think about servers at all.&lt;/p&gt;
&lt;h2&gt;
  
  
  Key ideas
&lt;/h2&gt;

&lt;p&gt;These are some key ideas that will come up repeatedly in our best&lt;br&gt;
practices. I\'m highlighting these specifically because they differ from&lt;br&gt;
traditional \"serverful\" architecture.&lt;/p&gt;
&lt;h3&gt;
  
  
  Concurrency
&lt;/h3&gt;

&lt;p&gt;We use the number of concurrent invocations to talk about the scale of a&lt;br&gt;
Function, not requests per second or capacity, which is more&lt;br&gt;
traditional. You can calculate your concurrency by multiplying your&lt;br&gt;
requests per second by the expected latency of the request, &lt;a href="https://en.wikipedia.org/wiki/Little%27s_law"&gt;see&lt;br&gt;
Little\'s Law&lt;/a&gt;. There is&lt;br&gt;
actually quite a lot of content in Marc\'s talk that I linked to earlier&lt;br&gt;
about this if you want a deeper dive on why this is the case. The main&lt;br&gt;
reason is that concurrency is a measure that doesn\'t depend on hardware&lt;br&gt;
(hence serverless right?). Concurrency also takes into account how&lt;br&gt;
efficiently you\'re responding to requests rather than just how many&lt;br&gt;
requests you\'re getting. One common ticket I\'d see at Lambda would be&lt;br&gt;
a team wondering why they were being throttled when they had low&lt;br&gt;
requests per second (more on this later).&lt;/p&gt;
&lt;h3&gt;
  
  
  Cold starts
&lt;/h3&gt;

&lt;p&gt;The big issue with serverless that people like to talk about is higher&lt;br&gt;
latency from cold starts. A cold start&lt;sup id="fnref1"&gt;1&lt;/sup&gt; is essentially when your&lt;br&gt;
execution environment needs to both prepare for the execution, and then&lt;br&gt;
actually perform the execution. At Lambda, we called these stages &lt;em&gt;Init&lt;/em&gt;&lt;br&gt;
and &lt;em&gt;Invoke&lt;/em&gt;. It\'s not uncommon to see cold starts that are over 10&lt;br&gt;
seconds, especially if you\'re not careful. I\'ve also seen many tickets&lt;br&gt;
about this in my time at Lambda.&lt;/p&gt;
&lt;h2&gt;
  
  
  Quick detour on code/data reuse.
&lt;/h2&gt;

&lt;p&gt;I also wanted to include a quick interlude about how persistent&lt;br&gt;
resources get reused because I think it\'s practical for those new at&lt;br&gt;
writing these Functions.&lt;/p&gt;
&lt;h3&gt;
  
  
  Class members
&lt;/h3&gt;

&lt;p&gt;We talked a little bit about &lt;em&gt;init&lt;/em&gt; and &lt;em&gt;invoke&lt;/em&gt;. Intuitively, you\'d&lt;br&gt;
think well I\'m creating some resources, let\'s say a DB client, during&lt;br&gt;
the &lt;em&gt;init&lt;/em&gt; phase, but how does it get reused? Do I instantiate a new&lt;br&gt;
client per request, or can we reuse resources across invokes? The&lt;br&gt;
answer, thankfully, is that you &lt;em&gt;do&lt;/em&gt; in fact reuse these resources&lt;br&gt;
across invokes. If you initialize your DB client outside of your&lt;br&gt;
function definition, it will be reused the next time you invoke, so&lt;br&gt;
members of your class probably behave as you would expect coming from a&lt;br&gt;
more serverful background. Let me illustrate this with a quick example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;db_client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;handle_invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;db_client&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;db_client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DbClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;db_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_some_stuff&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On your first invoke, you will instantiate a new &lt;code&gt;DbClient&lt;/code&gt;{.verbatim},&lt;br&gt;
but on subsequent requests to the same execution environment,&lt;br&gt;
&lt;code&gt;db_client&lt;/code&gt;{.verbatim} will continue to already be instantiated, so you&lt;br&gt;
will be able to &lt;code&gt;get_some_stuff&lt;/code&gt;{.verbatim} directly.&lt;/p&gt;

&lt;p&gt;The more perceptive readers may notice a potential problem here. If&lt;br&gt;
you\'re following security best practices using ephemeral credentials&lt;br&gt;
that expire after some hours, you could experience credentials issues by&lt;br&gt;
reusing these clients. If you\'re using the AWS SDK, this will be&lt;br&gt;
generally handled for you, but otherwise it\'s something to keep in mind&lt;br&gt;
as you\'re developing.&lt;/p&gt;
&lt;h3&gt;
  
  
  File System
&lt;/h3&gt;

&lt;p&gt;This is a quick one. If you use EFS with Lambda or by default with Azure&lt;br&gt;
Functions, your invokes all share the same file system. This was&lt;br&gt;
originally meant for machine learning workflows, where people have&lt;br&gt;
relatively large training models they want to load, but has plenty of&lt;br&gt;
other uses.&lt;/p&gt;
&lt;h2&gt;
  
  
  Best practices
&lt;/h2&gt;

&lt;p&gt;Here are a collection of best practices that I found to be less commonly&lt;br&gt;
reported, but are really helpful with design.&lt;/p&gt;
&lt;h3&gt;
  
  
  Keep functions short (like less than 2 minutes)
&lt;/h3&gt;

&lt;p&gt;If you read the Azure Functions best practices, they say that you should&lt;br&gt;
keep your functions short because they timeout. This is true, of course.&lt;br&gt;
Lambda used to time out at 5 minutes, but now has extended to 15&lt;br&gt;
minutes. So you might think, well, if I limit my function to 10 minutes,&lt;br&gt;
I should be pretty safe. Unfortunately, there is more nuance here.&lt;br&gt;
Earlier, I introduced the concept of concurrency and Little\'s Law.&lt;/p&gt;

&lt;p&gt;::: center&lt;br&gt;
L=&lt;code&gt;\lambdaW&lt;/code&gt;{=latex}&lt;br&gt;
:::&lt;/p&gt;

&lt;p&gt;&lt;code&gt;L&lt;/code&gt;{.verbatim} is the concurrency. λ is the effective arrival rate&lt;br&gt;
(requests per second), and &lt;code&gt;W&lt;/code&gt;{.verbatim} is the wait time (latency).&lt;/p&gt;

&lt;p&gt;For example, the largest throttling point for Lambda in one of the&lt;br&gt;
regions is 3000 concurrent invokes. If you consider a 10 minute function&lt;br&gt;
(600 seconds), we can calculate the λ, or requests per second at which&lt;br&gt;
you\'ll be throttled.&lt;/p&gt;

&lt;p&gt;::: center&lt;br&gt;
3000=&lt;em&gt;λ&lt;/em&gt; * 600&lt;/p&gt;

&lt;p&gt;&lt;em&gt;λ&lt;/em&gt; = 3000/600&lt;/p&gt;

&lt;p&gt;&lt;em&gt;λ&lt;/em&gt; = 5&lt;br&gt;
:::&lt;/p&gt;

&lt;p&gt;Oops, just 5?&lt;/p&gt;

&lt;p&gt;From the equation itself, you can see that the higher the latency, the&lt;br&gt;
lower the requests per second your function will be able to handle. Even&lt;br&gt;
using the default numbers, the λ decreases unintuitively quickly as W&lt;br&gt;
increases.&lt;/p&gt;

&lt;p&gt;Generally speaking, Lambda is designed to execute short functions, and&lt;br&gt;
other tools such as AWS Batch or ECS are better suited for longer&lt;br&gt;
running jobs.&lt;/p&gt;
&lt;h3&gt;
  
  
  Cold start related
&lt;/h3&gt;

&lt;p&gt;Let\'s dig a little deeper on the steps to &lt;em&gt;init&lt;/em&gt;. Generally speaking,&lt;br&gt;
no matter the serverless environment, we have to do these things.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Acquire an execution sandbox&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Pull the code/executable into the sandbox&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Start the executable runtime e.g. JVM or CLR&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt; Run your init code.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;
  
  
  Keep functions small (like under 50MB)
&lt;/h4&gt;

&lt;p&gt;We\'ve also already talked about cold starts. One of the most&lt;br&gt;
unintuitively slow parts of a cold start is actually pulling your&lt;br&gt;
code/binary. I suggested the limit of 50MB or so mainly because lots of&lt;br&gt;
people insist on using Java or C# to write functions, but in reality if&lt;br&gt;
you\'re using an interpreted runtime like python or node, you can easily&lt;br&gt;
keep your code under 1MB. I mean in this case Java and C# will be like&lt;br&gt;
50x slower, and that\'s just to download the executable.&lt;/p&gt;
&lt;h4&gt;
  
  
  Use an interpreted runtime for more predictable results
&lt;/h4&gt;

&lt;p&gt;While we\'re on the topic of runtimes, try to use a fast runtime. JVM&lt;br&gt;
and CLR have a reputation of taking a long time to initialize. I would&lt;br&gt;
routinely see such functions take upwards of 10 seconds to initialize.&lt;br&gt;
While JVM and CLR languages generally execute faster than node or&lt;br&gt;
python, (if you\'re following the earlier advice about function&lt;br&gt;
duration), you are spending a much higher proportion of your time in&lt;br&gt;
&lt;em&gt;init&lt;/em&gt; causing more latency instability when you do hit a cold start. In&lt;br&gt;
my experience, node has been a good choice for having a more consistent&lt;br&gt;
experience. You can also bypass the runtime completely and pick a&lt;br&gt;
compiled language like Golang or Rust&lt;sup id="fnref2"&gt;2&lt;/sup&gt;. I\'ve also been on teams that&lt;br&gt;
used Golang to great effect with Lambda as well.&lt;/p&gt;
&lt;h3&gt;
  
  
  Be mindful of price
&lt;/h3&gt;

&lt;p&gt;It\'s easy to get lost in the ease of using Functions and forget how&lt;br&gt;
much you\'re spending. I\'ve accidentally spent thousands of dollars (of&lt;br&gt;
Amazon\'s money) in just a few days. The pricing model is a constant&lt;br&gt;
cost per invoke and then a rate on GBs, where GB is how much memory&lt;br&gt;
you\'ve allocated (not how much you\'re using) and seconds of invocation&lt;br&gt;
rounded to the nearest millisecond. This means the less you use, the&lt;br&gt;
less you pay, but also conversely, the more you use, the more you pay.&lt;br&gt;
It\'d be good to look up how much it would cost to get a VM or&lt;br&gt;
Kubernetes to do the same job and make sure you\'re willing to pay the&lt;br&gt;
excess. I\'ve found that the point where Lambda starts costing more&lt;br&gt;
happens at a much lower concurrency than people generally think. Of&lt;br&gt;
course, functions &lt;em&gt;do&lt;/em&gt; more than VMs. They scale automagically, do OS&lt;br&gt;
patching, etc, so it may be worth it to you, but you should at least&lt;br&gt;
know how much you\'re paying for that.&lt;/p&gt;
&lt;h2&gt;
  
  
  Assorted Tips
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Lambda currently doesn\'t charge for inits under 10s
&lt;/h3&gt;

&lt;p&gt;Lambda doesn\'t really like people spreading this particular tidbit, but&lt;br&gt;
this is relatively widely known now. In order to optimize cold start&lt;br&gt;
times, your &lt;em&gt;init&lt;/em&gt; phase is generally run on a more powerful sandbox&lt;br&gt;
&lt;strong&gt;and&lt;/strong&gt; you don\'t have to pay for it. The caveat is that if you spend&lt;br&gt;
more than 10 seconds in the &lt;em&gt;init&lt;/em&gt; phase, the sandbox is restarted and&lt;br&gt;
you &lt;strong&gt;will&lt;/strong&gt; be charged for &lt;em&gt;init&lt;/em&gt;. There is a blog post that went&lt;br&gt;
relatively viral about this phenomenon:&lt;br&gt;
&lt;a href="https://hichaelmart.medium.com/shave-99-93-off-your-lambda-bill-with-this-one-weird-trick-33c0acebb2ea"&gt;https://hichaelmart.medium.com/shave-99-93-off-your-lambda-bill-with-this-one-weird-trick-33c0acebb2ea&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Init can happen before you actually make an invoke request
&lt;/h3&gt;

&lt;p&gt;This one surprises customers from time to time, but in order to optimize&lt;br&gt;
cold starts, the platform can initialize your execution environment well&lt;br&gt;
before you actually make an invoke. Especially if you make use of the&lt;br&gt;
dependency injection features. Reworking the previous example a little&lt;br&gt;
bit to show a common way that this comes up:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SomeCustomLogger&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;db_client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DbClient&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="n"&gt;logInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"db_client is initialized"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;handle_invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;db_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_some_stuff&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we log the initialization of &lt;code&gt;db_client&lt;/code&gt;{.verbatim}, you can see that&lt;br&gt;
log statement, even if you &lt;em&gt;did not&lt;/em&gt; make a request.&lt;/p&gt;

&lt;h3&gt;
  
  
  Don\'t use Task without returning something in Azure Functions (when you can)
&lt;/h3&gt;

&lt;p&gt;This is more off a quirk of how async/await works in dotnet, but plain&lt;br&gt;
&lt;code&gt;Task&lt;/code&gt;{.verbatim} functions are syntactic sugar for &lt;code&gt;void&lt;/code&gt;{.verbatim}.&lt;br&gt;
But since execution metadata is saved in the &lt;code&gt;Task&lt;/code&gt;{.verbatim} object,&lt;br&gt;
if you use just plain &lt;code&gt;Task&lt;/code&gt;{.verbatim}, you return &lt;code&gt;void&lt;/code&gt;{.verbatim}&lt;br&gt;
and you lose all your execution metadata. For example, if you return&lt;br&gt;
&lt;code&gt;Task&lt;/code&gt;{.verbatim}, &lt;strong&gt;&lt;em&gt;all Exceptions are suppressed&lt;/em&gt;&lt;/strong&gt; because there is&lt;br&gt;
no way to return them to the caller. For that reason, I suggest at least&lt;br&gt;
returning something like &lt;code&gt;Task&amp;lt;bool&amp;gt;&lt;/code&gt;{.verbatim}, which will throw&lt;br&gt;
Exceptions as expected.&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;Actually, within Lambda we had several levels of cold starts,&lt;br&gt;
which I get into a little bit later, but we\'re keeping it simple&lt;br&gt;
for now. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;Shoutout to &lt;a href="https://github.com/awslabs/aws-lambda-rust-runtime"&gt;https://github.com/awslabs/aws-lambda-rust-runtime&lt;/a&gt;.&lt;br&gt;
But probably you\'ll have issues with Rust\'s really large compiled&lt;br&gt;
binaries. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
    </item>
    <item>
      <title>Moving to Windows from Linux Pt 1</title>
      <dc:creator>Kevin Wu</dc:creator>
      <pubDate>Tue, 05 Oct 2021 11:17:20 +0000</pubDate>
      <link>https://dev.to/transienterror/moving-to-windows-from-linux-pt-1-44f6</link>
      <guid>https://dev.to/transienterror/moving-to-windows-from-linux-pt-1-44f6</guid>
      <description>&lt;p&gt;I've started recently at Microsoft and being a die-hard Linux user for some time, I missed a lot of the cool features I had been using on both Linux and MacOS. In this post, I'm going to talk about some of the tools that I use day to day and how I replaced them on Windows. Even though I used Windows growing up, I was not very technical then, so I still feel like I'm new to the Windows world, so do let me know if there are any other tools that I should know about. Hopefully, this can help some other Linux users who are trying to get comfortable in a Windows environment. I wasn't able to cover all of the tools that I found in this post, so I'll be adding more parts to this as I have time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Package manager (pamac, brew -&amp;gt; scoop)
&lt;/h2&gt;

&lt;p&gt;Lets start with how we can install the software that I will be talking about in later sections!&lt;/p&gt;

&lt;p&gt;Most Linux users are used to some sort of package manager, and I have used quite a lot of them over the years like apt, dnf, yum, pacman, nix + home-manager, and homebrew + linuxbrew. After trying so many, personally, I felt that choosing the path of least resistance is usually the easiest for me because the software tends to be more compatible with each other if I don't mix them or use the one the system intended. Manjaro recommends pamac, so I use that. And on Mac, Homebrew is the staple in this category.&lt;/p&gt;

&lt;p&gt;I know actually these installers are somewhat different. Pamac and its kin actually install onto the system (which is why you need sudo), but I like Homebrew's approach of installing at the user level (which is why you should not use sudo). I am the only user on any of my computers (as are most people these days), and I like the idea of not messing with my system when I don't need to, so I generally prefer to install things as a user. The good people at Apple and Microsoft work hard, after all, to make the System OS stable, and I don't like to mess with their work. Actually, it's even more annoying on Windows because you can't just sudo, you have to open an entire new window as Admin (without any of your user customizations) in order to install software on the system.&lt;/p&gt;

&lt;p&gt;In the Windows world, I found that there's chocolatey, scoop, and winget that are generally used for this purpose. I don't really have access to winget yet, so I ruled that one out pretty quickly. Chocolatey installs on the system rather than as the user, so I chose scoop since I prefer to install as a user. That being said though, I did install chocolatey anyway because their repositories tend to have more software and sometimes that's the only way for me to get software.&lt;/p&gt;

&lt;h2&gt;
  
  
  (Pseudo) Tiling Window Manager (pop-shell, amethyst -&amp;gt; komorebi)
&lt;/h2&gt;

&lt;p&gt;Do you ever get lost in all the windows that you have open? Tiling Window Managers help you keep your windows organized so you can spend more time doing things rather than arranging your windows. I also like that you can drive your entire desktop experience using your keyboard.&lt;/p&gt;

&lt;p&gt;More die-hard Linux users use full-on window managers e.g. i3 or awesome, but I actually prefer to still have a desktop environment, so I use scripts that emulate some of the most important behaviors for me. For most linuxes, I use either pop-shell on GNOME or krohnkite on KDE. On macOS, I use amethyst.&lt;/p&gt;

&lt;p&gt;Pop shell is pretty different from most tiling window managers, but I think it finds a good balance between usability and feature set. On the other hand though, it's hard to find a direct replacement for it. Ultimately (tldr), I settled on komorebi for Windows.&lt;/p&gt;

&lt;p&gt;At first, I used the Microsoft PowerToys, where I found an issue about emulating pop-shell. Eventually in that issue, I found a list of various projects trying to emulate tiling window managers on Windows. At first, it was pretty overwhelming because there are a ton of little-used projects. They were mostly either really young or no longer maintained. Luckily (or maybe not so luckily), I mostly had trouble actually installing a number of them due to being pretty inexperienced with installing OSS on Windows, so I was able to narrow it down quickly to a few projects that had relatively easy install instructions. I started off using workspacer, which worked really well out of the box, but I had trouble configuring it because I didn't know a lot of dotnet or C#.&lt;/p&gt;

&lt;p&gt;I liked komorebi the best because it was using a familiar technology (rust, cargo, autohotkey) and was intuitive to install and configure how I needed it. Since I have to use dotnet and C# for work, I imagine that eventually it'll be easier for me to use workspacer, so I think it might be interesting to try that one again later.&lt;/p&gt;

&lt;h2&gt;
  
  
  System stats monitor (system-monitor, iStat Menus, powerline stats -&amp;gt; Xmeters)
&lt;/h2&gt;

&lt;p&gt;Do you ever run a command and wonder if it actually worked? Especially on an ssh session, I find it comforting to see that the computer is actually doing something. It's also nice to have some system stats visible at all times so that when your computer freezes, you have a general idea as to why that happened.&lt;/p&gt;

&lt;p&gt;Currently when on Linux, I use system-monitor or the built-in KDE widgets. Alternatively, on an ssh session, I use tmux and powerline plugins. On macOS, I use iStat Menus, which work decently well but don't really fit in with the rest of the more elegant macOS aesthetic, or at least the free version.&lt;/p&gt;

&lt;p&gt;This was a pretty quick fix for me. I just searched it quickly on google and came up with XMeters.&lt;/p&gt;

&lt;h2&gt;
  
  
  System monitoring software (Activity Monitor, Gnome System Monitor -&amp;gt; ProcessExplorer)
&lt;/h2&gt;

&lt;p&gt;I'm normally not super picky about this kind of software, and having used Windows throughout my childhood, I am pretty familiar with Task Manager, but there is no way to even search for a process. While googling this issue, I found that a lot of people use Process Explorer, which has a lot of features that Task Manager lacks. I'm honestly not sure how Windows users have gone this long without even the ability to search for a process built-in.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Set Up Grpc Web Server With AWS</title>
      <dc:creator>Kevin Wu</dc:creator>
      <pubDate>Sat, 01 May 2021 12:20:57 +0000</pubDate>
      <link>https://dev.to/transienterror/set-up-grpc-web-server-with-aws-5h77</link>
      <guid>https://dev.to/transienterror/set-up-grpc-web-server-with-aws-5h77</guid>
      <description>&lt;h1&gt;
  
  
  Intro
&lt;/h1&gt;

&lt;p&gt;I was asked on one of my last posts about gRPC, how does one host a gRPC web server. I thought it would be a good opportunity to learn what the AWS customer experience is, currently, for setting up a simple gRPC web server. If you are advanced at gRPC and AWS already, you could probably set it up just using this post: &lt;a href="https://aws.amazon.com/blogs/aws/new-application-load-balancer-support-for-end-to-end-http-2-and-grpc/"&gt;https://aws.amazon.com/blogs/aws/new-application-load-balancer-support-for-end-to-end-http-2-and-grpc/&lt;/a&gt;, which is what I am using to do this. But if you need some guidance on how to use these components, like I did. The following may be helpful to you.&lt;/p&gt;

&lt;h1&gt;
  
  
  Setting up an EC2 instance
&lt;/h1&gt;

&lt;p&gt;My first step is setting up an EC2 instance, which will run our gRPC web server. From the AWS console, &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;select EC2.&lt;/li&gt;
&lt;li&gt;select "Instances"&lt;/li&gt;
&lt;li&gt;select "Launch Instances"&lt;/li&gt;
&lt;li&gt;Next, you can configure your EC2 instance. In case you are unfamiliar, here is what I did:

&lt;ol&gt;
&lt;li&gt;Select Amazon Linux 2 AMI on 64-bit (x86)&lt;/li&gt;
&lt;li&gt;Choose t2.micro (Because it's free)&lt;/li&gt;
&lt;li&gt;Click review and launch and then, on the next page launch&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;li&gt;Make sure that you add TCP on port 50051 as an open inbound port for your security group.&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Set up an ALB for my EC2 instance
&lt;/h1&gt;

&lt;p&gt;Technically, you already have a web server you could host your gRPC web application on, but I wanted to try setting up a load balancer as well. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click "Load Balancers" on the left&lt;/li&gt;
&lt;li&gt;Click "Create Load Balancer"&lt;/li&gt;
&lt;li&gt;Click "Application Load Balancer"

&lt;ol&gt;
&lt;li&gt;Enter any name (I chose "test-alb")&lt;/li&gt;
&lt;li&gt;Under Listeners, choose HTTPS and port 50051&lt;/li&gt;
&lt;li&gt;Under Availability Zones, select two AZs but make sure the one that your EC2 instance was created in is one of them. For me that was &lt;code&gt;us-west-2d&lt;/code&gt;, but you can check on the EC2 console where yours is.&lt;/li&gt;
&lt;li&gt;Click Configure Security Settings&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Creating a certificate
&lt;/h2&gt;

&lt;p&gt;This was one of the toughest parts for me, since I didn't actually have a real certificate to use. Luckily, you can create a self-signed certificate and use it here just fine, but it requires a little extra work. &lt;strong&gt;Note this is not a best practice, but it will work for this little demo.&lt;/strong&gt; First, on my computer I ran&lt;sup id="fnref1"&gt;1&lt;/sup&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes -keyout example.key -out example.crt -subj "/CN=example.com" -addext "subjectAltName-DNS:example.com,DNS:www.example.net,IP:10.0.0.1"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then I tried to use this certificate in various ways, by adding it in the Load Balancer creation UX with both ACM and IAM, and also adding it into ACM through the ACM UX and then trying to choose it here. Unfortunately, they all didn't work for me. Instead what did work for me was importing it into IAM and choosing it here. &lt;strong&gt;This is not a best practice, but it's what we're doing here for convenience.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws iam upload-server-certificate --server-certificate-name test-cert --certificate-body file://example.crt --private-key file://example.key
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, I was able to find this certificate in the Load Balancer creation UX.&lt;/p&gt;

&lt;h2&gt;
  
  
  Load Balancer Creation Continued
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;For Security groups, I just chose the security group my EC2 instance belonged in.&lt;/li&gt;
&lt;li&gt;For Configure Routing, I created a new target group (test-target-group)

&lt;ol&gt;
&lt;li&gt;Choose Instance for target type&lt;/li&gt;
&lt;li&gt;Protocol: HTTPS&lt;/li&gt;
&lt;li&gt;Port 50051&lt;/li&gt;
&lt;li&gt;Protocol Version: gRPC&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;li&gt;Register targets: I chose my EC2 instance here.&lt;/li&gt;
&lt;li&gt;Click review and then create.&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Running a gRPC server on the instance
&lt;/h1&gt;

&lt;p&gt;Next, we want to start some gRPC server on port 50051 so we can do an end to end test.&lt;/p&gt;

&lt;p&gt;I'm starting by running rustup so I can create a simple tonic server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env
cargo new server
cd server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, I open up &lt;code&gt;Cargo.toml&lt;/code&gt; and added &lt;code&gt;tonic&lt;/code&gt; and &lt;code&gt;tonic-health&lt;/code&gt;. e.g.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[dependencies]
tonic = "0.4"
tonic-health = "0.3.1"
tokio = { version = "1.5.0", features = ["full"] }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then &lt;code&gt;cargo build&lt;/code&gt;. This failed for me because it was missing &lt;code&gt;cc&lt;/code&gt;, which is strange because it looks like &lt;code&gt;glibc&lt;/code&gt; is actually installed. But, I just ran &lt;code&gt;sudo yum groupinstall "Development Tools"&lt;/code&gt; which installs a collection of tools, and it worked after that.&lt;/p&gt;

&lt;p&gt;Once that's done, open up &lt;code&gt;src/main.rs&lt;/code&gt; and put in&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#[tokio::main]
async fn main() -&amp;gt; Result&amp;lt;(), Box&amp;lt;dyn std::error::Error&amp;gt;&amp;gt; {
    let (mut health_reporter, health_service) = tonic_health::server::health_reporter();
    health_reporter
        .set_service_status("".to_string(), tonic_health::ServingStatus::Serving)
        .await;

    let addr = "0.0.0.0:50051".parse().unwrap();

    tonic::transport::Server::builder()
        .add_service(health_service)
        .serve(addr)
        .await?;

    Ok(())
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start your server with &lt;code&gt;cargo run&lt;/code&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Testing a request to the Load Balancer
&lt;/h1&gt;

&lt;p&gt;If everything is set up correctly, you should now be able to use &lt;a href="https://github.com/ktr0731/evans"&gt;&lt;code&gt;evans&lt;/code&gt;&lt;/a&gt; to access your web server at the load balancer url or even the url for your ec2 instance directly e.g.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;evans --host &amp;lt;your url&amp;gt; --proto health.proto -p 50051
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can get the health.proto file here:&lt;br&gt;
&lt;a href="https://github.com/hyperium/tonic/blob/master/tonic-health/proto/health.proto"&gt;https://github.com/hyperium/tonic/blob/master/tonic-health/proto/health.proto&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Hopefully, this will help other people who are interested in setting up a gRPC web server on AWS. There doesn't seem to be a lot of documentation out there on this specifically, so I hope that this article will be useful. &lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;This actually didn't work for me on my macOS machine because the openssl typically in the path on macOS is actually LibreSSL. You should instead &lt;code&gt;brew install openssl&lt;/code&gt; and use that binary's absolute path. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>aws</category>
    </item>
    <item>
      <title>Designing an Online Book Store</title>
      <dc:creator>Kevin Wu</dc:creator>
      <pubDate>Mon, 12 Apr 2021 10:38:07 +0000</pubDate>
      <link>https://dev.to/transienterror/designing-an-online-book-store-2j45</link>
      <guid>https://dev.to/transienterror/designing-an-online-book-store-2j45</guid>
      <description>&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;I've been given the opportunity recently to do a small tech talk at a Hackathon taking place at my alma mater. The goal is to both teach how software engineers build something as well as demonstrate it to them live. I wanted to pick a topic that would be somewhat representative to students of what I think most engineers work on, but also something that I had experience with. Having worked in e-commerce for a long time, I decided implementing a store using AWS would be the best way to demonstrate that. Maybe it's generic, but it is an easy-to-understand use-case because most college students have some experience using an online store and building something using cloud tools is likely to be helpful for them in their career in any kind of software engineering (or, at least for the hackathon). It also covers the kind of skills that people want to capture in a systems design interview question (for what that's worth).&lt;/p&gt;

&lt;p&gt;This will be the corresponding blog post in which I cover the same content except it focuses more on the experience of designing the system and my thought processes as I make those decisions. The talk will focus more on the how-to aspect of setting up the project and using the associated tools. Therefore, in this post, you see the more disorganized process of me designing something and maybe backtracking later and changing it a little etc. &lt;/p&gt;

&lt;h1&gt;
  
  
  Requirements
&lt;/h1&gt;

&lt;p&gt;Let's start with what do we want the store to be able to do.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We should be able to browse products. We can implement ~3 products in our example.&lt;/li&gt;
&lt;li&gt;We should be able to add some products to cart, and this cart should persist across browsing sessions. There are a lot of definitions of "session" in the front-end world, but I mean session as in the layman's terms here e.g. closing your browser and revisiting the same url.&lt;/li&gt;
&lt;li&gt;At the end of our "session", we should be able to buy the items in our cart and that order should be logged somewhere.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I think those are the basic elements for a store. Of course, I'm skipping a lot of details for simplicity here. I've worked most of my career to this point in Order Validation and Fulfillment, which both are conveniently ignored here.&lt;/p&gt;

&lt;h1&gt;
  
  
  Data store
&lt;/h1&gt;

&lt;p&gt;I like to start my design with how will we store data. Given the requirements that we've identified, we should identify what kind of data we need to store. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Product information. In order to browse products we need to display information about these products for the customer. Let's call this the catalog.&lt;/li&gt;
&lt;li&gt;Session information. We need to know what products customers have in their cart for the checkout stage.&lt;/li&gt;
&lt;li&gt;Order information. We need to know what customers ordered and how to fulfill that order. We need this to actually ship the product to customers but also for legal and tax reasons.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There are lots of ways to store data and data storage is a complicated topic in itself, but I am planning to do all of this with DynamoDB. The main reason is that I want to help students with their Hackathon. Therefore it's simplest to choose some kind of serverless solution to decrease the complexity of the project. This leaves either DynamoDB or S3, and DynamoDB makes the most sense for these things.And although serverless SQL is starting to exist nowadays, I think that NoSQL makes the most sense for the Hackathon too because we don't have the time to do the proper kind of table design during a Hackathon that SQL really requires.&lt;/p&gt;

&lt;p&gt;We still have to decide exactly how we want to structure our data, so the "data store" aspect of this design is not done, but one of the advantages of NoSQL is that we can decide this later or even as we implement, so I'm moving on to the API design.&lt;/p&gt;

&lt;h1&gt;
  
  
  API -- Or, a brief detour into the definition of an API
&lt;/h1&gt;

&lt;p&gt;At least when I was in college, I didn't really know what API meant, so here's a quick and dirty explanation. I see a lot of people trying to explain what an API is in light of the &lt;em&gt;Oracle V Google&lt;/em&gt; Supreme Court case, and they always just say API stands for Application Programming Interface. I feel that doesn't really help at all, so I will try to describe it differently. In short, software tends to be architected in layers, and an API is the general catch-all term for the ways software layers interact. &lt;/p&gt;

&lt;p&gt;So, for example, in python, in order to write to a file, you could use the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text.txt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;w&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;file_handler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;file_handler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Some string&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Writing files is complicated and depends on your Operating System, your File System, and even the actual kind of disk you have. Generically speaking, you make a request to your Operating System, which in turn makes a request to your File System, which in turn, makes a request to your actual hardware.&lt;/p&gt;

&lt;p&gt;Something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://mermaid-js.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiZ3JhcGggTFI7XG4gICAgaWQxKE9wZXJhdGluZyBTeXN0ZW0pLS0-IGlkMihGaWxlIFN5c3RlbSk7XG4gICAgaWQyKEZpbGUgU3lzdGVtKSAtLT4gSGFyZHdhcmVcbiIsIm1lcm1haWQiOnsidGhlbWUiOiJkZWZhdWx0In0sInVwZGF0ZUVkaXRvciI6ZmFsc2V9" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmermaid.ink%2Fimg%2FeyJjb2RlIjoiZ3JhcGggTFI7XG4gICAgaWQxKE9wZXJhdGluZyBTeXN0ZW0pLS0-IGlkMihGaWxlIFN5c3RlbSk7XG4gICAgaWQyKEZpbGUgU3lzdGVtKSAtLT4gSGFyZHdhcmVcbiIsIm1lcm1haWQiOnsidGhlbWUiOiJkZWZhdWx0In0sInVwZGF0ZUVkaXRvciI6ZmFsc2V9" alt="File write diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But python takes care of this for you, you write this same code regardless of whether your working with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;macOS, APFS, NVME SSD;&lt;/li&gt;
&lt;li&gt;Windows, NTFS, HDD;&lt;/li&gt;
&lt;li&gt;or; Linux, ext4, SATA SSD&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That snippet of python code is described as the File API for python. It's how python programs interact with Files. This allows programmers to create complicated systems without necessarily understanding how each piece of it works as long as they understand the concepts the API designer has created for them.&lt;/p&gt;

&lt;h1&gt;
  
  
  API Design
&lt;/h1&gt;

&lt;p&gt;If the data storage section are the nouns in this project, the APIs are the verbs. What can we do with these data? Let's break these down by the requirements again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Browsing Products
&lt;/h2&gt;

&lt;p&gt;Primarily, we need a way to read the catalog data. Let's call this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;getProduct: (productId: str) -&amp;gt; (Product)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will take a &lt;code&gt;productId&lt;/code&gt; which will be an &lt;a href="https://en.wikipedia.org/wiki/Universally_unique_identifier?oldformat=true" rel="noopener noreferrer"&gt;uuid&lt;/a&gt; and return a &lt;a href="https://en.wikipedia.org/wiki/JSON?oldformat=true" rel="noopener noreferrer"&gt;JSON&lt;/a&gt; representation of your product.&lt;sup id="fnref1"&gt;1&lt;/sup&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Saving a customer's cart session
&lt;/h2&gt;

&lt;p&gt;For this one, I expect customers to need to add products to their cart;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;addToCart: (customerId: str, productId: str) -&amp;gt; ()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;be able to list the items in cart;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;getCart: () -&amp;gt; List&amp;lt;Product&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and remove items from cart;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;removeFromCart: (customerId: str, productId: str) -&amp;gt; ()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note from this, you start to see the benefit of creating these APIs and not using the database directly. You could just read from the database using their API from the client side, but this way, you limit the ways that a customer can interact with the data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Checkout
&lt;/h2&gt;

&lt;p&gt;For checkout, we will be needing the same &lt;code&gt;getCart&lt;/code&gt; that we created earlier. In addition to that, we'll need a way to create orders:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;makeOrder: (customerId: str) -&amp;gt; (orderId: int)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;makeOrder&lt;/code&gt; takes a &lt;code&gt;customerId&lt;/code&gt;, and returns an &lt;code&gt;int&lt;/code&gt; representing the &lt;code&gt;orderId&lt;/code&gt;, which will be visible to the customer, so I've chosen a simple &lt;code&gt;int&lt;/code&gt; to display to them.&lt;/p&gt;

&lt;p&gt;For these APIs, I'm planning to use API Gateway backed by Lambda because I think serverless will be the easiest to use for the Hackathon (but also I'm biased).&lt;/p&gt;

&lt;h1&gt;
  
  
  Customer Interaction
&lt;/h1&gt;

&lt;p&gt;Generally, in this part of the design, we want to imagine the way that customers would interact with this system. For a web application this would be the web page or pages that they would use to shop. Often as a software engineer, this part of the design is usually done in advance. Luckily for the end users, typically Product Managers and/or UX Designers will design the general interface, and engineers only implement it.&lt;/p&gt;

&lt;p&gt;Since I have limited front end experience, having only worked in the front end for a few projects here and there and that front end is generally on the client side and doesn't have too much interaction with cloud architecture. I'm probably going to just make a quick website for demo purposes but not really include it in this design process.&lt;sup id="fnref2"&gt;2&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;My next post will be the how-to post on how to set this up using AWS.&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;Why an uuid instead of just a number? It can be a problem for customers to be able to guess your product ids, but it can also be used by competitors to guess how many products you have. See &lt;a href="https://en.wikipedia.org/wiki/German_tank_problem" rel="noopener noreferrer"&gt;https://en.wikipedia.org/wiki/German_tank_problem&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;Plus it took me two hours to embed the html for that one graphic in this post, so maybe I shouldn't be teaching front end development. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
    </item>
    <item>
      <title>Oncall superstition and the Return to Mean Bias
</title>
      <dc:creator>Kevin Wu</dc:creator>
      <pubDate>Mon, 12 Apr 2021 10:22:37 +0000</pubDate>
      <link>https://dev.to/transienterror/oncall-superstition-and-the-return-to-mean-bias-4k0h</link>
      <guid>https://dev.to/transienterror/oncall-superstition-and-the-return-to-mean-bias-4k0h</guid>
      <description>&lt;p&gt;I've been on call this week, so I haven't had a lot of time to write something out. But one thing I noticed relating to on call is the superstition that: acknowledging that there haven't been a lot of pages will, ironically, cause you to get paged. I'm not sure that there are many people who literally believe that or if it's just a bit of a running joke in the industry. But why is this belief so widespread?&lt;/p&gt;

&lt;p&gt;One thing I've enjoyed during my oncall this week was watching the &lt;a href="https://www.youtube.com/channel/UCgRBRE1DUP2w7HTH9j_L4OQ"&gt;Medlife Crisis youtube channel&lt;/a&gt; and particularly learning about how on call works for doctors. One of his videos was about how bias affects medical research &lt;sup id="fnref1"&gt;1&lt;/sup&gt;. While, watching this, I learned of a particular bias called Return to Mean Bias that describes this phenomenon. In fact, he uses basically the same example in his video with his own on call shifts that he works.&lt;/p&gt;

&lt;p&gt;The logic behind this is simple. If you assume that if you graph your number of incidents over time, you'd fluctuate around a mean value. Then, when you are experiencing a slow on call without a lot of incidents, you are probably in the middle of one of the lull periods in your graph, and therefore more likely to notice that it has been slow. Eventually, though, the number of incidents will have to return to that mean value, so after a lull you're actually more likely to have a rush of incidents.&lt;/p&gt;

&lt;p&gt;Take a look at this visual lovingly designed by my girlfriend:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ysvuNiUX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://kvwu.io/visual_for_kev.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ysvuNiUX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://kvwu.io/visual_for_kev.png" alt="return to mean visual"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The blue line is the mean number of incidents. When you have a slow period, you'll be about to ramp up back toward the mean as long as the mean has not changed.&lt;/p&gt;

&lt;p&gt;That's it. It was interesting to learn that this on call superstition is a probability trick. I will hopefully have more interesting content when my shift is over.&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=ooWA4tM_gUs"&gt;https://www.youtube.com/watch?v=ooWA4tM_gUs&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>devops</category>
    </item>
    <item>
      <title>Setting Up a gRPC Protobuf Server With Tonic
</title>
      <dc:creator>Kevin Wu</dc:creator>
      <pubDate>Mon, 12 Apr 2021 10:18:26 +0000</pubDate>
      <link>https://dev.to/transienterror/setting-up-a-grpc-protobuf-server-with-tonic-218e</link>
      <guid>https://dev.to/transienterror/setting-up-a-grpc-protobuf-server-with-tonic-218e</guid>
      <description>&lt;p&gt;Recently I've been starting to work with gRPC and protobuf. Before this, I was used to using just plain JSON and HTTP. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://grpc.io/"&gt;gRPC&lt;/a&gt; is a system developed by Google for fast RPC-style communication between miroservices. It uses HTTP/2 as its transport protocol, and by default, it uses &lt;a href="https://developers.google.com/protocol-buffers"&gt;protobuf&lt;/a&gt; (analogous to JSON) as its serialization format.&lt;/p&gt;

&lt;p&gt;I really like the idea of having a strong contract between the client and server. I've always been interested in type safety and proofs as code. Traditionally, with JSON, the only contract between client and server is that the reply more or less is in the JSON format and will fit the JSON specification, but you can get no guarantees regarding the structure or data that is transferred. With protobuf, the client and server agree on a contract beforehand with &lt;code&gt;proto&lt;/code&gt; files that define a structure and datatypes. This would allow us to create more powerful proofs that span more than one service in a miroservice architecture. And of course, gRPC promises to be a performant protocol because it sends nearly as few bytes as possible for each message, which generally translates to speed over the network.&lt;/p&gt;

&lt;p&gt;This post documents my experience setting up an example project with rust and &lt;a href="https://github.com/hyperium/tonic"&gt;tonic&lt;/a&gt;, which is maintained by one of my coworkers, &lt;a href="https://luciofran.co/"&gt;Lucio&lt;/a&gt;. I will set up a simple server, add some other APIs and set up a second server to do health checks.&lt;/p&gt;

&lt;h1&gt;
  
  
  Set up a new cargo project
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;cargo new grpc-demo
    Created binary &lt;span class="o"&gt;(&lt;/span&gt;application&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="sb"&gt;`&lt;/span&gt;grpc-demo&lt;span class="sb"&gt;`&lt;/span&gt; package

&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;grpc-demo
&lt;span class="nv"&gt;$ &lt;/span&gt;cargo add tonic
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're used to rust, this shouldn't be difficult to follow. It's the general way that one starts a project in the rust world. You may need to install &lt;a href="https://crates.io/crates/cargo-edit"&gt;cargo-edit&lt;/a&gt; in order to have &lt;code&gt;cargo add&lt;/code&gt;, but it's well worth it for managing dependencies in your cargo project.&lt;/p&gt;

&lt;h1&gt;
  
  
  Set up a simple tonic server
&lt;/h1&gt;

&lt;p&gt;I figured I should start with the &lt;a href="https://github.com/hyperium/tonic/tree/master/examples/src/helloworld"&gt;helloworld example&lt;/a&gt; in the tonic &lt;a href="https://github.com/hyperium/tonic/tree/master/examples"&gt;examples directory&lt;/a&gt;. I started with a few more dependencies that I noticed are being used in the example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cargo add anyhow
cargo add tokio
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Later on, I realized that &lt;a href="https://docs.rs/tokio/1.4.0/tokio/#example"&gt;tokio generally wants to be added with a list of features&lt;/a&gt;, so I've adjusted the &lt;code&gt;Cargo.toml&lt;/code&gt; in my project, so that it looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[dependencies]&lt;/span&gt;
&lt;span class="py"&gt;anyhow&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"1.0.40"&lt;/span&gt;
&lt;span class="nn"&gt;tokio&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="py"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"1.4.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;features&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;["full"]&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="py"&gt;tonic&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.4.1"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Creating the protobuf files
&lt;/h1&gt;

&lt;p&gt;At this point, I was creating the proto files in my project. I've never used protobuf before, so I expected this to be one of the most challenging sections.&lt;/p&gt;

&lt;p&gt;My first instinct was to create the proto files in the &lt;code&gt;src&lt;/code&gt; folder with &lt;code&gt;the main.rs&lt;/code&gt; file.&lt;br&gt;
It ended up looking like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;syntax = "proto3";

package helloworld;

service Greeter {
    rpc SayHello (HelloRequest) returns (HelloReply);
}

message HelloRequest {
    string name = 1;
}

message HelloReply {
    string message = 1;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Learning to include the protobuf files into our &lt;code&gt;main.rs&lt;/code&gt;
&lt;/h1&gt;

&lt;p&gt;When returning to my &lt;code&gt;main.rs&lt;/code&gt;, I added&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;mod&lt;/span&gt; &lt;span class="n"&gt;hello_world&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nn"&gt;tonic&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nd"&gt;include_proto!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"helloworld"&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;But this didn't work out. My linter, &lt;a href="https://rust-analyzer.github.io/"&gt;rust-analyzer&lt;/a&gt;, gave me an error "&lt;code&gt;OUT_DIR&lt;/code&gt; not set, enable "load out dirs from check" to fix"". This had recently been a bug with rust-analyzer, but even with building with &lt;code&gt;cargo build&lt;/code&gt;, I still got "environment variable &lt;code&gt;OUT_DIR&lt;/code&gt; not defined". I knew that this had something to do with how tonic generates code for the proto files.&lt;/p&gt;

&lt;p&gt;The original message from rust-analyzer was confusing to me because I remembered turning it on, but I couldn't find it anymore. Rust-analyzer is always changing quickly, so my first instinct was that maybe they had changed the configuration recently. Looking at the issues for rust-analyzer, I found &lt;a href="https://github.com/rust-analyzer/rust-analyzer/issues/7897"&gt;one&lt;/a&gt; that said the setting had been renamed to runBuildScripts. This one happened to be on in my configuration, so I decided it might be better to look into the other error message.&lt;/p&gt;

&lt;p&gt;After googling the other error message, I noticed a few issues on Github where people had the wrong directory structure, and this seemed very likely to me because I had just guessed the directory structure when I put my proto files in &lt;code&gt;src&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Looking through the &lt;a href="https://docs.rs/tonic-build/0.4.1/tonic_build/"&gt;tonic documentation&lt;/a&gt;, it looked like I would need to compile the proto files.&lt;br&gt;
This being my first time working with generated code and deviating from the default build process for rust, I quickly realized that I'd have to create a &lt;code&gt;build.rs&lt;/code&gt; file in the project root (not &lt;code&gt;src&lt;/code&gt;), and include&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nb"&gt;Box&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;dyn&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;error&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nn"&gt;tonic_build&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;compile_protos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"proto/helloworld.proto"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;Ok&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;This also required me to &lt;code&gt;cargo add -B tonic-build&lt;/code&gt;, create a new &lt;code&gt;proto&lt;/code&gt; directory for the proto files, and move &lt;code&gt;helloworld.proto&lt;/code&gt; into that directory. With all of those changes, my code started to build.&lt;/p&gt;

&lt;p&gt;One more interesting thing I found is that normally you can't make a function in a trait async. I got the error message&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;functions in traits cannot be declared `async`
`async` trait functions are not currently supported
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;but tonic gets by this with the &lt;code&gt;#[tonic::async_trait]&lt;/code&gt; macro on the trait.&lt;/p&gt;

&lt;h1&gt;
  
  
  Finally, writing out our simple server
&lt;/h1&gt;

&lt;p&gt;From there on out, everything else was straightforward. I simply needed to create a struct that implements the hello function that you want, and start the server. My final result looked like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;hello_world&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="nn"&gt;greeter_server&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;Greeter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;GreeterServer&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;HelloReply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HelloRequest&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;net&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;SocketAddr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;tonic&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;Response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;transport&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;anyhow&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;mod&lt;/span&gt; &lt;span class="n"&gt;hello_world&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nn"&gt;tonic&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nd"&gt;include_proto!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"helloworld"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;#[derive(Default)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;MyGreeter&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="nd"&gt;#[tonic::async_trait]&lt;/span&gt;
&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Greeter&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;MyGreeter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;say_hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&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;Request&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;HelloRequest&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;result&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;HelloReply&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Status&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;reply&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HelloReply&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello {}!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="nf"&gt;.into_inner&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="p"&gt;};&lt;/span&gt;

        &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reply&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="nd"&gt;#[tokio::main]&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;SocketAddr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"127.0.0.1:8000"&lt;/span&gt;&lt;span class="nf"&gt;.parse&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;greeter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;MyGreeter&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;default&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nn"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;.add_service&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;GreeterServer&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;greeter&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="nf"&gt;.serve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;.await&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nf"&gt;Ok&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;h1&gt;
  
  
  Testing the server
&lt;/h1&gt;

&lt;p&gt;After running the server with &lt;code&gt;cargo run&lt;/code&gt;, I needed a way to test that the server works. I had heard of an interesting tool called &lt;a href="https://github.com/ktr0731/evans"&gt;evans&lt;/a&gt;, so I decided to use this.&lt;br&gt;
It took me a while to figure out the right parameters to query the server, especially because tonic doesn't seem to support gRPC reflection right now, and there are few examples out there.&lt;/p&gt;

&lt;p&gt;What ended up working for me was:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;evans --proto proto/helloworld.proto -p 8000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This was particularly confusing because there is an argument called &lt;code&gt;--path&lt;/code&gt;, which doesn't work.&lt;/p&gt;

&lt;p&gt;However, after figuring out how &lt;code&gt;evans&lt;/code&gt; works, I was able to call my service.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;helloworld.Greeter@127.0.0.1:8000&amp;gt; call SayHello
name (TYPE_STRING) =&amp;gt; "kev"
{
  "message": "Hello \"kev\"!"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It works!&lt;/p&gt;

&lt;h1&gt;
  
  
  Adding a new API
&lt;/h1&gt;

&lt;p&gt;To check my understanding, I wanted to add a new API that is like Greeter but says goodbye instead.&lt;/p&gt;

&lt;p&gt;I started with adding my new rpc and messages in the proto files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight protobuf"&gt;&lt;code&gt;&lt;span class="na"&gt;syntax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"proto3"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;helloworld&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;service&lt;/span&gt; &lt;span class="n"&gt;Greeter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;rpc&lt;/span&gt; &lt;span class="n"&gt;SayHello&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HelloRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;returns&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HelloReply&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;rpc&lt;/span&gt; &lt;span class="n"&gt;SayGoodbye&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GoodbyeRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;returns&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GoodbyeReply&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;HelloRequest&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt; &lt;span class="o"&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="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;HelloReply&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="o"&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="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;GoodbyeRequest&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt; &lt;span class="o"&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="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;GoodbyeReply&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="o"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I added a new function in &lt;code&gt;main.rs&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;hello_world&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;
    &lt;span class="nn"&gt;greeter_server&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;Greeter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;GreeterServer&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;GoodbyeReply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;GoodbyeRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HelloReply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HelloRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;net&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;SocketAddr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;tonic&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="nn"&gt;transport&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Server&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;Response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Status&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;anyhow&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;mod&lt;/span&gt; &lt;span class="n"&gt;hello_world&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nn"&gt;tonic&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nd"&gt;include_proto!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"helloworld"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;#[derive(Default)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;MyGreeter&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="nd"&gt;#[tonic::async_trait]&lt;/span&gt;
&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Greeter&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;MyGreeter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;say_hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&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;Request&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;HelloRequest&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;result&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;HelloReply&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Status&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;reply&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HelloReply&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello {}!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="nf"&gt;.into_inner&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="p"&gt;};&lt;/span&gt;

        &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;say_goodbye&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&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;Request&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;GoodbyeRequest&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;result&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;GoodbyeReply&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Status&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;reply&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GoodbyeReply&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Goodbye {}!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="nf"&gt;.into_inner&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="p"&gt;};&lt;/span&gt;
        &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reply&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="nd"&gt;#[tokio::main]&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;SocketAddr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"127.0.0.1:8000"&lt;/span&gt;&lt;span class="nf"&gt;.parse&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;greeter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;MyGreeter&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;default&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nn"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;.add_service&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;GreeterServer&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;greeter&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="nf"&gt;.serve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;.await&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nf"&gt;Ok&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;I did a sanity check with &lt;code&gt;evans&lt;/code&gt; to show that it worked:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;helloworld.Greeter@127.0.0.1:8000&amp;gt; show service
+---------+------------+----------------+---------------+
| SERVICE |    RPC     |  REQUEST TYPE  | RESPONSE TYPE |
+---------+------------+----------------+---------------+
| Greeter | SayHello   | HelloRequest   | HelloReply    |
| Greeter | SayGoodbye | GoodbyeRequest | GoodbyeReply  |
+---------+------------+----------------+---------------+

helloworld.Greeter@127.0.0.1:8000&amp;gt; call SayGoodbye
name (TYPE_STRING) =&amp;gt; kev
{
  "message": "Goodbye kev!"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Create a health-check service that runs on a second server and port.
&lt;/h1&gt;

&lt;p&gt;Once again, I started by creating a new proto file called &lt;code&gt;health.proto&lt;/code&gt; with my new HealthCheck service defined in the same &lt;code&gt;proto&lt;/code&gt; directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight protobuf"&gt;&lt;code&gt;&lt;span class="na"&gt;syntax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"proto3"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;health&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;service&lt;/span&gt; &lt;span class="n"&gt;HealthCheck&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;rpc&lt;/span&gt; &lt;span class="n"&gt;isHealthy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HealthCheckRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;returns&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HealthCheckReply&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;HealthCheckRequest&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;HealthCheckReply&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="na"&gt;isHealthy&lt;/span&gt; &lt;span class="o"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, I edited the &lt;code&gt;build.rs&lt;/code&gt; file to include this new proto file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nb"&gt;Box&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;dyn&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;error&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nn"&gt;tonic_build&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;compile_protos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"proto/helloworld.proto"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nn"&gt;tonic_build&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;compile_protos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"proto/health.proto"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;Ok&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;This time I had to &lt;code&gt;cargo add futures&lt;/code&gt; in order to import &lt;code&gt;try_join&lt;/code&gt;, but it was relatively straightforward to implement a new &lt;code&gt;HealthChecker&lt;/code&gt; struct, which just always returns true. I then set up a new server instance in &lt;code&gt;main&lt;/code&gt; and used &lt;code&gt;try_join!&lt;/code&gt; to run them both concurrently.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;healthcheck&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;
    &lt;span class="nn"&gt;health_check_server&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;HealthCheck&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HealthCheckServer&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;HealthCheckReply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HealthCheckRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;hello_world&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;
    &lt;span class="nn"&gt;greeter_server&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;Greeter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;GreeterServer&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;GoodbyeReply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;GoodbyeRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HelloReply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HelloRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;futures&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;try_join&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;net&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;SocketAddr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;tonic&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="nn"&gt;transport&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Server&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;Response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Status&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;anyhow&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;mod&lt;/span&gt; &lt;span class="n"&gt;hello_world&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nn"&gt;tonic&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nd"&gt;include_proto!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"helloworld"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;mod&lt;/span&gt; &lt;span class="n"&gt;healthcheck&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nn"&gt;tonic&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nd"&gt;include_proto!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"health"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;#[derive(Default)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;MyGreeter&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="nd"&gt;#[tonic::async_trait]&lt;/span&gt;
&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Greeter&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;MyGreeter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;say_hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&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;Request&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;HelloRequest&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;result&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;HelloReply&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Status&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;reply&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HelloReply&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello {}!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="nf"&gt;.into_inner&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="p"&gt;};&lt;/span&gt;

        &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;say_goodbye&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&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;Request&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;GoodbyeRequest&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;result&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;GoodbyeReply&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Status&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;reply&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GoodbyeReply&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Goodbye {}!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="nf"&gt;.into_inner&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="p"&gt;};&lt;/span&gt;
        &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reply&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="nd"&gt;#[derive(Default)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;HealthChecker&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="nd"&gt;#[tonic::async_trait]&lt;/span&gt;
&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;HealthCheck&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;HealthChecker&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;is_healthy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="mi"&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;Request&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;HealthCheckRequest&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;result&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;HealthCheckReply&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Status&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HealthCheckReply&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;is_healthy&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="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;#[tokio::main]&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;SocketAddr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"127.0.0.1:8000"&lt;/span&gt;&lt;span class="nf"&gt;.parse&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;greeter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;MyGreeter&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;default&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;health_addr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;SocketAddr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"127.0.0.1:9000"&lt;/span&gt;&lt;span class="nf"&gt;.parse&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;greeter_server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nn"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;.add_service&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;GreeterServer&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;greeter&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="nf"&gt;.serve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;health_server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;.add_service&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;HealthCheckServer&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;HealthChecker&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;default&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
        &lt;span class="nf"&gt;.serve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;health_addr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nd"&gt;try_join!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;greeter_server&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;health_server&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nf"&gt;Ok&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;Finally, I tested it with &lt;code&gt;evans&lt;/code&gt; again, and it showed that both services were up and running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;helloworld.Greeter@127.0.0.1:8000&amp;gt; call SayHello
name (TYPE_STRING) =&amp;gt; kev
{
  "message": "Hello kev!"
}

helloworld.Greeter@127.0.0.1:8000&amp;gt; 

health.HealthCheck@127.0.0.1:9000&amp;gt; call isHealthy
{
  "isHealthy": true
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>rust</category>
    </item>
    <item>
      <title>Setting up a static site with Hugo, Gitlab and Netlify</title>
      <dc:creator>Kevin Wu</dc:creator>
      <pubDate>Mon, 12 Apr 2021 10:11:03 +0000</pubDate>
      <link>https://dev.to/transienterror/setting-up-a-static-site-with-hugo-gitlab-and-netlify-9po</link>
      <guid>https://dev.to/transienterror/setting-up-a-static-site-with-hugo-gitlab-and-netlify-9po</guid>
      <description>&lt;p&gt;How fitting that the first post on a blog is how to essentially set one up. This is my first time using Hugo, so this post is targeting absolute beginners with experience using Unix.&lt;/p&gt;

&lt;h1&gt;
  
  
  Install Hugo
&lt;/h1&gt;

&lt;p&gt;The first thing you need to do is install the hugo CLI. I did this via Nix, but you can find the instructions for your platform on their site &lt;a href="https://gohugo.io/getting-started/installing/"&gt;https://gohugo.io/getting-started/installing/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Nix:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nix-env -i hugo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What I really liked about hugo is that it is simple to use for just writing plain markdown and builds very quickly compared to other static site generators like Gatsby or Jekyll. This really follows in the tradition of golang, which hugo is written in.&lt;/p&gt;

&lt;h1&gt;
  
  
  Set up local git repository
&lt;/h1&gt;

&lt;p&gt;Next, you can create a new static site with&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hugo new site my-site
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should create a directory called my-site and fill it with a template to get started on your site. Then inside the directory, you can create an interactive preview of your site using &lt;code&gt;hugo server&lt;/code&gt;. This hosts a local version of your site on port 1313 on &lt;code&gt;localhost&lt;/code&gt;. It was kind enough to bind the address to your &lt;code&gt;localhost&lt;/code&gt; too so only you should be able to see it. It should look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ hugo server

Start building sites … 

                   | EN  
-------------------+-----
  Pages            | 10  
  Paginator pages  |  0  
  Non-page files   |  0  
  Static files     |  1  
  Processed images |  0  
  Aliases          |  2  
  Sitemaps         |  1  
  Cleaned          |  0  

Built in 54 ms
Watching for changes in /Users/kvwu/workspace/kvwu-blog/{archetypes,content,themes}
Watching for config changes in /Users/kvwu/workspace/kvwu-blog/config.toml
Environment: "development"
Serving pages from memory
Running in Fast Render Mode. For full rebuilds on change: hugo server --disableFastRender
Web Server is available at http://localhost:1313/ (bind address 127.0.0.1)
Press Ctrl+C to stop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice how fast it builds! 54ms is quite good. This is really good for a personal blog where I don't want to waste a lot of time watching the build process run.&lt;/p&gt;

&lt;p&gt;You can initialize git at this point in the &lt;code&gt;my-site&lt;/code&gt; directory with &lt;code&gt;git init&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The next thing that I did was set up a nice theme. You can find a lot of great themes available at &lt;a href="https://themes.gohugo.io/"&gt;https://themes.gohugo.io/&lt;/a&gt;. I just found one that I liked and added it as a submodule of my new site repository.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git submodule add $THEME_URL themes/$THEME_NAME
# For example for my theme
git submodule add https://github.com/vaga/hugo-theme-m10c.git themes/m10c
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This copies the repository at the &lt;code&gt;$THEME_URL&lt;/code&gt; in the themes directory, and should have added &lt;code&gt;themes/$THEME_NAME&lt;/code&gt; to staging. You can take a look at the theme by adding &lt;code&gt;theme = $THEME_NAME&lt;/code&gt; to your &lt;code&gt;config.toml&lt;/code&gt; and looking at &lt;code&gt;http://localhost:1313/&lt;/code&gt;, and if it looks good to you, commit these changes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git commit -m 'add theme'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I also found it useful to edit some other information in &lt;code&gt;config.toml&lt;/code&gt;.&lt;br&gt;
I changed the &lt;code&gt;author&lt;/code&gt; and &lt;code&gt;params.description&lt;/code&gt; to better fit my needs. These changed the values on the sidebar for my theme. I suppose you could play around and find which configurations change your page.&lt;/p&gt;
&lt;h1&gt;
  
  
  Set up Gitlab remote repository
&lt;/h1&gt;

&lt;p&gt;Gitlab is a site that allows you to host a git repository online. You could also use Github, but I used Gitlab, so my instructions will be for that.&lt;/p&gt;

&lt;p&gt;As far as I know, there isn't a great way to set up a remote repository on Gitlab through CLI, and it's not easy to describe how to use their website with words. Their instructions on how to do this can be found here &lt;a href="https://docs.gitlab.com/ee/user/project/working_with_projects.html#create-a-project"&gt;https://docs.gitlab.com/ee/user/project/working_with_projects.html#create-a-project&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once you have set up a remote repository, you can add your local repository to it&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git remote add origin git@github.com:username/projectpath.git
git push
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Set up Netlify
&lt;/h1&gt;

&lt;p&gt;Netlify is a service that will host your site for you. This particular section suffers from the same problem as the Gitlab one. Netlify does have a cli, but I used their web UI. However, luckily for us, Netlify provides really detailed instructions on their site for how to host your site: &lt;a href="https://gohugo.io/hosting-and-deployment/hosting-on-netlify/"&gt;https://gohugo.io/hosting-and-deployment/hosting-on-netlify/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The tutorial, at least at time of writing, shows how to set up using Github but it's pretty easy to set up with Gitlab as well by just clicking Gitlab instead of Github when prompted.&lt;/p&gt;

&lt;p&gt;When prompted to select your repo, select the repo you just created and your master branch. This will create a hook so that whenever you push your master branch, you will deploy a new version of the website. &lt;/p&gt;

&lt;p&gt;One issue that I encountered with the compatibility was that my theme required at least hugo 0.55, but Netlify was using 0.54 by default. In this case you can create a &lt;code&gt;netlify.toml&lt;/code&gt; file e.g.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[context.production.environment]
HUGO_VERSION = "0.81.0"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to specify your hugo version. I chose 0.81 because that was the version that I had installed, which I think should lead to the most consistent experience. You can find out which version you're using by running &lt;code&gt;hugo version&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>netlify</category>
    </item>
  </channel>
</rss>
