X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/03a016b1edff72e698474cd31a887530ea89b530..ffa1fd1fdf584c71e248e9bb7d523f788a517510:/sdk/go/httpserver/id_generator.go diff --git a/sdk/go/httpserver/id_generator.go b/sdk/go/httpserver/id_generator.go index c744691aa8..14d89873b6 100644 --- a/sdk/go/httpserver/id_generator.go +++ b/sdk/go/httpserver/id_generator.go @@ -5,12 +5,17 @@ package httpserver import ( + "math/rand" "net/http" "strconv" "sync" "time" ) +const ( + HeaderRequestID = "X-Request-Id" +) + // IDGenerator generates alphanumeric strings suitable for use as // unique IDs (a given IDGenerator will never return the same ID // twice). @@ -18,21 +23,24 @@ type IDGenerator struct { // Prefix is prepended to each returned ID. Prefix string - lastID int64 - mtx sync.Mutex + mtx sync.Mutex + src rand.Source } // Next returns a new ID string. It is safe to call Next from multiple // goroutines. func (g *IDGenerator) Next() string { - id := time.Now().UnixNano() g.mtx.Lock() - if id <= g.lastID { - id = g.lastID + 1 + defer g.mtx.Unlock() + if g.src == nil { + g.src = rand.NewSource(time.Now().UnixNano()) + } + a, b := g.src.Int63(), g.src.Int63() + id := strconv.FormatInt(a, 36) + strconv.FormatInt(b, 36) + for len(id) > 20 { + id = id[:20] } - g.lastID = id - g.mtx.Unlock() - return g.Prefix + strconv.FormatInt(id, 36) + return g.Prefix + id } // AddRequestIDs wraps an http.Handler, adding an X-Request-Id header @@ -40,8 +48,11 @@ func (g *IDGenerator) Next() string { func AddRequestIDs(h http.Handler) http.Handler { gen := &IDGenerator{Prefix: "req-"} return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - if req.Header.Get("X-Request-Id") == "" { - req.Header.Set("X-Request-Id", gen.Next()) + if req.Header.Get(HeaderRequestID) == "" { + if req.Header == nil { + req.Header = http.Header{} + } + req.Header.Set(HeaderRequestID, gen.Next()) } h.ServeHTTP(w, req) })