diff --git a/.mapping.json b/.mapping.json index ce8f605d2..9783093ad 100644 --- a/.mapping.json +++ b/.mapping.json @@ -368,6 +368,7 @@ "tests/acceptance/http_test.go":"load/projects/pandora/tests/acceptance/http_test.go", "tests/acceptance/testdata/connect/connect-check-limit.yaml":"load/projects/pandora/tests/acceptance/testdata/connect/connect-check-limit.yaml", "tests/acceptance/testdata/connect/connect-check-passes.yaml":"load/projects/pandora/tests/acceptance/testdata/connect/connect-check-passes.yaml", + "tests/acceptance/testdata/connect/connect-pool-size.yaml":"load/projects/pandora/tests/acceptance/testdata/connect/connect-pool-size.yaml", "tests/acceptance/testdata/connect/connect-ssl.yaml":"load/projects/pandora/tests/acceptance/testdata/connect/connect-ssl.yaml", "tests/acceptance/testdata/connect/connect.yaml":"load/projects/pandora/tests/acceptance/testdata/connect/connect.yaml", "tests/acceptance/testdata/connect/payload.uri":"load/projects/pandora/tests/acceptance/testdata/connect/payload.uri", @@ -377,6 +378,7 @@ "tests/acceptance/testdata/http/http-check-limit.yaml":"load/projects/pandora/tests/acceptance/testdata/http/http-check-limit.yaml", "tests/acceptance/testdata/http/http-check-passes.yaml":"load/projects/pandora/tests/acceptance/testdata/http/http-check-passes.yaml", "tests/acceptance/testdata/http/http.yaml":"load/projects/pandora/tests/acceptance/testdata/http/http.yaml", + "tests/acceptance/testdata/http/http2-pool-size.yaml":"load/projects/pandora/tests/acceptance/testdata/http/http2-pool-size.yaml", "tests/acceptance/testdata/http/http2.yaml":"load/projects/pandora/tests/acceptance/testdata/http/http2.yaml", "tests/acceptance/testdata/http/https.yaml":"load/projects/pandora/tests/acceptance/testdata/http/https.yaml", "tests/acceptance/testdata/http/payload.uri":"load/projects/pandora/tests/acceptance/testdata/http/payload.uri", diff --git a/components/guns/http/base.go b/components/guns/http/base.go index 4d1e6b972..53561708e 100644 --- a/components/guns/http/base.go +++ b/components/guns/http/base.go @@ -15,6 +15,7 @@ import ( "github.com/pkg/errors" "github.com/yandex/pandora/core" "github.com/yandex/pandora/core/aggregator/netsample" + "github.com/yandex/pandora/core/clientpool" "github.com/yandex/pandora/core/warmup" "github.com/yandex/pandora/lib/netutil" "go.uber.org/zap" @@ -28,6 +29,7 @@ type BaseGunConfig struct { AutoTag AutoTagConfig `config:"auto-tag"` AnswLog AnswLogConfig `config:"answlog"` HTTPTrace HTTPTraceConfig `config:"httptrace"` + PoolSize int `config:"pool-size"` } // AutoTagConfig configure automatic tags generation based on ammo URI. First AutoTag URI path elements becomes tag. @@ -78,17 +80,21 @@ func NewBaseGun(clientConstructor ClientConstructor, cfg HTTPGunConfig, answLog }, AnswLog: answLog, Client: client, + ClientConstructor: func() Client { + return clientConstructor(cfg.Client, cfg.Target) + }, } } type BaseGun struct { - DebugLog bool // Automaticaly set in Bind if Log accepts debug messages. - Config BaseGunConfig - Connect func(ctx context.Context) error // Optional hook. - OnClose func() error // Optional. Called on Close(). - Aggregator netsample.Aggregator // Lazy set via BindResultTo. - AnswLog *zap.Logger - Client Client + DebugLog bool // Automaticaly set in Bind if Log accepts debug messages. + Config BaseGunConfig + Connect func(ctx context.Context) error // Optional hook. + OnClose func() error // Optional. Called on Close(). + Aggregator netsample.Aggregator // Lazy set via BindResultTo. + AnswLog *zap.Logger + Client Client + ClientConstructor func() Client core.GunDeps } @@ -96,8 +102,34 @@ type BaseGun struct { var _ Gun = (*BaseGun)(nil) var _ io.Closer = (*BaseGun)(nil) -func (b *BaseGun) WarmUp(_ *warmup.Options) (any, error) { - return nil, nil +type SharedDeps struct { + clientPool *clientpool.Pool[Client] +} + +func (b *BaseGun) WarmUp(opts *warmup.Options) (any, error) { + return b.createSharedDeps(opts) +} + +func (b *BaseGun) createSharedDeps(opts *warmup.Options) (*SharedDeps, error) { + clientPool, err := b.prepareClientPool() + if err != nil { + return nil, err + } + return &SharedDeps{ + clientPool: clientPool, + }, nil +} + +func (b *BaseGun) prepareClientPool() (*clientpool.Pool[Client], error) { + if b.Config.PoolSize <= 0 { + return nil, nil + } + clientPool, _ := clientpool.New[Client](b.Config.PoolSize) + for i := 0; i < b.Config.PoolSize; i++ { + client := b.ClientConstructor() + clientPool.Add(client) + } + return clientPool, nil } func (b *BaseGun) Bind(aggregator netsample.Aggregator, deps core.GunDeps) error { @@ -106,6 +138,10 @@ func (b *BaseGun) Bind(aggregator netsample.Aggregator, deps core.GunDeps) error // Enable debug level logging during shooting. Creating log entries isn't free. b.DebugLog = true } + extraDeps, ok := deps.Shared.(*SharedDeps) + if ok && extraDeps.clientPool != nil { + b.Client = extraDeps.clientPool.Next() + } if b.Aggregator != nil { log.Panic("already binded") diff --git a/tests/acceptance/connect_test.go b/tests/acceptance/connect_test.go index ee3ee2039..ac4d7f687 100644 --- a/tests/acceptance/connect_test.go +++ b/tests/acceptance/connect_test.go @@ -73,6 +73,12 @@ func (s *ConnectGunSuite) Test_Connect() { isTLS: true, wantCnt: 4, }, + { + name: "connect-pool-size", + filecfg: "testdata/connect/connect-pool-size.yaml", + isTLS: false, + wantCnt: 4, + }, } for _, tt := range tests { s.Run(tt.name, func() { diff --git a/tests/acceptance/http_test.go b/tests/acceptance/http_test.go index 829a48a7c..ccd610b93 100644 --- a/tests/acceptance/http_test.go +++ b/tests/acceptance/http_test.go @@ -97,6 +97,16 @@ func (s *PandoraSuite) Test_Http_Check_Passes() { isTLS: false, wantCnt: 15, }, + { + name: "http2-pool-size", + filecfg: "testdata/http/http2-pool-size.yaml", + isTLS: true, + preStartSrv: func(srv *httptest.Server) { + _ = http2.ConfigureServer(srv.Config, nil) + srv.TLS = srv.Config.TLSConfig + }, + wantCnt: 8, + }, } for _, tt := range tests { s.Run(tt.name, func() { diff --git a/tests/acceptance/testdata/connect/connect-pool-size.yaml b/tests/acceptance/testdata/connect/connect-pool-size.yaml new file mode 100644 index 000000000..244271a8e --- /dev/null +++ b/tests/acceptance/testdata/connect/connect-pool-size.yaml @@ -0,0 +1,23 @@ +pools: + - id: "" + ammo: + file: testdata/http/payload.uri + type: uri + result: + type: discard + gun: + target: {{.target}} + type: connect + pool-size: 1 + answlog: + enabled: false + rps-per-instance: false + rps: + - duration: 1s + ops: 4 + type: const + startup: + - times: 2 + type: once +log: + level: debug diff --git a/tests/acceptance/testdata/http/http2-pool-size.yaml b/tests/acceptance/testdata/http/http2-pool-size.yaml new file mode 100644 index 000000000..012fec7a9 --- /dev/null +++ b/tests/acceptance/testdata/http/http2-pool-size.yaml @@ -0,0 +1,26 @@ +pools: + - id: "" + ammo: + type: uri + headers: + - '[Content-Type: application/json]' + uris: + - / + result: + type: discard + gun: + target: {{.target}} + type: http2 + answlog: + enabled: false + pool-size: 1 + rps-per-instance: false + rps: + - duration: 1s + ops: 8 + type: const + startup: + - times: 2 + type: once +log: + level: debug