An open API service indexing awesome lists of open source software.

https://github.com/vs4vijay/matrix

A Distributed Microservice in Go
https://github.com/vs4vijay/matrix

go golang microservice

Last synced: about 1 year ago
JSON representation

A Distributed Microservice in Go

Awesome Lists containing this project

README

          

# matrix

[![Release](https://github.com/vs4vijay/matrix/workflows/Release/badge.svg)](https://github.com/vs4vijay/matrix/releases)
[![Go Report Card](https://goreportcard.com/badge/github.com/vs4vijay/matrix)](https://goreportcard.com/report/github.com/vs4vijay/matrix)
[![Maintainability](https://api.codeclimate.com/v1/badges/ef8ddc6dc9dc972a7968/maintainability)](https://codeclimate.com/github/vs4vijay/matrix/maintainability)

---

## Installation

```console
go get github.com/vs4vijay/matrix
```

OR (Via **Homebrew**)

```console
brew install vs4vijay/matrix/matrix
```

OF (Via **Installer Script**)

```console
curl -fsSL https://raw.githubusercontent.com/vs4vijay/matrix/matrix/scripts/install.sh | bash
```

---

## Development

- Latest Go (`brew install golang`)
- Setup GOPATH (If you're using go version < 1.11)
```bash
export GOPATH=$HOME/golib
export GOPATH=$GOPATH:$HOME/github/matrix

go run main.go
```

- Auto Reload:
- `Air` - https://github.com/cosmtrek/air
- WatchMan: https://github.com/facebook/watchman
- modd: https://github.com/cortesi/modd
- entr: http://eradman.com/entrproject
- https://github.com/codegangsta/gin

---

---

### Contributing Guidelines

Before submitting a pull request, please ensure that you have run tests and lint checks locally. This will help in making the CI checks smooth and faster.

#### PR Gate Checks

When you submit a pull request, it will trigger automated checks for code linting, running unit tests, and checking for merge conflicts. These checks are in place to maintain the quality and integrity of the codebase. Please make sure your code passes these checks before submitting a PR.

### Guidelines

- Prefer `goimports` then `gofmt`
- Use `golint` for style mistakes
- https://github.com/golang/go/wiki/CodeReviewComments

---

### Commands
```bash
~/go/bin/cobra init --pkg-name github.com/vs4vijay/matrix

go mod init github.com/vs4vijay/matrix

go build

~/go/bin/cobra add list

createCmd.MarkFlagRequired("secret")
```

---

### Logging
```golang
log.SetFormatter(&log.TextFormatter{ForceColors: true})
log.SetOutput(colorable.NewColorableStdout())
```
- Log Verbosity: `cmd.PersistentFlags().CountVarP(&verbosity, "verbosity", "v", "set verbosity")`

---

### Linting
- gofmt
- goimports
- golint
- go vet

---

### Makefile
```bash
tools:
go get golang.org/x/tools/cmd/goimports
go get github.com/kisielk/errcheck
go get github.com/golang/lint/golint
go get github.com/axw/gocov/gocov
go get github.com/matm/gocov-html
go get github.com/tools/godep
go get github.com/mitchellh/gox

- `make test-lint`: runs linter/style checks
- `make test-unit`: runs basic unit tests
- `make test`: runs all of the above

```

---

### I/O

```golang

s := bufio.Scanner(os.Stdin)
s.Scan()

// OR

scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
break
}
if err := scanner.Err(); err != nil {
panic(err)
}

// OR

serverData, err := bufio.NewReader(connection).ReadString('\n')

```

---

### JSON / Marshalling / Un-marshalling

```golang

// Marshalling 1
j, err := json.Marshal(p)

// Marshalling 2
json.NewEncoder(writer).Encode(todos)

// Un-marshalling 1
body := make(map[string]interface{})
bodyBytes, _ := ioutil.ReadAll(request.Body)
err := json.Unmarshal(bodyBytes, &body)

// Un-marshalling 2
body := make(map[string]interface{})
err := json.NewDecoder(request.Body).Decode(&body)

```

---

```golang

// Make HTTP Call

payloadBytes, err := json.Marshal(payload)
if err != nil {
return nil, err
}

client = &http.Client{
Timeout: 10 * time.Second,
}
request, err := http.NewRequest(method, url, bytes.NewBuffer(payloadBytes))

request.Header.Add(echo.HeaderContentType, echo.MIMEApplicationJSON)
request.Header.Add("Authorization", "Bearer " + apiKey)
response, err := client.Do(request)
if err != nil {
return nil, err
}

defer response.Body.Close()
body, err := ioutil.ReadAll(response.Body)
if err != nil {
return nil, err
}

string(body)

// Convert Payload - I
values := map[string]string{"username": username, "password": password}
dataBytes, _ := json.Marshal(values)
resp, err := http.Post(authAuthenticatorUrl, "application/json", bytes.NewBuffer(dataBytes))

// Convert Payload - II, Mainly for Streaming
buf := new(bytes.Buffer)
json.NewEncoder(buf).Encode(body)
resp, err := http.Post(authAuthenticatorUrl, "application/json", buf)

// Ready Body
body, err := ioutil.ReadAll(resp.Body)

// Read Body to Object
var result map[string]interface{}
json.NewDecoder(resp.Body).Decode(&result)

```

---

### Channels
```golang
bye := make(chan os.Signal, 1)
signal.Notify(bye, os.Interrupt, syscall.SIGTERM)
<-bye
```

### WaitGroups
```golang
var wg sync.WaitGroup

wg.Add(1)
wg.Done()

wg.Wait()

```

---

### Signals
- signal.Notify(s1, syscall.SIGWINCH)
- signal.Ignore(syscall.SIGINT)
- signal.Stop(s1)
```golang
sigs := make(chan os.Signal, 1)
done := make(chan bool, 1)

signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)

go func() {
sig := <-sigs
fmt.Println(sig)
done <- true
}()

fmt.Println("awaiting signal")
<-done
fmt.Println("exiting")
```

---

### Timers and Tickers

```golang

// Timer
timer := time.NewTimer(2 * time.Second)
<-timer.C
fmt.Println("Timer 1 fired")

// Ticker
ticker := time.NewTicker(2 * time.Second)
done := make(chan bool)

go func() {
for {
select {
case <-done:
return
case t := <-ticker.C:
fmt.Println("Tick at", t)
}
}
}()

time.Sleep(10 * time.Second)
ticker.Stop()
done <- true
fmt.Println("Ticker stopped")

```

---

### Context
```golang
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
OR
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()

// Example 2

ctx := context.Background()
ctx, cancel := context.WithCancel(ctx)

go func() {
s := bufio.Scanner(os.Stdin)
s.Scan()
cancel()
}()

// Example 3
time.AfterFunc(time.Second, cancel)

// OR
ctx := context.Background()
ctx, cancel := context.WithTimeout(ctx, time.Second)
defer cancel() // "deadline exceeded", but "cancel()" will cancel

// viz
func viz(ctx context.Context, d time.Duration, msg string) {
select {
case <- time.After(d):
fmt.Println(msg)
case <- ctx.Done()
fmt.Errorf(ctx.Err())
}
}

```

---

### Mutex
```golang
var mutex *sync.Mutex

users.mutex.Lock()
defer users.mutex.Unlock()
append(users, user)
```

---

### Testing
- Table Testing

---

### System Exec
```golang

binary, lookErr := exec.LookPath("ls")

// Spawing
out, err := exec.Command("ls").Output()

// Using Syscall
args := []string{"ls", "-a", "-l", "-h"}
env := os.Environ()
execErr := syscall.Exec(binary, args, env)
```

---

### OS Detection:

- `runtime.GOOS == "windows"`

### APIs

- `net/http` - Native Implementation
- `chi` - lightweight, compatible net.Http
- `mux` -
- `gin` -
- `iris` -
- `echo` -
- `beego`

#### Using net/http:

```golang

// Option-I:

func someFunc(w http.ResponseWriter, r *http.Request) {
w.write([]byte("Hey"))
// fmt.Fprintln(w, "Hey")
}

http.HandleFunc("/", someFunc)
http.ListenAndServe(address, nil)

// Option-II:

http.Handle("/", server)
http.ListenAndServe(address, nil)
```
- server should have Handler interface, which should have ServeHTTP method

#### Using Mux:

```golang
router := mux.NewRouter()
router.HandleFunc("/", Index)
http.ListenAndServe(address, router)
```
- To get params - `mux.Vars(request)`

---

### Graceful Shutdown

```golang

// Trap sigterm or interrupt to gracefully shutdown the server
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, os.Interrupt)
signal.Notify(sigChan, os.Kill)

// Block until a signal is received.
sig := <-sigChan
logger.Printf("Got signal: %v, shutting down the server\n", sig)

// gracefully shutdown the server, waiting max 30 seconds for current operations to complete
ctx, _ := context.WithTimeout(context.Background(), 30*time.Second)
srv.Shutdown(ctx)

// OR

quit := make(chan os.Signal)
signal.Notify(quit, os.Interrupt)
<-quit

ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
if err := e.Shutdown(ctx); err != nil {
e.Logger.Fatal(err)
}
}

```

---

### Bash:
```bash
yell() { echo "FAILED> $*" >&2; }
die() { yell "$*"; exit 1; }
try() { "$@" || die "failed executing: $*"; }
log() { echo "--> $*"; }
```

---

### Dockerization:

```bash
docker build -t vs4vijay/matrix .
docker run vs4vijay/matrix
```

- Cleanup:
```bash
docker container prune
docker image prune
docker network prune
docker volume prune
```

- List Dangling Images: `docker images -f dangling=true`
- `docker rmi $(docker images --filter "dangling=true" -q --no-trunc)`
- Remove Volumes of Dangling Images: `docker volume rm $(docker volume ls -qf dangling=true)`
- Remove Containers: `docker rm $(docker ps -qa --no-trunc --filter "status=exited")`
- Remove Everything: `docker system prune -a --volumes`
- Kill All Running Containers: `docker kill $(docker ps -q)`

---

### Build Binary

- Build Tags: `// +build pro`
- go build -tags pro

---

### Distribute Binaries

- Manual Build
```bash
GOOS=darwin GOARCH=amd64 go build
GOOS=linux GOARCH=amd64 go build
GOOS=windows GOARCH=386 go build
```

- Git tags
- Create Tag: `git tag -a v0.0.0 -m "Initial release"`
- Push Tag: `git push origin v0.0.0`
- Delete Tag: `git push origin :v0.0.1`

- Go Releaser
- `brew install goreleaser/tap/goreleaser`
- `goreleaser init`
- Test: `goreleaser --snapshot --skip-publish --rm-dist`
- Release: `goreleaser --rm-dist`
- CI/CD with Github Actions:
```yaml
name: Release

on:
push:
tags:
- "v*.*.*"

jobs:
goreleaser:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v2
-
name: Unshallow
run: git fetch --prune --unshallow
-
name: Set up Go
uses: actions/setup-go@v1
with:
go-version: 1.14.x
-
name: GoReleaser Action
uses: goreleaser/goreleaser-action@v1.3.1
with:
version: latest
args: release --rm-dist
env:
GITHUB_TOKEN: ${{ secrets.GORELEASER_TOKEN }}
```

- Brew formula
- Repo: [vs4vijay/homebrew-matrix](https://github.com/vs4vijay/homebrew-matrix)
```
brew install matrix
brew info matrix
brew reinstall matrix --force
brew update
brew upgrade matrix
```

---

### Deployment
- Fly:
- OpenShift: https://manage.openshift.com/

---

### Badges
- ![Release](https://github.com/vs4vijay/matrix/workflows/Release/badge.svg) - `![Release](https://github.com/vs4vijay/matrix/workflows/Release/badge.svg)`

---

### 3rd Party Integrations
- Renovate Bot
- HoundCI
- Kodiak
- https://codecov.io/
- https://codeclimate.com/
- https://github.com/NickeManarin/ScreenToGif
- Sentry

---

### Git Hooks
```bash
git config core.hooksPath .
```
- commit - go mod tidy

---

### Microservice Toolkits
- Go Zero - https://github.com/zeromicro/go-zero
- Micro - https://github.com/micro/micro
- Go Kit - https://gokit.io/
- Gizmo - https://github.com/nytimes/gizmo
- Kite - https://github.com/koding/kite
- Beego - https://github.com/beego/beego
- Echo

---

### Development Notes

```

GO111MODULE=on
GOPROXY=https://gocenter.io
CGO_ENABLED=0

GOARCH=wasm GOOS=js go build -o app.wasm

wget: wget -q -O - https://raw.githubusercontent.com/rancher/k3d/master/install.sh | TAG=v1.3.4 bash
curl: curl -s https://raw.githubusercontent.com/rancher/k3d/master/install.sh | TAG=v1.3.4 bash

curl -sfL https://get.k3s.io | sh -

go get github.com/labstack/echo/v4

https://github.com/rivo/tview

Config - github.com/spf13/viper

go get github.com/satori/go.uuid
go get github.com/google/uuid

URL.QueryEscape

// fake.SetLang("ru")

https://www.jsonstore.io/da0e87e759b30f08825fd3b99adc0e42160c3be842c83ca8c1cec9698f58ffb2

json.NewDecoder(r.Body).Decode(&req)

json.NewEncoder(rw).Encode(...)

Service Discovery
Cirtuit Breaking
Rate Limiting
Tracing
Deploy Strategy
App Logging
Audit Logging
Caching
Security

----

Packaging applications with Docker
Testing microservice
Continuous Delivery
Observability
Using Kubernetes
Debugging
Security
Asynchronous microservices
Caching
Microservice reliability using a Service Mesh

----

Onion architecture
Hexagon architecture
Clean architecture

----

micro new jazz --type="srv"

protoc -I src ...

micro query <...>

micro web

```