-
-
Save ateleshev/7dbd9bdb4f146fe59bd0 to your computer and use it in GitHub Desktop.
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…
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment