Commit 1bdeb058 authored by Clayton Coleman's avatar Clayton Coleman

Slightly pause on requests to allow most to finish

Currently, every write will result in a 202 (etcd adding a few ms of latency to each request). This forces clients to go into a poll loop and pick a reasonable server poll frequency, which results in 1 + N queries to the server for the single operation and adds unavoidable latency to each request which affects their perception of the service. Add a very slight (25ms by default) delay to wait for requests to finish. For clients doing normal writes this reduces the requests made against the server to 1. For clients on long requests this has no effect. The downside is that http connections are held on to for a longer period in high write loads. The decrease in perceived latency from the kubecfg is significant.
parent 2486414c
...@@ -59,10 +59,11 @@ func NewNotFoundErr(kind, name string) error { ...@@ -59,10 +59,11 @@ func NewNotFoundErr(kind, name string) error {
// //
// TODO: consider migrating this to go-restful which is a more full-featured version of the same thing. // TODO: consider migrating this to go-restful which is a more full-featured version of the same thing.
type APIServer struct { type APIServer struct {
prefix string prefix string
storage map[string]RESTStorage storage map[string]RESTStorage
ops *Operations ops *Operations
mux *http.ServeMux mux *http.ServeMux
asyncOpWait time.Duration
} }
// New creates a new APIServer object. // New creates a new APIServer object.
...@@ -74,6 +75,8 @@ func New(storage map[string]RESTStorage, prefix string) *APIServer { ...@@ -74,6 +75,8 @@ func New(storage map[string]RESTStorage, prefix string) *APIServer {
prefix: strings.TrimRight(prefix, "/"), prefix: strings.TrimRight(prefix, "/"),
ops: NewOperations(), ops: NewOperations(),
mux: http.NewServeMux(), mux: http.NewServeMux(),
// Delay just long enough to handle most simple write operations
asyncOpWait: time.Millisecond * 25,
} }
// Primary API methods // Primary API methods
...@@ -279,6 +282,8 @@ func (s *APIServer) createOperation(out <-chan interface{}, sync bool, timeout t ...@@ -279,6 +282,8 @@ func (s *APIServer) createOperation(out <-chan interface{}, sync bool, timeout t
op := s.ops.NewOperation(out) op := s.ops.NewOperation(out)
if sync { if sync {
op.WaitFor(timeout) op.WaitFor(timeout)
} else if s.asyncOpWait != 0 {
op.WaitFor(s.asyncOpWait)
} }
return op return op
} }
......
...@@ -400,6 +400,7 @@ func TestCreate(t *testing.T) { ...@@ -400,6 +400,7 @@ func TestCreate(t *testing.T) {
handler := New(map[string]RESTStorage{ handler := New(map[string]RESTStorage{
"foo": simpleStorage, "foo": simpleStorage,
}, "/prefix/version") }, "/prefix/version")
handler.asyncOpWait = 0
server := httptest.NewServer(handler) server := httptest.NewServer(handler)
client := http.Client{} client := http.Client{}
......
...@@ -95,6 +95,7 @@ func TestOpGet(t *testing.T) { ...@@ -95,6 +95,7 @@ func TestOpGet(t *testing.T) {
handler := New(map[string]RESTStorage{ handler := New(map[string]RESTStorage{
"foo": simpleStorage, "foo": simpleStorage,
}, "/prefix/version") }, "/prefix/version")
handler.asyncOpWait = 0
server := httptest.NewServer(handler) server := httptest.NewServer(handler)
client := http.Client{} client := http.Client{}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment