Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
A pattern I created to maintain connections to an RPC server in Go. Since net/rpc does not provide any methods for automatically reconnecting to an RPC server, I needed a work-around. Additionally, rpc.Client does not export any state variables (rpc.Client.shutdown and rpc.Client.closing) nor does it export the Client's Mutex. So, we wrap the rp…
package main
import (
"myapp/webserver/app/common"
"github.com/golang/glog"
"github.com/gorilla/mux"
"encoding/json"
"strconv"
"flag"
"fmt"
"log"
"net/http"
"net/rpc"
"time"
"sync"
)
type RpcConnection struct {
sync.Mutex
rpcClient *rpc.Client
}
var dataHost *string // endpoint for cache frontend service
var browserCacheControl *int
var router *mux.Router
var rpcConnection RpcConnection
func RpcConnect() (err error) {
rpcConnection.rpcClient, err = rpc.DialHTTP("tcp", *dataHost)
return err
}
// http://stackoverflow.com/a/6391185/1162491
func RpcConnectionCheck(rpcCallError error) {
var err error
if rpcConnection.rpcClient == nil {
log.Println("Restarting RPC Connection due to nil connection")
err = RpcConnect()
} else if rpcCallError == rpc.ErrShutdown || reflect.TypeOf(rpcCallError) == reflect.TypeOf((*rpc.ServerError)(nil)).Elem() {
log.Println("Restarting RPC Connection due to error")
rpcConnection.Lock()
err = RpcConnect()
rpcConnection.Unlock()
}
if err != nil {
log.Fatal("Unable to initialize connection to RPC")
}
}
func HttpInterceptor(w http.ResponseWriter, r *http.Request) {
startTime := time.Now()
router.ServeHTTP(w, r)
finishTime := time.Now()
elapsedTime := finishTime.Sub(startTime)
common.LogAccess(w, r, elapsedTime)
}
func main() {
dataHost = flag.String("dl", "localhost:9001", "dataaccess endpoint")
flag.Parse()
defer glog.Flush()
err := RpcConnect()
if err != nil {
log.Fatal("Unable to initialize connection to RPC")
}
router = mux.NewRouter()
router.HandleFunc("/healthcheck", func(w http.ResponseWriter, r *http.Request) {
accessCall := rpcConnection.rpcClient.Go(...)
replyCall := <-accessCall.Done
if replyCall.Error != nil {
http.Error(w, replyCall.Error.Error(), http.StatusInternalServerError)
// Return the error no matter what - you could write your own reattempt loop and try here
RpcConnectionCheck(replyCall.Error)
return
}
fmt.Fprintf(w, "success")
})
http.HandleFunc("/", HttpInterceptor)
http.ListenAndServe("0.0.0.0:"+*port, nil)
}

I'm wondering about rpcConnection.rpcClient.Go(...) what should be some valid args for this function call?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment