Speedrun Merrymake

This guide is intended to get your code running in Merrymake as fast as possible. So let's jump straight into it.

Install the CLI

First we need to install the CommandLine Interface (CLI) with the command:

$ npm install --global @merrymake/cli

Quickstart a project

We can now use the CLI to automatically setup a user account, with a service ready to deploy. We only need to specify which programming language we prefer then watch the magic:

$ mm quickstart
> [p] python
  [#] c#
  [r] rust
  [t] typescript
  [¤] javascript

Take note of the key it gives us as it will be important later. Then simply run the command it gives us, to navigate to the new service:

$ cd [org]/services/Merrymake

Deploy the service

We can deploy the service with a Git push or with the command:

$ mm deploy

Trigger the service

In order to trigger a service we need a key, fortunately quickstart gave us one to use:

$ curl --silent \
    --header "Content-Type: text/plain" \
    --data "World" \
    https://rapids.merrymake.io/[key]/hello

We have now learned how to deploy and execute code with Merrymake. This is sufficient to start playing around. The rest of the tutorial covers advanced topics such as system maintenance, setting up proper security, and integrations.

Get Properly Introduced

While quickstart is great for playing around, it does not support production level software. To demonstrate how to work with Merrymake professionally we are going to build an uptime detector. Before we get started on that we need to master the CLI itself.

Master the CLI

We at Merrymake have spent a lot of effort making the CLI as easy to use as possible, therefore it is different from usual CLI's in a few important areas:

Context sensitivity

The Merrymake-CLI looks at which folder we are in, and presents only options relevant to that context. For example we cannot create an organization inside another organization. If you are missing an option, verify that you are in the correct folder to perform that action.

Preselecting options

Every option in the CLI has a unique word, highlighted with yellow. This name can be used as a commandline argument to preselect that option skipping the choice. In the example from earlier, mm quickstart presented a choice of languages, if we were to call it again we can skip this choice by adding the language as a commandline argument:

$ mm quickstart typescript

For text prompts we can preselect the default options by using underscore (_) as the commandline argument.

Shorthand preselection

Most options in the CLI also have brackets with a character inside it, this character can be used as a shorthand when preselecting this option, by prefixing it with a dash (-). Using shorthand looks like this:

$ mm quickstart -t

It is possible to chain shorthands, combining -b -t into -bt. Note that not all options have a shorthand version, such as the command quickstart itself.

Help for text input

When you are asked to type in text you can press escape to display a help-text. For example when we hit escape while setting up a cron job:

$ mm cron new event event
Cron expression (optional): |
Eg. every 5 minutes is '*/5 * * * *'

Dryrun

The final CLI feature we want to mention is the dryrun mode. This mode lets us navigate through the CLI without making changes to our project, which is very helpful when building commands to use as part some automation, or if we're just curious about what lies behind an option. ;-)

$ mm dryrun org

Register a device

To work with Merrymake we need to register the device and tie it to a user account. The CLI sends all commands securely via ssh, which is like a fingerprint for your computer. quickstart automatically set up an ssh key for you, and configured it for Merrymake, however it did not tie an email to the account.

Accounts with no emails attached get's automatically deleted after a while without notice -- since we have no email to notify. We can prevent this by adding an email to our account, then we'll be notified if our account is in danger of being archived. Adding an email also lets us register multiple ssh keys (ie. multiple devices) to the same account.

$ mm register merrymake
If you're a security samurai like cofounder Nicolaj, and would like to use a password protected ssh key, you need to unlock it before you can use it with the CLI.
$ eval `ssh-agent`
$ ssh-add [file]

Create an organization

After registering our device, it is time to start building our uptime detector. The first step is to create an organization for it. An organization consists of service groups, loosely corresponding to teams, with repos (aka services) inside them. When we setup a new organization we also have to name the first service group and repo.

$ mm org [name] services alpha basic
Cloning [name]...
Creating service group...
Creating service...
Fetching template...
Use 'cd [name]\\services\\alpha' to go to the new service.
Then use 'mm deploy' to deploy it.

In addition to service groups, each organization also has one central message queue called the rapids and one event-catalogue which we'll cover in depth later.

For now, let's follow the instructions from the CLI and go to the new service:

$ cd [org]/services/alpha

Deploy with Git

In the speedrun, we saw that mm deploy can deploy a service to the platform. Behind the scene deployment happens through Git. Thus, we can work with services exclusively through Git if we prefer. Using Git directly is recommended if multiple developers are collaborating the service, because then we can control the commit messages. To deploy a service with Git, we simply commit our changes as normal and then push the main branch. Since we selected a template we are ready to push:

$ git push origin main
[some git stuff]
remote: 88.     .88                                                88
remote: 888.   .888                                                88
remote: 88Y8. .8P88                                                88
remote: 88 Y8o8P 88  .88.  88.d8 88.d8 Yb     dP 8888bd88b   .88.8 88  .8P .88.
remote: 88  Y8P  88 d"  "b 88"   88"    Yb   dP  88 '88 '8b d"  "8 88 .8P d"  "b
remote: 88   "   88 888888 88    88      Yb dP   88  88  88 8    8 88d8P  888888
remote: 88       88 Y.     88    88       Y8P    88  88  88 Y.  .8 88" 8b Y.
remote: 88       88  "88P  88    88       dP     88  88  88  "88"8 88  "8b "88P
remote:                                  dP
remote: Cloning repository...
remote: Detecting project type...
remote: Scheduling typescript build...
remote: [Build output]
remote: Build completed...
remote: Registering service...
remote: Deploying service...
remote: Queueing smoke test...
remote: Service 'Merrymake' will be released if/when the smoke test succeeds.

From this output we can see that Merrymake builds, packages, and deploys our service automatically. This is pretty normal for a continuous deployment pipeline. What is unique is the 'smoke test'. In Merrymake, before a service is allowed to handle traffic is started once, to ensure there are no critical errors in the configuration. We'll return to the smoke test later.

We can check if our smoke test went through we can inspect the rapids, this displays all events that have gone through our system:

$ mm queue
      Id     │ River        │ Event        │ Status  │ Queue time
      -------┼--------------┼--------------┼---------┼----------------------
> [_] 192554 │         init │              │ success │ 23/11/2023, 14.44.23

Smoke tests are unique in that they have an empty Event. As we can see, the smoke test succeeded so the service is now live. If we want more details about an event, such as its console output we can drill down into it:

$ mm queue 192554 init
{
  messageId: '192554c1-ff81-435a-8bc0-35eb522b26d0',
  startedOn: '2023-11-23T13:44:23.577Z',
  finishedOn: '2023-11-23T13:44:23.636Z',
  result: 'success'
}
Output:

This becomes more useful when our services print something. Let's proceed so we can get to trigger it!

Create an api-key

Services are trigged by events coming indirectly from the rapids. The rapids -- and thus the organization -- is isolated from the outside by a virtual wall. To allow events from the outside we need an api-key or key for short. In Merrymake, all keys are temporary, to prevent old keys accidentally becoming security vulnerabilities. When creating a key we can specify a human readable description, which is highly encouraged, to help distinguish keys from each other. Let's create a new key for admin use lasting 14 days:

$ mm key new admin "14 days"

New keys are created as master keys, therefore like services they can post any event to the rapids. Later we'll look at how to limit this by whitelist events for api-keys.

Trigger a service with code

In the speedrun we triggered the code from curl, but in our uptime detector we would like a little more convenience. Let's create an admin portal where we can easily send events to our rapids. We create a file on our desktop called admin.html, and populate it with:

<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Admin portal</title>
  </head>
  
  <body>
    <input type="text" id="event-type" />
    <button id="button">Post to Rapids</button>
    <pre id="response"></pre>
    <script>
      let respElem = document.getElementById("response");
      let textElem = document.getElementById("event-type");
      let button = document.getElementById("button");
      function loadDoc(url, method, body, resolve) {
        const xhttp = new XMLHttpRequest();
        xhttp.onload = function () {
          if (this.readyState === 4) {
            respElem.innerText = (this.responseText);
          }
        }
        xhttp.open(method, url, true);
        respElem.innerText = "Waiting...";
        xhttp.send(JSON.stringify(body));
      }
      button.addEventListener("click", (e) => {
        loadDoc(
          `https://rapids.merrymake.io/[key]/${textElem.value}`, 
          "GET", 
          "", 
          (resp) => console.log(resp));
      });
    </script>
  </body>
</html>

Remember to replace [key] with your api-key from the previous section.

Try it out by opening the file in a browser and posting a hello event. The output should say:

Hello, {}!

It looks a bit odd because the service we deployed expects a payload, which our admin portal currently don't support. The important thing is that we have verified that we can deploy and trigger services, so now it is time to start building the actual uptime detector.

Other interesting bits

Disable an api-key

To disable a key we set its duration to 0 seconds:

$ mm key [key] _ '0s'