func (e *Engine) Serve(ctx context.Context) error { pools := make([]*UserPool, 0, len(e.cfg.Pools)) for _, upc := range e.cfg.Pools { up, err := NewUserPoolFromConfig(&upc) if err != nil { log.Printf("Could not create user pool: %s", err) continue } pools = append(pools, up) } promises := utils.Promises{} for _, up := range pools { promises = append(promises, utils.PromiseCtx(ctx, up.Start)) } select { case err := <-promises.All(): if err != nil { return err } case <-ctx.Done(): } log.Println("Done") return nil }
func (up *UserPool) Start(ctx context.Context) error { // userCtx will be canceled when all users finished their execution userCtx, resultCancel := context.WithCancel(ctx) userPromises := utils.Promises{} utilsPromises := utils.Promises{ utils.PromiseCtx(ctx, up.ammunition.Start), utils.PromiseCtx(userCtx, up.results.Start), utils.PromiseCtx(ctx, up.startupLimiter.Start), } var sharedLimiter limiter.Limiter if up.sharedSchedule { var err error sharedLimiter, err = GetLimiter(up.userLimiterConfig) if err != nil { return fmt.Errorf("could not make a user limiter from config due to %s", err) } // Starting shared limiter. // This may cause spike load in the beginning of a test if it takes time // to initialize a user, because we don't wait for them to initialize in // case of shared limiter and there might be some ticks accumulated utilsPromises = append(utilsPromises, utils.PromiseCtx(userCtx, sharedLimiter.Start)) } for range up.startupLimiter.Control() { var l limiter.Limiter if up.sharedSchedule { l = sharedLimiter } else { var err error l, err = GetLimiter(up.userLimiterConfig) if err != nil { return fmt.Errorf("could not make a user limiter from config due to %s", err) } } g, err := GetGun(up.gunConfig) if err != nil { return fmt.Errorf("could not make a gun from config due to %s", err) } u := &User{ Name: up.name, Ammunition: up.ammunition, Results: up.results, Limiter: l, Gun: g, } if !up.sharedSchedule { utilsPromises = append(utilsPromises, utils.PromiseCtx(userCtx, l.Start)) } userPromises = append(userPromises, utils.PromiseCtx(ctx, u.Run)) } // FIXME: wrong logic here log.Println("Started all users. Waiting for them") err := <-userPromises.All() resultCancel() // stop result listener when all users finished err2 := utilsPromises.All() if err2 != nil { fmt.Printf("%v", err2) } return err }