func newHTTPProxy(cfg *config.Config) http.Handler { if err := route.SetPickerStrategy(cfg.Proxy.Strategy); err != nil { exit.Fatal("[FATAL] ", err) } log.Printf("[INFO] Using routing strategy %q", cfg.Proxy.Strategy) if err := route.SetMatcher(cfg.Proxy.Matcher); err != nil { exit.Fatal("[FATAL] ", err) } log.Printf("[INFO] Using routing matching %q", cfg.Proxy.Matcher) tr := &http.Transport{ ResponseHeaderTimeout: cfg.Proxy.ResponseHeaderTimeout, MaxIdleConnsPerHost: cfg.Proxy.MaxConn, Dial: (&net.Dialer{ Timeout: cfg.Proxy.DialTimeout, KeepAlive: cfg.Proxy.KeepAliveTimeout, }).Dial, } return proxy.NewHTTPProxy(tr, cfg.Proxy) }
/** 使用配置信息创建并返回HTTP代理服务器的句柄 */ func newHTTPProxy(cfg *config.Config) http.Handler { // 设置路由拣选策略 if err := route.SetPickerStrategy(cfg.Proxy.Strategy); err != nil { exit.Fatal("[FATAL] ", err) } log.Printf("[INFO] Using routing strategy %q", cfg.Proxy.Strategy) // 设置路由匹配器 if err := route.SetMatcher(cfg.Proxy.Matcher); err != nil { exit.Fatal("[FATAL] ", err) } log.Printf("[INFO] Using routing matching %q", cfg.Proxy.Matcher) // 配置转换器 tr := &http.Transport{ ResponseHeaderTimeout: cfg.Proxy.ResponseHeaderTimeout, MaxIdleConnsPerHost: cfg.Proxy.MaxConn, Dial: (&net.Dialer{ Timeout: cfg.Proxy.DialTimeout, KeepAlive: cfg.Proxy.KeepAliveTimeout, }).Dial, } /** @todo 上面代码中有疑问,如下代码: Dial: (&net.Dialer{ Timeout: cfg.Proxy.DialTimeout, KeepAlive: cfg.Proxy.KeepAliveTimeout, }).Dial 第一行为何用 &net.Dialer ? 即为何使用引用? 原因是 net包的Dialer结构体(struct)的方法Dial是指针类型,所以只有使用引用定义的时候才能访问到该函数 */ // 生成并返回HTTP代理句柄 return proxy.NewHTTPProxy(tr, cfg.Proxy) }
func TestGracefulShutdown(t *testing.T) { req := func(url string) int { resp, err := http.Get(url) if err != nil { t.Fatal(err) } defer resp.Body.Close() return resp.StatusCode } // start a server which responds after the shutdown has been triggered. srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { <-quit // wait for shutdown signal return })) defer srv.Close() // load the routing table tbl, err := route.ParseString("route add svc / " + srv.URL) if err != nil { t.Fatal(err) } route.SetTable(tbl) // start proxy with graceful shutdown period long enough // to complete one more request. var wg sync.WaitGroup l := config.Listen{Addr: "127.0.0.1:57777", Proto: "http"} wg.Add(1) go func() { defer wg.Done() startListeners([]config.Listen{l}, 250*time.Millisecond, proxy.NewHTTPProxy(http.DefaultTransport, config.Proxy{}), nil) }() // trigger shutdown after some time shutdownDelay := 100 * time.Millisecond go func() { time.Sleep(shutdownDelay) close(quit) }() // give proxy some time to start up // needs to be done before shutdown is triggered time.Sleep(shutdownDelay / 2) // make 200 OK request // start before and complete after shutdown was triggered if got, want := req("http://"+l.Addr+"/"), 200; got != want { t.Fatalf("request 1: got %v want %v", got, want) } // make 503 request // start and complete after shutdown was triggered if got, want := req("http://"+l.Addr+"/"), 503; got != want { t.Fatalf("got %v want %v", got, want) } // wait for listen() to return // note that the actual listeners have not returned yet wg.Wait() }