Skip to content

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.

go
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.

go
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.

go
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)
}