Summary
This reflects on how the raccoon-go-client can be used to communicate with the raccoon service using the different communication protocols.
Proposed solution
The idea is to keep the initialisations of the WebSocket, HTTP, and GRPC clients distinct so that users can select the one they are interested in using.
Message Encoding:
The client will take care of the serialization/deserialization of the JSON and PROTO messages. The user does not have to worry about it; the client will handle it.
Observability:
Client Stats using StatsD:
The client is also intending to provide the stats for API calls. The following stats are planned for export to the user.
sent_tt_ms
ack_tt_ms
total_bytes_sent
total_bytes_recieved
total_conn_err
Logging:
The client provides the interface and the default console logging that the user can use, disable, or provide its own implementation.
Client Info (version.go):
The client will emit the following information about itself, which will be provided during the go build command using the “-ldflags”
Name
Version
BuildDate
Request Guid:
The client will auto generate the request_guid. The client will also provide the provision to pass the request_guid.
Serialization:
The user can pass the array of high level proto/json etc. to the send API, and the client will internally serialize the user data and wrap it for the raccoon request.
The client comes with Json/Proto serializers built in, and even users can configure any serialization.
Websocket
Event Ack:
In the case of WebSocket, the client will also provide the async delivery channel to which the user can subscribe to receive the event acknowledgements.
Ping/Pong -:
The client will internally handle the ping/pong communication with the raccoon, will provide the setting for interval time.
Retry
The user can configure the retry options on which the client will retry based on the configuration provided.
This proposal gives the user the flexibility to use any serialization for converting the event bytes before sending them to the client, default will be proto.
The client will ship the Json/Proto serializer as part of the package.
// Request message
type Event struct {
Type string
Data interface{}
}
// Response message
type Response struct {
Status string
SentTime int64
Reason string
Data map[string]string
}
type Client interface {
Send([]*Event) (string, *Response, error)
SetUserClientInfo(*App)
}
// interfaces
type WebSocket interface {
Client
// WebSocket specific methods
}
type Grpc interface { Client }
type Rest interface { Client }
type RestClient struct { Opts Options }
type ClientOption interface {
Apply(*Options)
}
type Options struct {
Ser Serializer
}
func (s *RestClient) Apply(op *Options) {
s.serialize = op.Ser
}
func WithSerializer(ser Serializer) ClientOption {
return &RestClient{ serialize: ser }
}
// NewRest creates the rest client.
func NewRest(url string, opts ...ClientOption) *RestClient {
var o Options
for _, opt := range opts {
opt.Apply(&o)
}
return &RestClient{
Serialize: o.Serializer,
}
}
// Serializer
type Serializer func(interface{}) ([]byte, error)
// set the app info
func (*RestClient) SetAppInfo(app *App) {}
// Send sends the events to the raccoon service
func (c *RestClient) Send(events []*Event) (string, *Response, error) {
e := []*pb.Event{}
for _, ev := range events {
// serialize the bytes based on the config
b, _ := c.serialize(ev.Data)
e = append(e, &pb.Event{
EventBytes: b,
Type: ev.Type,
})
}
reqId := uuid.NewString()
raccoonReq := &pb.SendEventRequest{
ReqGuid: reqId,
Events: e,
}
// log & Send racoonReq to raccoon service
log.Print(raccoonReq)
return reqId, &Response{}, nil
}
// Client usage example
func ClientExample() {
JSON := func(i interface{}) ([]byte, error) {
return json.Marshal(i)
}
rest := NewRest("http://localhost:8080",
WithSerializer(JSON),
)
rest.SetAppInfo(&App{
Id: "goplay-123",
Name: "goplay-backend",
Version: "1.0",
})
reqId, resp, err := rest.Send([]*Event{
&Event{
Type: "page",
Data: &struct {
name string
}{"page-name"},
},
})
if err != nil {
log.Printf("%v, %s", err, reqId)
}
log.Print(resp.Status)
}