A template project to demonstrate how to run WebAssembly functions as sidecar microservices in dapr

Overview

Live Demo

1. Introduction

DAPR is a portable, event-driven runtime that makes it easy for any developer to build resilient, stateless and stateful applications that run on the cloud and edge and embraces the diversity of languages and developer frameworks. It's a Microsoft-incubated open-source project.

WasmEdge is a open-source, high-performance, extensible, and hardware optimized WebAssembly Virtual Machine for automotive, cloud, AI, and blockchain applications.

In this demonstration App, we create two image processing web services, integrated with Dapr. This project is built to demonstrate how to use Dapr to integrate Web applications in any programming language, and how WasmEdge can be embed in Go and Rust applications.

2. Architecture

This project contains mainly three components:

It is a simple Go Web application which is exposed as an endpoint of the whole application. It will render a static HTML page for the user to upload an image, and receive the image from the user, redirect request to internal image APIs.

This Dapr service is written in Golang. It uses WASI to call a prebuild wasm file to classify an image using a Tensorflow model.

This Dapr service is written in Rust. It simply starts a new process for the WasmEdge VM to run and perform grayscale on a image.

doc

3. Prerequisites

4. Build

make pre-install  ## Install WasmEdge dependences
make build        ## Will build all the components

## If you modify the wasm functions project,
## Use the commands in ./functions/grayscale/build.sh 
## and ./functions/classify/build.sh to generate new compiled files
make build-wasm

5. Run

To simplify the deployment, we provide a script to run the services:

make run-api-go ## Run the image-api-go
make run-api-rs ## Run the image-api-rs
make run-web ## Run the Web port service

For each component, you can also run it individually:

Start the web-port service

cd web-port
dapr run --app-id go-web-port \
         --app-protocol http \
         --app-port 8080 \
         --dapr-http-port 3500 \
         --components-path ../config \
         --log-level debug \
         ./web-port

Start the image-api-go service

cd image-api-go
dapr run --app-id image-api-go \
         --app-protocol http \
         --app-port 9003 \
         --dapr-http-port 3501 \
         --log-level debug \
         --components-path ../config \
         ./image-api-go

Start the image-api-rust service

cd image-api-rs
dapr run --app-id image-api-rs \
         --app-protocol http \
         --app-port 9004 \
         --dapr-http-port 3502 \
         --components-path ../config \
         --log-level debug \
         ./target/debug/image-api-rs

After all the services started, we can use this command to verify:

dapr list
  APP ID        HTTP PORT  GRPC PORT  APP PORT  COMMAND               AGE  CREATED              PID
  go-web-port   3500       44483      8080      ./web-port            15m  2021-08-26 12:19.59  270961
  image-api-rs  3502       41661      9004      ./target/release/...  9m   2021-08-26 12:25.27  285749
  image-api-go  3501       34291      9003      ./image-api-go        9m   2021-08-26 12:25.27  285852

6. Online Demo: Dapr-WasmEdge

7. Appendix: an introduction to Dapr SDK

Dapr provides SDKs for different programming languages. Using the SDKs is the easiest way to run your applications in Dapr.

The SDK contains Client, Service, and Runtime API, and it is easy to use. For example, we use Service SDK in go-sdk to create the image-api-go service

func main() {
	s := daprd.NewService(":9003")

	if err := s.AddServiceInvocationHandler("/api/image", imageHandlerWASI); err != nil {
		log.Fatalf("error adding invocation handler: %v", err)
	}

	if err := s.Start(); err != nil && err != http.ErrServerClosed {
		log.Fatalf("error listenning: %v", err)
	}
}

In web-port/web_port.go, we use Dapr's Client to send request to Service:

func daprClientSend(image []byte, w http.ResponseWriter) {
	ctx := context.Background()

	// create the client
	client, err := dapr.NewClient()
	if err != nil {
		panic(err)
	}

	content := &dapr.DataContent{
		ContentType: "text/plain",
		Data:        image,
	}

	resp, err := client.InvokeMethodWithContent(ctx, "image-api-go", "/api/image", "post", content)
	if err != nil {
		panic(err)
	}
	log.Printf("dapr-wasmedge-go method api/image has invoked, response: %s", string(resp))
	fmt.Printf("Image classify result: %q\n", resp)
	w.WriteHeader(http.StatusOK)
	fmt.Fprintf(w, "%s", string(resp))
}

For any Web Service which don't use Dapr SDK but registered as a Dapr instance, we can still can use http or gRpc to interact with it. Dapr will start a sidecar for each service instance. Essentially, sidecar works as a proxy for a service instance. We send request to sidecar, then the request is forwarded to the service instance. For example, in web-port/web_port.go we send a request to Rust api like this(3502 is the port of Sidecar):

