Microsoft's distributed application framework Dapr Helloworld

Dapr HelloWorld

<a name="XMoC2"></a>

Dapr

Distributed Application Runtime. An event-driven, portable runtime for building microservices on cloud and edge.

Distributed application runtime, event driven, and portable runtime for cloud and edge microservices.

I don't know much now.

<a name="MCBci"></a>

dapr/dapr

GitHub

Dapr is a portable, serverless, event-driven runtime that makes it easy for developers to build resilient, stateless and stateful microservices that run on the cloud and edge and embraces the diversity of languages and developer frameworks.

Dapr codifies the best practices for building microservice applications into open, independent, building blocks that enable you to build portable applications with the language and framework of your choice. Each building block is independent and you can use one, some, or all of them in your application.

There are more labels for stateless or stateful than described above. I've been exposed to some state machines when I was studying computational theory.

”State is the source of all evils

Note that multi language and multi developer framework are mentioned. I think it is his choice to share information through communication, that is, HTTP and GRPC support multi language features. Microsoft wants to set a rule for building microservice applications. Fundamentally establish the independence of each application you develop.

Here's a QuickStart

<a name="BuQMg"></a>

Environmental Science

  1. Install Docker (microservices cannot be separated from containerization.)
  2. Install Dapr
  3. Node.js version 8 or greater (this Helloworld is a node application)

<a name="9Pq3v"></a>

On MacOS

Install the latest darwin Dapr CLI to /usr/local/bin

curl -fsSL https://raw.githubusercontent.com/dapr/cli/master/install/install.sh | /bin/bash

Conditional acceleration

Perform initialization (the docker container will be started)

$ dapr init
⌛  Making the jump to hyperspace...
Downloading binaries and setting up components
✅  Success! Dapr is up and running

$ docker ps
CONTAINER ID        IMAGE                COMMAND                  CREATED             STATUS              PORTS                        NAMES
b3a5600e672f        redis                "docker-entrypoint.s..."   44 hours ago        Up 44 hours         0.0.0.0:6379->6379/tcp       xenodochial_hofstadter
e5010ba0c33f        daprio/dapr          "./placement"            44 hours ago        Up 44 hours         0.0.0.0:50005->50005/tcp     dapr_placement

<a name="qGzU3"></a>

HelloWorld

<a name="s5AAY"></a>

Application Architecture

< br / > you can see that two endpoint s are exposed as HTTP access, one for creating a query.

Mainly depends on our interaction with Dapr. In the diagram, it serves as the Runtime

  • Provides the Dapr API for multi language calls.
  • Provide status management By state stores

<a name="Szu0t"></a>

Download Code

Download and enter the corresponding folder

git clone https://github.com/dapr/samples.git
cd samples/1.hello-world

<a name="nsc6T"></a>

Cat app.js

// $ cat app.js 
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
// ------------------------------------------------------------

const express = require('express');
const bodyParser = require('body-parser');
require('isomorphic-fetch');

const app = express();
app.use(bodyParser.json());

const daprPort = process.env.DAPR_HTTP_PORT || 3500;
const stateUrl = `http://localhost:${daprPort}/v1.0/state`;
const port = 3000;

app.get('/order', (_req, res) => {
    fetch(`${stateUrl}/order`)
        .then((response) => {
            return response.json();
        }).then((orders) => {
            res.send(orders);
        });
});

app.post('/neworder', (req, res) => {
    const data = req.body.data;
    const orderId = data.orderId;
    console.log("Got a new order! Order ID: " + orderId);

    const state = [{
        key: "order",
        value: data
    }];

    fetch(stateUrl, {
        method: "POST",
        body: JSON.stringify(state),
        headers: {
            "Content-Type": "application/json"
        }
    }).then((response) => {
        console.log((response.ok) ? "Successfully persisted state" : "Failed to persist state");
    });

    res.status(200).send();
});

app.listen(port, () => console.log(`Node App listening on port ${port}!`));

Here are some routes and handlers

Note lines 14-16

const daprPort = process.env.DAPR_HTTP_PORT || 3500;
const stateUrl = `http://localhost:${daprPort}/v1.0/state`;
const port = 3000;

3500 is the environment port of Dapr. If you change it during installation, you need to consider it. < br / > stateurl is the URL provided by Dapr

<a name="zjdNP"></a>

Handlers

<a name="iWwkd"></a>

/neworder
app.post('/neworder', (req, res) => {
    const data = req.body.data;
    const orderId = data.orderId;
    console.log("Got a new order! Order ID: " + orderId);

    const state = [{
        key: "order",
        value: data
    }];

    fetch(stateUrl, {
        method: "POST",
        body: JSON.stringify(state),
        headers: {
            "Content-Type": "application/json"
        }
    }).then((response) => {
        console.log((response.ok) ? "Successfully persisted state" : "Failed to persist state");
    });

    res.status(200).send();
});

The focus here is on state storage, that is, state is stored in Dapr through stateurl.

<a name="IaPwp"></a>

/order

We do not use the persistent data directly through res.json as Response, but through exposing a GET endpoint to verify whether the persistence is successful by accessing it.

app.get('/order', (_req, res) => {
    fetch(`${stateUrl}/order`)
        .then((response) => {
            return response.json();
        }).then((orders) => {
            res.send(orders);
        });
});

Now we have implemented stateless in Dapr through state transition. Similarly, we can add a local cache and make Node application stateful through a new endpoint access

<a name="6NX8n"></a>

