Files
docs/docs/go/advanced/rpc.md

2.1 KiB

RPC

RPC stands for Remote Procedure Calls, and allows for external Go microservices to call functions in our application directly.

Listener

To do this, you need to define a RPCServer dummy type, and payload to receive, and a function that gets a pointer to a response string and returns an error.

type RPCServer struct{}

type RPCPayload struct {
	Name string
	Data string
}

func (r *RPCServer) LogInfo(payload RPCPayload, resp *string) error {
	collection := client.Database("logs").Collection("logs")
	_, err := collection.InsertOne(context.TODO(), data.LogEntry{
		Name: payload.Name,
		Data: payload.Data,
	})
	if err != nil {
		log.Println("error writing to mongo ", err)
		return err
	}
	*resp = "processed payload via RPC: " + payload.Name

	return nil
}

To instantiate the RPCServer, use the below syntax in your main application file. Basically you define a function that creates the connection and listens on a port. Then, you register your RPC handler type and serve the RPC server.

func (app *Config) rpcListen() error {
	log.Println("Starting RPC server on port " + RPC_PORT)
	listen, err := net.Listen("tcp", fmt.Sprintf("0.0.0.0:%s", RPC_PORT))
	if err != nil {
		return err
	}
	defer listen.Close()

	for {
		rpcConn, err := listen.Accept()
		if err != nil {
			log.Println("Error accepting connection: ", err)
			continue
		}
		go rpc.ServeConn(rpcConn)
	}
}

// in function where you start your app...
err = rpc.Register(new(RPCServer))
go app.rpcListen()

Sender

To send messages via RPC, you need to create a type for the payload that exactly matches that of the receiver.

type RPCPayload struct {
	Name string
	Data string
}

func (app *Config) logItemViaRPC(r http.ResponseWriter, l LogPayload) {
	client, err := rpc.Dial("tcp", "logger:5001")
	if err != nil {
		app.errorJSON(r, err)
		return
	}

	payload := RPCPayload{
		Name: l.Name,
		Data: l.Data,
	}

	var resp string

	err = client.Call("RPCServer.LogInfo", payload, &resp)
	if err != nil {
		app.errorJSON(r, err)
		return
	}

	returnPayload := jsonResponse{
		Error:   false,
		Message: resp,
	}

	app.writeJSON(r, http.StatusAccepted, returnPayload)
}