client := &http.Client{}
	// http://localhost:<daprPort>/v1.0/invoke/<appId>/method/<method-name>
	req, err := http.NewRequest("POST", "http://localhost:3502/v1.0/invoke/image-api-rs/method/api/image", bytes.NewBuffer(image))
	if err != nil {
		panic(err)
	}
	req.Header.Set("Content-Type", "text/plain")
	resp, _ := client.Do(req)
	defer resp.Body.Close()
	body, _ := ioutil.ReadAll(resp.Body)
	fmt.Fprintf(w, "%s", body)
Issues
  • It seems that memory leak occurs when image-api-go is called.

    It seems that memory leak occurs when image-api-go is called.

    I replace the web-port imageHandler func with the following code, to make it easier to observe(making more requests on one click). The memory usage of image-api-go is keeping growing when click classify.

    type mock struct {}
    
    func (m *mock)WriteHeader(statusCode int) {
    }
    
    func (m *mock)Header() http.Header {
    	return nil
    }
    func (m *mock)Write(b []byte) (int, error) {
    	return len(b), nil
    }
    
    func imageHandler(w http.ResponseWriter, r *http.Request) {
    	println("imageHandler ....")
    	body, err := ioutil.ReadAll(r.Body)
    
    	if err != nil {
    		println("error: ", err.Error())
    		panic(err)
    	}
    	api := r.Header.Get("api")
    	if api == "go" {
    		daprClientSend(body, w)
    		for i:=0;i<10;i++ {
    			go func() {
    				for i:=0;i<10;i++ {
    					daprClientSend(body, &mock{})
    				}
    			}()
    		}
    	} else {
    		httpClientSend(body, w)
    	}
    }
    
    opened by Taction 6
  • Use wasmedge-bindgen instead of wasm-bindgen in the GO SDK example

    Use wasmedge-bindgen instead of wasm-bindgen in the GO SDK example

    The current example uses wasm-bindgen to pass call parameters from the GO app to the WASM function. However, wasm-bindgen does not work with the Rust WASI target since Rust version 1.51. We now have a better solution for bindgen since WasmEdge 0.9.0. It is called wasmedge-bindgen:

    https://wasmedge.org/book/en/embed/go/function.html

    Can we refactor the GO host example to use wasmedge-bindgen?

    opened by juntao 5
  • update wasmedge_wasi_socket version to 0.2.0

    update wasmedge_wasi_socket version to 0.2.0

    reoslve Mismatched function type. Expected: FuncType {params{i32 , i32 , i32} returns{i32}} , Got: FuncType {params{i32 , i32} returns{i32}} issue: #25

    opened by marviniter 1
  • Seems the wasm file is missed

    Seems the wasm file is missed

    https://github.com/second-state/dapr-wasm/blob/main/image-api-go/image_api.go#L50 The resource loaded seems not exist. Besides would you mind provide the code before compiling into wasm?

    opened by Taction 1
  • make run-api-wasi-socket-rs error with  Mismatched function type

    make run-api-wasi-socket-rs error with Mismatched function type

    make run-api-wasi-socket-rs error log:

    == APP == [2021-12-29 11:44:31.136] [error] instantiation failed: incompatible import type, Code: 0x61
    == APP == [2021-12-29 11:44:31.136] [error]     Mismatched function type. Expected: FuncType {params{i32 , i32 , i32} returns{i32}} , Got: FuncType {params{i32 , i32} returns{i32}}
    == APP == [2021-12-29 11:44:31.136] [error]     When linking module: "wasi_snapshot_preview1" , function name: "sock_accept"
    == APP == [2021-12-29 11:44:31.136] [error]     At AST node: import description
    == APP == [2021-12-29 11:44:31.136] [error]     At AST node: import section
    == APP == [2021-12-29 11:44:31.136] [error]     At AST node: module
    
    opened by marviniter 0
  • Create a customized WasmEdge for dapr

    Create a customized WasmEdge for dapr

    The WasmEdge GO SDK allows developers to register host functions to the runtime, and create a customized version of WasmEdge that includes the host functions.

    We should add Dapr GO SDK functions into a customized version of WasmEdge.

    We should then create Rust APIs for those Dapr host functions so that WasmEdge app developers can use them.

    opened by juntao 3
  • Create WasmEdge HTTP server sidecars

    Create WasmEdge HTTP server sidecars

    We would like to create two sidecars that are just wasmedge or wasmedge-tensorflow-lite. Instead of using GO or Rust to implement HTTP servers and then bootstrap wasmedge, we would just run those wasmedge-based server apps in sidecars.

    Sidecar #1: implement the grayscale function in Rust.

    https://github.com/second-state/wasmedge_wasi_socket/tree/main/examples/http_server

    Sidecar #2: implement the tensorflow function in JS

    https://github.com/second-state/wasmedge-quickjs#http-request

    https://github.com/second-state/wasmedge-quickjs#tensorflow

    https://www.secondstate.io/articles/embed-javascript-in-rust/

    After that, modify the web port to show all 4 sidecar apps.

    opened by juntao 15
  • Error: error getting topics from app - unexpected end of JSON input - error occurred while beginning pubsub messages

    Error: error getting topics from app - unexpected end of JSON input - error occurred while beginning pubsub messages

    Hi,

    I am performing the grayscale tutorial example i.e. make run-api-rs the following error is occurring.

    ERRO[0000] error getting topics from app: unexpected end of JSON input  app_id=image-api-rs instance=wasm-oci-demo scope=dapr.runtime type=log ver=1.4.2
    ERRO[0000] error occurred while beginning pubsub messages: error getting topics from app: unexpected end of JSON input  app_id=image-api-rs instance=wasm-oci-demo scope=dapr.runtime type=log ver=1.4.2
    INFO[0000] dapr initialized. Status: Running. Init Elapsed 9.416037000000001ms  app_id=image-api-rs instance=wasm-oci-demo scope=dapr.runtime type=log ver=1.4.2
    

    The following video (which starts just as the error occurs) demonstrates the above error in action.

    https://youtu.be/A5EhO7cNTCw?t=392

    It seems that dapr list is displaying the correct output (in terms of apps, ports etc.)

    [email protected]:~$ dapr list
      APP ID        HTTP PORT  GRPC PORT  APP PORT  COMMAND               AGE  CREATED              PID     
      go-web-port   3500       40659      8080      ./web-port            36s  2021-10-05 02:38.25  334410  
      image-api-rs  3502       34493      9004      ./target/debug/im...  23s  2021-10-05 02:38.38  334530  
      image-api-go  3501       40639      9003      ./image-api-go        9s   2021-10-05 02:38.52  334658 
    

    Is it possible that the grayscale needs to be added to the config i.e. https://github.com/second-state/dapr-wasm/blob/main/config/conf.json

    Any suggestions would be greatly appreciated.

    Thanks Tim

    opened by tpmccallum 2