Dapr Run Node.js App

  1. npm install: through package.json in the current directory, express and body parser will be installed. We can see these two items in line 7-8 of app.js.
  2. dapr run --app-id mynode --app-port 3000 --port 3500 node app.js
$ dapr run --app-id mynode --app-port 3000 --port 3500 node app.js
ℹ️  Starting Dapr with id mynode. HTTP Port: 3500. gRPC Port: 55099
✅  You're up and running! Both Dapr and your app logs will appear here.

There should be CLI commands running in the background. Here is the log of foreground printing.

== DAPR == time="2019-11-06T10:37:41+08:00" level=info msg="starting Dapr Runtime -- version 0.1.0 -- commit 4358565-dirty"
== DAPR == time="2019-11-06T10:37:41+08:00" level=info msg="log level set to: info"
== DAPR == time="2019-11-06T10:37:41+08:00" level=info msg="standalone mode configured"
== DAPR == time="2019-11-06T10:37:41+08:00" level=info msg="dapr id: mynode"
== DAPR == time="2019-11-06T10:37:41+08:00" level=info msg="loaded component messagebus (pubsub.redis)"
== DAPR == time="2019-11-06T10:37:41+08:00" level=info msg="loaded component statestore (state.redis)"
== DAPR == time="2019-11-06T10:37:41+08:00" level=info msg="application protocol: http. waiting on port 3000"
== APP == Node App listening on port 3000!
== DAPR == time="2019-11-06T10:37:42+08:00" level=info msg="application discovered on port 3000"
== DAPR == 2019/11/06 10:37:42 redis: connecting to localhost:6379
== DAPR == 2019/11/06 10:37:42 redis: connected to localhost:6379 (localAddr: [::1]:55130, remAddr: [::1]:6379)
== DAPR == time="2019-11-06T10:37:42+08:00" level=info msg="actor runtime started. actor idle timeout: 1h0m0s. actor scan interval: 30s"
== DAPR == time="2019-11-06T10:37:42+08:00" level=info msg="actors: starting connection attempt to placement service at localhost:50005"
== DAPR == time="2019-11-06T10:37:42+08:00" level=info msg="http server is running on port 3500"
== DAPR == time="2019-11-06T10:37:42+08:00" level=info msg="gRPC server is running on port 55099"
== DAPR == time="2019-11-06T10:37:42+08:00" level=info msg="local service entry announced"
== DAPR == time="2019-11-06T10:37:42+08:00" level=info msg="dapr initialized. Status: Running. Init Elapsed 945.8297490000001ms"
== DAPR == time="2019-11-06T10:37:42+08:00" level=info msg="actors: established connection to placement service at localhost:50005"
== DAPR == time="2019-11-06T10:37:42+08:00" level=info msg="actors: placement order received: lock"
== DAPR == time="2019-11-06T10:37:42+08:00" level=info msg="actors: placement order received: update"
== DAPR == time="2019-11-06T10:37:42+08:00" level=info msg="actors: placement tables updated"
== DAPR == time="2019-11-06T10:37:42+08:00" level=info msg="actors: placement order received: unlock"

⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠

<a name="4c61x"></a>

Post and Get

Next, note that the port in this article is the default 3500 in app.js <a name="B0eiO"></a>

Post

<a name="zK8en"></a>

Curl
curl -XPOST -d @sample.json http://localhost:3500/v1.0/invoke/mynode/method/neworder

<a name="4JeyP"></a>

Vscode

If you use vscode, use this plugin Rest Client Plugin < br / > then open sample.http in the directory, and you can see the option of send request < br / > sample.http 

POST http://localhost:3500/v1.0/invoke/mynode/method/neworder
{
  "data": {
    "orderId": "42"
  } 
}

<a name="b0mVa"></a>

Postman

As shown in the figure: "http://localhost:3500/v1.0/invoke/mynode/method/neworder"

<a name="iMLzt"></a>

Result Update

You can see the new log in the terminal you started

== APP == Got a new order! Order ID: 42
== APP == Successfully persisted state

<a name="VFOMe"></a>

Get

<a name="zYZpd"></a>

Curl
curl http://localhost:3500/v1.0/invoke/mynode/method/order

<a name="RiAVm"></a>

Vscode

sample.http

GET http://localhost:3500/v1.0/invoke/mynode/method/order

<a name="oi8De"></a>

Postman

<a name="sOJNZ"></a>

Terminate

ctrl + c or dapr stop -- app ID mynode

^C
ℹ️  terminated signal received: shutting down
✅  Exited Dapr successfully
✅  Exited App successfully

<a name="sojfC"></a>

Feature

  • Event driven pub sub system with pluggable provider and at least one semantics
  • Use input and output bindings for pluggable providers
  • State management with pluggable data storage
  • Consistent service to service discovery and invocation
  • Select join state model: strong / final consistency, first write / last write wins
  • Cross platform virtual actor
  • Speed limit
  • Built in distributed tracing using OpenTelemetry
  • Run locally on Kubernetes using dedicated operators and CRD s
  • Support all programming languages through HTTP and gRPC
  • Multi cloud, open components from Azure, AWS, GCP (binding, publish subscribe, status)
  • Run anywhere as a process or containerization
  • Lightweight (58MB binary, 4MB physical memory)
  • Run as a helper - no special SDK or library required
  • Dedicated CLI easy to debug developer friendly experience
  • Clients of Java, Dotnet, Go, Javascript and Python

<a name="lMDgW"></a>

Refer

Tags: Programming JSON github curl Redis

Posted on Wed, 06 Nov 2019 06:50:22 -0500 by reneeshtk