func TestOpenRTB(t *testing.T) { m := make(map[string]interface{}) if err := json.Unmarshal(sample, &m); err != nil { t.Fatal(err) } br, err := json.Marshal(m) if err != nil { t.Fatal(err) } log.Println(string(br)) b := &Bidders{ Pattern: "../../../../configs/bidders/*.json", } c := trace.Start(trace.SetHandler(context.Background(), nil), "test", "") b.Start() e := &Exchange{Bidders: b} w := httptest.NewRecorder() e.ServeHTTP(c, w, &http.Request{Body: ioutil.NopCloser(bytes.NewReader(br))}) trace.Leave(c, "done") log.Println(w.Code, w.Body.String()) }
func (b *Bidders) Start() (err error) { b.state.Store(make(map[string]*Agent)) //log.Println("START") update := func() (err error) { b.mu.Lock() defer b.mu.Unlock() log.Println("checking configurations...") ctx := trace.Start(trace.SetHandler(context.Background(), b.Tracer), b.Name+".Tick", "") last := b.state.Load().(map[string]*Agent) agents, err := Import(b.Pattern) if err != nil { log.Println(err) err = nil } if len(agents) == 0 { log.Println("no files found: ", b.Pattern) trace.Leave(ctx, "Errors.NoFiles") return } next := make(map[string]*Agent) now := time.Now().UTC() for _, agent := range agents { id := fmt.Sprintf("%d", agent.ID) //log.Println(id, agent.Account[0]) next[id] = agent if a := last[id]; a == nil { agent.Begin() } else { agent.state = a.state agent.Update(ctx, now) } } b.state.Store(next) trace.Leave(ctx, "Done") return } if err = update(); err != nil { log.Println(err) } b.tick = rtb.PeriodicFunc(rtb.Every(time.Minute), func() { err := update() if err != nil { log.Println(err) } }) return }
// ServeHTTP creates the root context and pass it to the HTTP request handler. // The default /ready route is also handled. func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { if atomic.LoadInt64(&s.ready) == 0 { http.Error(w, "server is closed", http.StatusServiceUnavailable) return } // start trace key := r.Header.Get(trace.HeaderKey) ctx := trace.Start(trace.SetHandler(context.Background(), s.Tracer), s.name, key) // ready? if r.URL.Path == "/ready" && r.Method == "GET" { trace.Leave(ctx, "Ready") w.WriteHeader(http.StatusOK) return } if s.Handler != nil { s.Handler.ServeHTTP(ctx, w, r) } trace.Leave(ctx, "Served") }
// Start installs the server and starts serving requests until the server is closed. func (s *Server) Start() (err error) { s.Server.Handler = s // open socket s.listen, err = net.Listen("tcp", defaults.String(s.Server.Addr, ":http")) if err != nil { return } s.name = defaults.String(s.Name, s.listen.Addr().String()) // provide a default read timeout if missing if 0 == s.Server.ReadTimeout { s.Server.ReadTimeout = time.Minute } // track new/closed HTTP connections s.conns = make(map[net.Conn]http.ConnState) cs := s.Server.ConnState s.Server.ConnState = func(conn net.Conn, state http.ConnState) { s.mu.Lock() defer s.mu.Unlock() switch state { case http.StateNew: atomic.AddInt64(&s.count, +1) s.wg.Add(1) s.conns[conn] = state case http.StateClosed, http.StateHijacked: atomic.AddInt64(&s.count, -1) s.wg.Done() delete(s.conns, conn) case http.StateActive, http.StateIdle: s.conns[conn] = state } if nil != cs { cs(conn, state) } } // update metrics s.tick = Tick(time.Second, func() { ctx := trace.Start(trace.SetHandler(context.Background(), s.Tracer), s.name+".Tick", "") trace.Set(ctx, "Connections", atomic.LoadInt64(&s.count)) trace.Set(ctx, "State", atomic.LoadInt64(&s.ready)) trace.Leave(ctx, "Ticked") }) // serve requests go func() { s.Server.Serve(s.listen) }() // set ready if !atomic.CompareAndSwapInt64(&s.ready, 0, 1) { panic("server is already ready to serve requests") } return }