Owner
Second State
Fast, safe, portable & serverless. Deploy Rust functions in edge computing, Jamstack, SaaS and service mesh applications.
Second State
WebAssembly interop between Go and JS values.

vert Package vert provides WebAssembly interop between Go and JS values. Install GOOS=js GOARCH=wasm go get github.com/norunners/vert Examples Hello W

null 76 Aug 12, 2022
WebAssembly for Proxies (Golang host implementation)

WebAssembly for Proxies (GoLang host implementation) The GoLang implementation for proxy-wasm, enabling developer to run proxy-wasm extensions in Go.

MOSN 37 May 28, 2022
πŸΉπŸ•ΈοΈ WebAssembly runtime for Go

Wasmer Go Website β€’ Docs β€’ Slack Channel A complete and mature WebAssembly runtime for Go based on Wasmer. Features Easy to use: The wasmer API mimics

Wasmer 2.1k Aug 8, 2022
πŸΉπŸ•ΈοΈ WebAssembly runtime for Go

Wasmer Go Website β€’ Docs β€’ Slack Channel A complete and mature WebAssembly runtime for Go based on Wasmer. Features Easy to use: The wasmer API mimics

Wasmer 2.1k Aug 12, 2022
Golang-WASM provides a simple idiomatic, and comprehensive API and bindings for working with WebAssembly for Go and JavaScript developers

A bridge and bindings for JS DOM API with Go WebAssembly. Written by Team Ortix - Hamza Ali and Chan Wen Xu. GOOS=js GOARCH=wasm go get -u github.com/

TeamOrtix 74 Jul 15, 2022
A package to build progressive web apps with Go programming language and WebAssembly.

Go-app is a package for building progressive web apps (PWA) with the Go programming language (Golang) and WebAssembly (Wasm). Shaping a UI is done by

Maxence Charriere 6.4k Aug 14, 2022
A package to build progressive web apps with Go programming language and WebAssembly.

Go-app is a package for building progressive web apps (PWA) with the Go programming language (Golang) and WebAssembly (Wasm). Shaping a UI is done by

Maxence Charriere 6.4k Aug 8, 2022
Vugu: A modern UI library for Go+WebAssembly (experimental)

Vugu: A modern UI library for Go+WebAssembly (experimental)

Vugu 4.4k Aug 4, 2022
WebAssembly runtime for wasmer-go

gowasmer When compiling Go to WebAssembly, the Go compiler assumes the WebAssembly is going to run in a JavaScript environment. Hence a wasm_exec.js f

mattn 91 Jul 28, 2022
Tiny, blazing fast WebAssembly compute

