func (a *Agent) Update(ctx context.Context, now time.Time) { ctx = trace.Enter(ctx, a.Account[0]+".Pace") a.post() p := a.state.Load().(*Pacing) dt := now.Sub(p.timestamp) n := atomic.LoadInt64(&p.requests) qps := float64(n) / dt.Seconds() m := 0.0 s := 1.0 bps := 0.0 if a.Parameters != nil { pace, err := strconv.Atoi(strings.TrimSuffix(a.Parameters.Pace, "USD/1M")) if err != nil { pace = 0 } price, err := strconv.Atoi(strings.TrimSuffix(a.Parameters.Price, "USD/1M")) if err != nil { price = 0 } if price != 0 { bps = float64(pace) / float64(price) / 60.0 / 2.0 if bps >= qps { s = 1.0 } else { s = bps / qps } m = bps * dt.Seconds() } } ema := 0.8*p.sampling + 0.2*s trace.Set(ctx, "BPS", bps) trace.Set(ctx, "QPS", qps) //trace.Set(ctx, "SmoothQPS", qps) trace.Set(ctx, "Sampling", s) trace.Set(ctx, "SamplingEMA", ema) a.state.Store(&Pacing{ bids: int64(m), timestamp: now, qps: qps, sampling: ema, }) trace.Leave(ctx, "Done") }
// 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 }