coinbit_engineer_test

This project was created as a stage of completing the submission test. the main goal of creating a service using an implementation of event-driven architecture using Kafka as a message broker

Getting Started

Here some preparations that you might need before using this project.

Application Config

Before start the appliaction, first create configuration file. Name configuration is config.env

PORT=8000
BROKER="localhost:9092"

Topics

We define brokers includes topic-group it represents implement interface. When the Execute() function is called it will run the consumer process of kafka. See code provider.go

type Group string

const (
	BalanceGroup   Group = "balance"
	FlaggerGroup   Group = "flagger"
	ThresholdGroup Group = "threshold"
)

type Broker interface {
	Execute(ctx context.Context, groupName Group) error
}

Protobuf

we collect the need for transform protobuf as encoding/decoding payload for kafka broker. See code stream_encoders.go

var (
	DepositStream    goka.Stream = "deposit"
	FlagWalletStream goka.Stream = "flag_wallet"
)

type DepositEncoder struct{}

func (c *DepositEncoder) Encode(value interface{}) ([]byte, error) {
	...
}
func (c *DepositEncoder) Decode(data []byte) (interface{}, error) {
	...
}

type CounterEncoder struct{}

func (c *CounterEncoder) Encode(value interface{}) ([]byte, error) {
	...
}

func (c *CounterEncoder) Decode(data []byte) (interface{}, error) {
	...
}

API Endpoints

Goka provides three components to build systems: emitters, processors, and views. The following figure depicts our initial design using these three components together with Kafka and the endpoints.

Deposit endpoint

If John wants to deposit money, he would send a request to the send endpoint with the wallet_id and the amount of the message. For example:

curl -X POST \
    -d '{"wallet_id": "69da5a28bfee68a8b0bfeba076ee43f8ca4", "amount": 3500}' \
    http://localhost:8080/api/deposit
{
    "code": 200,
    "data": null,
    "message": "success"
}

Check Endpoint

When John wants to check his wallet balance, he requests that from the check endpoint. For example:

curl --location --request GET 'http://localhost:8000/api/check/69da5a28bfee68a8b0bfeba076ee43f8ca4'
{
	"wallet_id": "69da5a28bfee68a8b0bfeba076ee43f8ca4",
	"balance": 3500,
	"above_threshold": true
}

Running the project

In this project, we can put the endpoint handlers and, therefore, emitter and view in the same Go program. we start the collector processor. In another Go program can start the api service

proto-gen:
	protoc --go_out=. ./proto/*.proto

run-dev-api:
	go run cmd/main.go -service=api

run-dev-broker-balance:
	go run cmd/main.go -service=broker -broker_name=balance

run-dev-broker-flagger:
	go run cmd/main.go -service=broker -broker_name=flagger

run-dev-broker-detector:
	go run cmd/main.go -service=broker -broker_name=threshold