Sat, the tiny WebAssembly compute module Sat (as in satellite) is an experiment, and isn't ready for production use. Please try it out and give feedba

Suborbital 289 Aug 7, 2022
WebAssembly Lightweight Javascript Framework in Go (AngularJS Inspired)

Tango Lightweight WASM HTML / Javascript Framework Intro WebAssembly is nice, Go on the web is nice, so I ported Tangu to Go and WebAssembly. Tangu is

enimatek 4 Jun 8, 2022
Running a Command line tool written in Go on browser with WebAssembly

Running a command line tool written in Go on browser with WebAssembly This repo contains code/assets from the article Files: . β”œβ”€β”€ article.md

wcchoi 79 Jul 3, 2022
This library provides WebAssembly capability for goja Javascript engine

This module provides WebAssembly functions into goja javascript engine.

YC-L 1 Jan 10, 2022
A Brainfuck to WebAssembly compiler written in Go.

brainfuck2wasm A Brainfuck to WebAssembly compiler written in Go. I am writing this compiler for a Medium article. When I complete the compiler, I'll

Luke I. Wilson 2 Jun 6, 2022
Dom - A Go API for different Web APIs for WebAssembly target

Go DOM binding (and more) for WebAssembly This library provides a Go API for dif

Denys Smirnov 460 Aug 4, 2022
wazero: the zero dependency WebAssembly runtime for Go developers

wazero: the zero dependency WebAssembly runtime for Go developers WebAssembly is a way to safely run code compiled in other languages. Runtimes execut

Tetrate Labs 1.7k Aug 4, 2022
Run WASM tests inside your browser

wasmbrowsertest Run Go wasm tests easily in your browser. If you have a codebase targeting the wasm platform, chances are you would want to test your

Agniva De Sarker 127 Jul 13, 2022
The Dapr CLI allows you to setup Dapr on your local dev machine or on a Kubernetes cluster

Dapr CLI The Dapr CLI allows you to setup Dapr on your local dev machine or on a

null 1 Dec 23, 2021
A test repo to demonstrate the current (go1.17.2) issue when trying to use retractA test repo to demonstrate the current (go1.17.2) issue when trying to use retract

test-go-mod-retract This is a test repo to demonstrate the current (go1.17.2) issue when trying to use retract in go.mod to retract a version in a non

Yuxuan 'fishy' Wang 0 Oct 16, 2021
This Go based project of Aadhyarupam Innovators demonstrate the code examples for building microservices, integration with cloud services (Google Cloud Firestore), application configuration management (Viper) etc.

This Go based project of Aadhyarupam Innovators demonstrate the code examples for building microservices, integration with cloud services (Google Cloud Firestore), application configuration management (Viper) etc.

Aadhyarupam 0 Jan 31, 2022
YoMo 43 Jun 20, 2022
This is an example to demonstrate implementation golang microservices using domain driven design principles and sugestions from go-kit

go-kit DDD Domain Driven Design is prevelent and rising standard for organizing your microservice code. This design architecture emphasis on Code orga

Sourabh Mandal 1 Feb 9, 2022
Go-project-template - Template for a golang project

This is a template repository for golang project Usage Go to github: https://git

KyberNetwork 3 Jul 9, 2022
Project Flogo is an open source ecosystem of opinionated event-driven capabilities to simplify building efficient & modern serverless functions, microservices & edge apps.

Project Flogo is an Open Source ecosystem for event-driven apps Ecosystem | Core | Flows | Streams | Flogo Rules | Go Developers | When to use Flogo |

TIBCO Software Inc. 2.1k Aug 11, 2022
Simple project to demonstrate the loading of eBPF programs via florianl/go-tc.

tc-skeleton Simple project to demonstrate the loading of eBPF programs via florianl/go-tc.

Florian Lehner 29 Jul 19, 2022
A sample golang project to demonstrate the integration with rancher pipeline

pipeline-example-go This is a sample golang project to demonstrate the integration with rancher pipeline. Building go build -o ./bin/hello-server Runn

null 0 Oct 30, 2021
PHP functions implementation to Golang. This package is for the Go beginners who have developed PHP code before. You can use PHP like functions in your app, module etc. when you add this module to your project.

PHP Functions for Golang - phpfuncs PHP functions implementation to Golang. This package is for the Go beginners who have developed PHP code before. Y

Serkan Algur 51 Aug 5, 2022
Dapr is a portable, event-driven, runtime for building distributed applications across cloud and edge.

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 18.8k Aug 8, 2022
Collection of personal Dapr demos (bindings, state, pub/sub, service-to-service invocation)

Dapr demos Collection of personal Dapr demos. Note, some of these demos require latest version of Dapr, Ingress gateway, Observability components, or

Mark Chmarny 152 Jul 27, 2022