Skip to content

Commit

Permalink
Pass NewRouter a struct instead of too many params.
Browse files Browse the repository at this point in the history
NewRouter()'s parameter list was already getting out of hand.

Copying it straight into struct Router for now just for the sake of
convenience. Probably change that soon.
  • Loading branch information
sengi committed Aug 5, 2023
1 parent f09307a commit dc13c65
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 65 deletions.
72 changes: 41 additions & 31 deletions lib/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,30 @@ const (

// Router is a wrapper around an HTTP multiplexer (trie.Mux) which retrieves its
// routes from a passed mongo database.
//
// TODO: decouple Router from its database backend. Router should not know
// anything about the database backend. Its representation of the route table
// should be independent of the underlying DBMS. Route should define an
// abstract interface for some other module to be able to bulk-load and
// incrementally update routes. Since Router should not care where its routes
// come from, Route and Backend should not contain bson fields.
// MongoReplicaSet, MongoReplicaSetMember etc. should move out of this module.
type Router struct {
mux *triemux.Mux
lock sync.RWMutex
mongoURL string
mongoDbName string
mongoPollInterval time.Duration
backendConnectTimeout time.Duration
backendHeaderTimeout time.Duration
mongoReadToOptime bson.MongoTimestamp
logger logger.Logger
ReloadChan chan bool
mux *triemux.Mux
lock sync.RWMutex
mongoReadToOptime bson.MongoTimestamp
logger logger.Logger
opts Options
ReloadChan chan bool
}

type Options struct {
MongoURL string
MongoDbName string
MongoPollInterval time.Duration
BackendConnTimeout time.Duration
BackendHeaderTimeout time.Duration
LogFileName string
}

type Backend struct {
Expand Down Expand Up @@ -71,16 +84,16 @@ type Route struct {

// NewRouter returns a new empty router instance. You will need to call
// SelfUpdateRoutes() to initialise the self-update process for routes.
func NewRouter(mongoURL, mongoDbName string, mongoPollInterval, beConnTimeout, beHeaderTimeout time.Duration, logFileName string) (rt *Router, err error) {
logInfo("router: using mongo poll interval:", mongoPollInterval)
logInfo("router: using backend connect timeout:", beConnTimeout)
logInfo("router: using backend header timeout:", beHeaderTimeout)
func NewRouter(o Options) (rt *Router, err error) {
logInfo("router: using mongo poll interval:", o.MongoPollInterval)
logInfo("router: using backend connect timeout:", o.BackendConnTimeout)
logInfo("router: using backend header timeout:", o.BackendHeaderTimeout)

l, err := logger.New(logFileName)
l, err := logger.New(o.LogFileName)
if err != nil {
return nil, err
}
logInfo("router: logging errors as JSON to", logFileName)
logInfo("router: logging errors as JSON to", o.LogFileName)

// TODO: avoid using the global registry.
registerMetrics(prometheus.DefaultRegisterer)
Expand All @@ -92,15 +105,11 @@ func NewRouter(mongoURL, mongoDbName string, mongoPollInterval, beConnTimeout, b

reloadChan := make(chan bool, 1)
rt = &Router{
mux: triemux.NewMux(),
mongoURL: mongoURL,
mongoPollInterval: mongoPollInterval,
mongoDbName: mongoDbName,
backendConnectTimeout: beConnTimeout,
backendHeaderTimeout: beHeaderTimeout,
mongoReadToOptime: mongoReadToOptime,
logger: l,
ReloadChan: reloadChan,
mux: triemux.NewMux(),
mongoReadToOptime: mongoReadToOptime,
logger: l,
opts: o,
ReloadChan: reloadChan,
}

go rt.pollAndReload()
Expand Down Expand Up @@ -137,9 +146,9 @@ func (rt *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
}

func (rt *Router) SelfUpdateRoutes() {
logInfo(fmt.Sprintf("router: starting self-update process, polling for route changes every %v", rt.mongoPollInterval))
logInfo(fmt.Sprintf("router: starting self-update process, polling for route changes every %v", rt.opts.MongoPollInterval))

tick := time.Tick(rt.mongoPollInterval)
tick := time.Tick(rt.opts.MongoPollInterval)
for range tick {
logDebug("router: polling MongoDB for changes")

Expand All @@ -159,9 +168,9 @@ func (rt *Router) pollAndReload() {
}
}()

logDebug("mgo: connecting to", rt.mongoURL)
logDebug("mgo: connecting to", rt.opts.MongoURL)

sess, err := mgo.Dial(rt.mongoURL)
sess, err := mgo.Dial(rt.opts.MongoURL)
if err != nil {
logWarn(fmt.Sprintf("mgo: error connecting to MongoDB, skipping update (error: %v)", err))
return
Expand All @@ -184,7 +193,7 @@ func (rt *Router) pollAndReload() {

if rt.shouldReload(currentMongoInstance) {
logDebug("router: updates found")
rt.reloadRoutes(sess.DB(rt.mongoDbName), currentMongoInstance.Optime)
rt.reloadRoutes(sess.DB(rt.opts.MongoDbName), currentMongoInstance.Optime)
} else {
logDebug("router: no updates found")
}
Expand Down Expand Up @@ -290,7 +299,8 @@ func (rt *Router) loadBackends(c *mgo.Collection) (backends map[string]http.Hand
backends[backend.BackendID] = handlers.NewBackendHandler(
backend.BackendID,
backendURL,
rt.backendConnectTimeout, rt.backendHeaderTimeout,
rt.opts.BackendConnTimeout,
rt.opts.BackendHeaderTimeout,
rt.logger,
)
}
Expand Down
72 changes: 38 additions & 34 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,24 @@ ROUTER_FRONTEND_WRITE_TIMEOUT=60s See https://cs.opensource.google/go/go/+/mast
os.Exit(ErrUsage)
}

func getenvDefault(key string, defaultVal string) string {
val := os.Getenv(key)
if val == "" {
val = defaultVal
func getenv(key string, defaultVal string) string {
if s := os.Getenv(key); s != "" {
return s
}
return defaultVal
}

return val
func getenvDuration(key string, defaultVal string) time.Duration {
s := getenv(key, defaultVal)
return mustParseDuration(s)
}

func mustParseDuration(s string) (d time.Duration) {
d, err := time.ParseDuration(s)
if err != nil {
log.Fatal(err)
}
return
}

func listenAndServeOrFatal(addr string, handler http.Handler, rTimeout time.Duration, wTimeout time.Duration) {
Expand All @@ -61,30 +72,7 @@ func listenAndServeOrFatal(addr string, handler http.Handler, rTimeout time.Dura
}
}

func parseDurationOrFatal(s string) (d time.Duration) {
d, err := time.ParseDuration(s)
if err != nil {
log.Fatal(err)
}
return
}

func main() {
router.EnableDebugOutput = os.Getenv("ROUTER_DEBUG") != ""
var (
pubAddr = getenvDefault("ROUTER_PUBADDR", ":8080")
apiAddr = getenvDefault("ROUTER_APIADDR", ":8081")
mongoURL = getenvDefault("ROUTER_MONGO_URL", "127.0.0.1")
mongoDbName = getenvDefault("ROUTER_MONGO_DB", "router")
mongoPollInterval = getenvDefault("ROUTER_MONGO_POLL_INTERVAL", "2s")
errorLogFile = getenvDefault("ROUTER_ERROR_LOG", "STDERR")
tlsSkipVerify = os.Getenv("ROUTER_TLS_SKIP_VERIFY") != ""
backendConnectTimeout = getenvDefault("ROUTER_BACKEND_CONNECT_TIMEOUT", "1s")
backendHeaderTimeout = getenvDefault("ROUTER_BACKEND_HEADER_TIMEOUT", "20s")
frontendReadTimeout = getenvDefault("ROUTER_FRONTEND_READ_TIMEOUT", "60s")
frontendWriteTimeout = getenvDefault("ROUTER_FRONTEND_WRITE_TIMEOUT", "60s")
)

returnVersion := flag.Bool("version", false, "")
flag.Usage = usage
flag.Parse()
Expand All @@ -94,11 +82,20 @@ func main() {
os.Exit(0)
}

feReadTimeout := parseDurationOrFatal(frontendReadTimeout)
feWriteTimeout := parseDurationOrFatal(frontendWriteTimeout)
beConnectTimeout := parseDurationOrFatal(backendConnectTimeout)
beHeaderTimeout := parseDurationOrFatal(backendHeaderTimeout)
mgoPollInterval := parseDurationOrFatal(mongoPollInterval)
router.EnableDebugOutput = os.Getenv("ROUTER_DEBUG") != ""
var (
pubAddr = getenv("ROUTER_PUBADDR", ":8080")
apiAddr = getenv("ROUTER_APIADDR", ":8081")
mongoURL = getenv("ROUTER_MONGO_URL", "127.0.0.1")
mongoDbName = getenv("ROUTER_MONGO_DB", "router")
mongoPollInterval = getenvDuration("ROUTER_MONGO_POLL_INTERVAL", "2s")
errorLogFile = getenv("ROUTER_ERROR_LOG", "STDERR")
tlsSkipVerify = os.Getenv("ROUTER_TLS_SKIP_VERIFY") != ""
beConnTimeout = getenvDuration("ROUTER_BACKEND_CONNECT_TIMEOUT", "1s")
beHeaderTimeout = getenvDuration("ROUTER_BACKEND_HEADER_TIMEOUT", "20s")
feReadTimeout = getenvDuration("ROUTER_FRONTEND_READ_TIMEOUT", "60s")
feWriteTimeout = getenvDuration("ROUTER_FRONTEND_WRITE_TIMEOUT", "60s")
)

log.Printf("using frontend read timeout: %v", feReadTimeout)
log.Printf("using frontend write timeout: %v", feWriteTimeout)
Expand All @@ -110,7 +107,14 @@ func main() {
"Do not use this option in a production environment.")
}

rout, err := router.NewRouter(mongoURL, mongoDbName, mgoPollInterval, beConnectTimeout, beHeaderTimeout, errorLogFile)
rout, err := router.NewRouter(router.Options{
MongoURL: mongoURL,
MongoDbName: mongoDbName,
MongoPollInterval: mongoPollInterval,
BackendConnTimeout: beConnTimeout,
BackendHeaderTimeout: beHeaderTimeout,
LogFileName: errorLogFile,
})
if err != nil {
log.Fatal(err)
}
Expand Down

0 comments on commit dc13c65

Please sign in to comment.