refactor: distributed load testing

This commit is contained in:
徐聪
2022-07-11 00:02:22 +08:00
parent b121282525
commit 848d72fe3a
40 changed files with 1958 additions and 1280 deletions

2
go.mod
View File

@@ -30,7 +30,7 @@ require (
golang.org/x/net v0.0.0-20220225172249-27dd8689420f
golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602
google.golang.org/grpc v1.45.0
google.golang.org/protobuf v1.27.1
google.golang.org/protobuf v1.28.0
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
)

3
go.sum
View File

@@ -866,8 +866,9 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

View File

@@ -3,6 +3,7 @@ package hrp
import (
"fmt"
"github.com/httprunner/httprunner/v4/hrp/internal/builtin"
"golang.org/x/net/context"
"io/ioutil"
"os"
"path/filepath"
@@ -98,12 +99,12 @@ func (b *HRPBoomer) Run(testcases ...ITestCase) {
// report execution timing event
defer sdk.SendEvent(event.StartTiming("execution"))
taskSlice := b.ConvertTestCasesToTasks(testcases...)
taskSlice := b.ConvertTestCasesToBoomerTasks(testcases...)
b.Boomer.Run(taskSlice...)
}
func (b *HRPBoomer) ConvertTestCasesToTasks(testcases ...ITestCase) (taskSlice []*boomer.Task) {
func (b *HRPBoomer) ConvertTestCasesToBoomerTasks(testcases ...ITestCase) (taskSlice []*boomer.Task) {
// load all testcases
testCases, err := LoadTestCases(testcases...)
if err != nil {
@@ -129,25 +130,8 @@ func (b *HRPBoomer) ConvertTestCasesToTasks(testcases ...ITestCase) (taskSlice [
return taskSlice
}
func (b *HRPBoomer) PollTestCases() {
for {
select {
case <-b.Boomer.ParseTestCasesChan():
var tcs []ITestCase
for _, tc := range b.GetTestCasesPath() {
tcp := TestCasePath(tc)
tcs = append(tcs, &tcp)
}
b.GetTestCaseBytesChan() <- b.TestCasesToBytes(tcs...)
log.Info().Msg("put testcase successful")
case <-b.Boomer.GetCloseChan():
return
}
}
}
func (b *HRPBoomer) OutTestCases(testCases []*TestCase) []*TCase {
var outTestCases []*TCase
func (b *HRPBoomer) ParseTestCases(testCases []*TestCase) []*TCase {
var parsedTestCases []*TCase
for _, tc := range testCases {
caseRunner, err := b.hrpRunner.newCaseRunner(tc)
if err != nil {
@@ -155,12 +139,12 @@ func (b *HRPBoomer) OutTestCases(testCases []*TestCase) []*TCase {
os.Exit(1)
}
caseRunner.parsedConfig.Parameters = caseRunner.parametersIterator.outParameters()
outTestCases = append(outTestCases, &TCase{
parsedTestCases = append(parsedTestCases, &TCase{
Config: caseRunner.parsedConfig,
TestSteps: caseRunner.testCase.ToTCase().TestSteps,
})
}
return outTestCases
return parsedTestCases
}
func (b *HRPBoomer) TestCasesToBytes(testcases ...ITestCase) []byte {
@@ -170,7 +154,7 @@ func (b *HRPBoomer) TestCasesToBytes(testcases ...ITestCase) []byte {
log.Error().Err(err).Msg("failed to load testcases")
os.Exit(1)
}
tcs := b.OutTestCases(testCases)
tcs := b.ParseTestCases(testCases)
testCasesBytes, err := json.Marshal(tcs)
if err != nil {
log.Error().Err(err).Msg("failed to marshal testcases")
@@ -192,7 +176,7 @@ func (b *HRPBoomer) Quit() {
b.Boomer.Quit()
}
func (b *HRPBoomer) runTasks(testCases []*TCase, profile *boomer.Profile) {
func (b *HRPBoomer) runTestCases(testCases []*TCase, profile *boomer.Profile) {
var testcases []ITestCase
for _, tc := range testCases {
tesecase, err := tc.toTestCase()
@@ -230,7 +214,7 @@ func (b *HRPBoomer) runTasks(testCases []*TCase, profile *boomer.Profile) {
b.Run(testcases...)
}
func (b *HRPBoomer) rebalanceTasks(profile *boomer.Profile) {
func (b *HRPBoomer) rebalanceBoomer(profile *boomer.Profile) {
b.SetProfile(profile)
b.SetSpawnCount(b.GetProfile().SpawnCount)
b.SetSpawnRate(b.GetProfile().SpawnRate)
@@ -241,17 +225,17 @@ func (b *HRPBoomer) rebalanceTasks(profile *boomer.Profile) {
func (b *HRPBoomer) PollTasks() {
for {
select {
case tasks := <-b.Boomer.GetTasksChan():
case task := <-b.Boomer.GetTasksChan():
// 清理过时测试用例任务
if len(b.Boomer.GetTasksChan()) > 0 {
continue
}
//Todo: 过滤掉已经传输过的task
if tasks.Tasks != nil {
testCases := b.BytesToTestCases(tasks.Tasks)
go b.runTasks(testCases, tasks.Profile)
if task.TestCases != nil {
testCases := b.BytesToTestCases(task.TestCases)
go b.runTestCases(testCases, task.Profile)
} else {
go b.rebalanceTasks(tasks.Profile)
go b.rebalanceBoomer(task.Profile)
}
case <-b.Boomer.GetCloseChan():
@@ -260,6 +244,25 @@ func (b *HRPBoomer) PollTasks() {
}
}
func (b *HRPBoomer) PollTestCases(ctx context.Context) {
for {
select {
case <-b.Boomer.ParseTestCasesChan():
var tcs []ITestCase
for _, tc := range b.GetTestCasesPath() {
tcp := TestCasePath(tc)
tcs = append(tcs, &tcp)
}
b.TestCaseBytesChan() <- b.TestCasesToBytes(tcs...)
log.Info().Msg("put testcase successful")
case <-b.Boomer.GetCloseChan():
return
case <-ctx.Done():
return
}
}
}
func (b *HRPBoomer) convertBoomerTask(testcase *TestCase, rendezvousList []*Rendezvous) *boomer.Task {
// init runner for testcase
// this runner is shared by multiple session runners

View File

@@ -1,6 +1,7 @@
package cmd
import (
"golang.org/x/net/context"
"os"
"strings"
"time"
@@ -55,7 +56,7 @@ var boomCmd = &cobra.Command{
hrpBoomer = hrp.NewStandaloneBoomer(boomArgs.SpawnCount, boomArgs.SpawnRate)
}
hrpBoomer.SetProfile(&boomArgs.Profile)
hrpBoomer.EnableGracefulQuit()
ctx := hrpBoomer.EnableGracefulQuit(context.Background())
// run boomer
switch hrpBoomer.GetMode() {
@@ -67,15 +68,20 @@ var boomCmd = &cobra.Command{
hrpBoomer.SetSpawnCount(boomArgs.SpawnCount)
hrpBoomer.SetSpawnRate(boomArgs.SpawnRate)
}
go hrpBoomer.StartServer()
go hrpBoomer.RunMaster()
hrpBoomer.PollTestCases()
if boomArgs.autoStart {
hrpBoomer.InitBoomer()
} else {
go hrpBoomer.StartServer()
}
go hrpBoomer.PollTestCases(ctx)
hrpBoomer.RunMaster()
case "worker":
if boomArgs.ignoreQuit {
hrpBoomer.SetIgnoreQuit()
}
go hrpBoomer.RunWorker()
hrpBoomer.PollTasks()
go hrpBoomer.PollTasks()
hrpBoomer.RunWorker()
time.Sleep(3 * time.Second)
case "standalone":
if venv != "" {
hrpBoomer.SetPython3Venv(venv)

View File

@@ -2,6 +2,7 @@ package boomer
import (
"github.com/httprunner/httprunner/v4/hrp/internal/json"
"golang.org/x/net/context"
"math"
"os"
"os/signal"
@@ -84,20 +85,6 @@ func (b *Boomer) SetProfile(profile *Profile) {
}
}
func (p *Profile) dispatch(workers int64) *Profile {
workerProfile := *p
if p.SpawnCount > 0 {
workerProfile.SpawnCount = p.SpawnCount / workers
}
if p.SpawnRate > 0 {
workerProfile.SpawnRate = p.SpawnRate / float64(workers)
}
if p.MaxRPS > 0 {
workerProfile.MaxRPS = p.MaxRPS / workers
}
return &workerProfile
}
// SetMode only accepts boomer.DistributedMasterMode、boomer.DistributedWorkerMode and boomer.StandaloneMode.
func (b *Boomer) SetMode(mode Mode) {
switch mode {
@@ -169,14 +156,9 @@ func (b *Boomer) RunWorker() {
b.workerRunner.run()
}
// GetTestCaseBytesChan gets test case bytes chan
func (b *Boomer) GetTestCaseBytesChan() chan []byte {
switch b.mode {
case DistributedMasterMode:
return b.masterRunner.testCaseBytes
default:
return nil
}
// TestCaseBytesChan gets test case bytes chan
func (b *Boomer) TestCaseBytesChan() chan []byte {
return b.masterRunner.testCaseBytes
}
func ProfileToBytes(profile *Profile) []byte {
@@ -197,18 +179,8 @@ func BytesToProfile(profileBytes []byte) *Profile {
return profile
}
// GetProfileBytesChan gets profile bytes chan
func (b *Boomer) GetProfileBytesChan() chan []byte {
switch b.mode {
case DistributedMasterMode:
return b.masterRunner.profileBytes
default:
return nil
}
}
// GetTasksChan gets profile bytes chan
func (b *Boomer) GetTasksChan() chan *profileMessage {
// GetTasksChan getsTasks chan
func (b *Boomer) GetTasksChan() chan *task {
switch b.mode {
case DistributedWorkerMode:
return b.workerRunner.tasksChan
@@ -373,13 +345,16 @@ func (b *Boomer) EnableMemoryProfile(memoryProfile string, duration time.Duratio
}
// EnableGracefulQuit catch SIGINT and SIGTERM signals to quit gracefully
func (b *Boomer) EnableGracefulQuit() {
func (b *Boomer) EnableGracefulQuit(ctx context.Context) context.Context {
ctx, cancel := context.WithCancel(ctx)
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGTERM, syscall.SIGINT)
go func() {
<-c
b.Quit()
cancel()
}()
return ctx
}
// Run accepts a slice of Task and connects to the locust master.

View File

@@ -1,9 +0,0 @@
package boomer
type client interface {
connect() (err error)
close()
recvChannel() chan *genericMessage
sendChannel() chan *genericMessage
disconnectedChannel() chan bool
}

View File

@@ -3,7 +3,6 @@ package boomer
import (
"context"
"fmt"
"io"
"sync"
"sync/atomic"
"time"
@@ -12,27 +11,30 @@ import (
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/credentials/oauth"
"google.golang.org/grpc/metadata"
"github.com/httprunner/httprunner/v4/hrp/internal/data"
"github.com/httprunner/httprunner/v4/hrp/internal/grpc/messager"
"github.com/httprunner/httprunner/v4/hrp/internal/boomer/data"
"github.com/httprunner/httprunner/v4/hrp/internal/boomer/grpc/messager"
"github.com/pkg/errors"
"github.com/rs/zerolog/log"
)
type grpcClient struct {
messager.MessageClient
masterHost string
masterPort int
identity string // nodeID
config *grpcClientConfig
fromMaster chan *genericMessage
toMaster chan *genericMessage
disconnectedFromMaster chan bool
shutdownChan chan bool
fromMaster chan *genericMessage
toMaster chan *genericMessage
disconnectedChan chan bool
shutdownChan chan bool
failCount int32
wg sync.WaitGroup
wg *sync.WaitGroup
}
type grpcClientConfig struct {
@@ -48,10 +50,6 @@ type grpcClientConfig struct {
const token = "httprunner-secret-token"
func logger(format string, a ...interface{}) {
log.Logger.Log().Msg(fmt.Sprintf(format, a...))
}
// unaryInterceptor is an example unary interceptor.
func unaryInterceptor(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
var credsConfigured bool
@@ -94,6 +92,15 @@ func newWrappedStream(s grpc.ClientStream) grpc.ClientStream {
return &wrappedStream{s}
}
func extractToken(ctx context.Context) (tkn string, ok bool) {
md, ok := metadata.FromIncomingContext(ctx)
if !ok || len(md[token]) == 0 {
return "", false
}
return md[token][0], true
}
// streamInterceptor is an example stream interceptor.
func streamInterceptor(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error) {
var credsConfigured bool
@@ -133,26 +140,27 @@ func newClient(masterHost string, masterPort int, identity string) (client *grpc
// Initiate the stream with a context that supports cancellation.
ctx, cancel := context.WithCancel(context.Background())
client = &grpcClient{
masterHost: masterHost,
masterPort: masterPort,
identity: identity,
fromMaster: make(chan *genericMessage, 100),
toMaster: make(chan *genericMessage, 100),
disconnectedFromMaster: make(chan bool),
shutdownChan: make(chan bool),
masterHost: masterHost,
masterPort: masterPort,
identity: identity,
fromMaster: make(chan *genericMessage, 100),
toMaster: make(chan *genericMessage, 100),
disconnectedChan: make(chan bool),
shutdownChan: make(chan bool),
config: &grpcClientConfig{
ctx: ctx,
ctxCancel: cancel,
mutex: sync.RWMutex{},
},
wg: &sync.WaitGroup{},
}
return client
}
func (c *grpcClient) connect() (err error) {
func (c *grpcClient) start() (err error) {
addr := fmt.Sprintf("%v:%v", c.masterHost, c.masterPort)
// Create tls based credential.
creds, err := credentials.NewClientTLSFromFile(data.Path("x509/ca_cert.pem"), "x.test.example.com")
creds, err := credentials.NewClientTLSFromFile(data.Path("x509/ca_cert.pem"), "www.httprunner.com")
if err != nil {
log.Fatal().Msg(fmt.Sprintf("failed to load credentials: %v", err))
}
@@ -160,7 +168,7 @@ func (c *grpcClient) connect() (err error) {
// oauth.NewOauthAccess requires the configuration of transport
// credentials.
grpc.WithTransportCredentials(creds),
grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(1024 * 1024 * 1024)),
grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(32 * 10e9)),
grpc.WithUnaryInterceptor(unaryInterceptor),
grpc.WithStreamInterceptor(streamInterceptor),
}
@@ -169,43 +177,47 @@ func (c *grpcClient) connect() (err error) {
log.Error().Err(err).Msg("failed to connect")
return err
}
grpc.MaxCallRecvMsgSize(32 * 10e9)
go c.recv()
go c.send()
biStream, err := messager.NewMessageClient(c.config.conn).BidirectionalStreamingMessage(c.config.ctx)
if err != nil {
log.Error().Err(err).Msg("call bidirectional streaming message err")
return err
}
c.config.setBiStreamClient(biStream)
log.Info().Msg(fmt.Sprintf("Boomer is connected to master(%s) press Ctrl+c to quit.\n", addr))
c.MessageClient = messager.NewMessageClient(c.config.conn)
return nil
}
func (c *grpcClient) reConnect() (err error) {
biStream, err := messager.NewMessageClient(c.config.conn).BidirectionalStreamingMessage(c.config.ctx)
func (c *grpcClient) register(ctx context.Context) error {
ctx, cancel := context.WithTimeout(ctx, time.Second)
defer cancel()
res, err := c.Register(ctx, &messager.RegisterRequest{NodeID: c.identity})
if err != nil {
return
return err
}
c.config.setBiStreamClient(biStream)
// register worker information to master
c.sendChannel() <- newGenericMessage("register", nil, c.identity)
//// tell master, I'm ready
//log.Info().Msg("send client ready signal")
//c.sendChannel() <- newClientReadyMessageToMaster(c.identity)
log.Info().Msg(fmt.Sprintf("Boomer is reConnected to master press Ctrl+c to quit.\n"))
return
if res.Code != "0" {
return errors.New(res.Message)
}
return nil
}
func (c *grpcClient) close() {
close(c.shutdownChan)
c.config.ctxCancel()
if c.config.conn != nil {
c.config.conn.Close()
func (c *grpcClient) signOut(ctx context.Context) error {
ctx, cancel := context.WithTimeout(ctx, time.Second)
defer cancel()
res, err := c.SignOut(ctx, &messager.SignOutRequest{NodeID: c.identity})
if err != nil {
return err
}
if res.Code != "0" {
return errors.New(res.Message)
}
return nil
}
func (c *grpcClient) newBiStreamClient() (err error) {
md := metadata.New(map[string]string{token: c.identity})
ctx := metadata.NewOutgoingContext(c.config.ctx, md)
biStream, err := c.BidirectionalStreamingMessage(ctx)
if err != nil {
return err
}
c.config.setBiStreamClient(biStream)
println("successful to establish bidirectional stream with master, press Ctrl+c to quit.\n")
return nil
}
func (c *grpcClient) recvChannel() chan *genericMessage {
@@ -213,8 +225,6 @@ func (c *grpcClient) recvChannel() chan *genericMessage {
}
func (c *grpcClient) recv() {
c.wg.Add(1)
defer c.wg.Done()
for {
select {
case <-c.shutdownChan:
@@ -235,7 +245,7 @@ func (c *grpcClient) recv() {
}
if msg.NodeID != c.identity {
log.Warn().
log.Info().
Str("nodeID", msg.NodeID).
Str("type", msg.Type).
Interface("data", msg.Data).
@@ -266,8 +276,6 @@ func (c *grpcClient) sendChannel() chan *genericMessage {
}
func (c *grpcClient) send() {
c.wg.Add(1)
defer c.wg.Done()
for {
select {
case <-c.shutdownChan:
@@ -278,7 +286,7 @@ func (c *grpcClient) send() {
// We may send genericMessage to master.
switch msg.Type {
case "quit":
c.disconnectedFromMaster <- true
c.disconnectedChan <- true
}
}
}
@@ -298,9 +306,6 @@ func (c *grpcClient) sendMessage(msg *genericMessage) {
switch err {
case nil:
atomic.StoreInt32(&c.failCount, 0)
break
case io.EOF:
fallthrough
default:
//log.Error().Err(err).Interface("genericMessage", *msg).Msg("failed to send message")
atomic.AddInt32(&c.failCount, 1)
@@ -308,5 +313,13 @@ func (c *grpcClient) sendMessage(msg *genericMessage) {
}
func (c *grpcClient) disconnectedChannel() chan bool {
return c.disconnectedFromMaster
return c.disconnectedChan
}
func (c *grpcClient) close() {
close(c.shutdownChan)
c.config.ctxCancel()
if c.config.conn != nil {
c.config.conn.Close()
}
}

View File

@@ -0,0 +1,34 @@
-----BEGIN CERTIFICATE-----
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
-----END CERTIFICATE-----

View File

@@ -0,0 +1,52 @@
-----BEGIN PRIVATE KEY-----
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
8xnynnp57i3BHHHbjY4R02Mqsfi1nNoN
-----END PRIVATE KEY-----

View File

@@ -0,0 +1,34 @@
-----BEGIN CERTIFICATE-----
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
-----END CERTIFICATE-----

View File

@@ -0,0 +1,52 @@
-----BEGIN PRIVATE KEY-----
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
+3KzjPLML31OD8TN22FUzsYcdw2prEU=
-----END PRIVATE KEY-----

View File

@@ -0,0 +1,32 @@
-----BEGIN CERTIFICATE-----
MIIFcTCCA1mgAwIBAgICA+gwDQYJKoZIhvcNAQELBQAwUDELMAkGA1UEBhMCVVMx
CzAJBgNVBAgMAkNBMQwwCgYDVQQHDANTVkwxDTALBgNVBAoMBGdSUEMxFzAVBgNV
BAMMDnRlc3QtY2xpZW50X2NhMB4XDTIyMDcxMDA0MzAxNVoXDTMyMDcwNzA0MzAx
NVowTjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQwwCgYDVQQHDANTVkwxDTAL
BgNVBAoMBGdSUEMxFTATBgNVBAMMDHRlc3QtY2xpZW50MTCCAiIwDQYJKoZIhvcN
AQEBBQADggIPADCCAgoCggIBAK36523v5SEM+J8ReNt3USwylERoUMqygoQRTIy7
ipzfO2dmo5OANFsJtPb3CH+YB6kS9llAioLa9UNrD6SBlR23No/QJeXBiXgpUXAE
DCLhQ/aj0fEy8AEnW+a6mM5jmsEHOy/O3q/KF1JdjNA1T7HuBS6cIvp5+7rF1rG9
tzJLLrXwUZLKlMjdCDuLxp/qtYUoH81CIuveWAODH3oad559HgD6UBgDRntdT902
IUnTejCAOY9Q0yTlcMMbz+FEMZ43Xq4E89YQ7Mel+xkb0lL7H6mNabvfZTX+5qm9
RDtxrNvLH+hZ+OPOp2qrfyJBaj/yP+4TTN4pC4y5Vqkq7sZ1fjfx9gZTsQLAvmr6
/c/Z59IlsAIvttbam7FFNrwVlWsD5uRP2DZyKXTjRRCA8NnBo9fltD1FbKKevcqu
PilMiyg8+dJnhKxOeMlw1WSx0h8FFU+jf4MFFX+qFsJB7Ecss1bWpnoYsaeKGMG7
mcOx5weglRlVccDQollZBXoIM/pDKJNrAbA8otKXbGGl1LJY20HZLNYPIRRlH2pe
YoLyhUi1AKFMecHxcGOIxlHVZ0gfEoWcChYvlWi6M/09c2Qtqq/QfKhD7DAXmMDS
xYFskyAAYSxgX2Q/5Y6mP+qRzDxT0Qm5JyN+UV0laqQ1KBA11+BF8RKriMGYSXy4
afDJAgMBAAGjVzBVMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFNv1CHU7dlRoE4Lh
/elJzmaSFpU5MA4GA1UdDwEB/wQEAwIF4DAWBgNVHSUBAf8EDDAKBggrBgEFBQcD
AjANBgkqhkiG9w0BAQsFAAOCAgEAoF0Jc770+dMNNiDyKsGOPgUJBsYMTyGqPmpd
7Nu7wmI+PBlgDkTvVZjU3EO/Y5Ez6fum5gCtf7OKPIYLfV95WBxgkkEvBEYaX4To
eL9nr9jP9AQ9sZocPTSCrlVrIeOT3tV683BY+N8sfHW6xIeI9tqTXTExCKmwuKyZ
+qyokn35Kkydyn47J4bclPD56UWctQinO2cXm2RVHkJlmQSoFREdb0S3xiFt8aAW
olB2xWMCwXb7LDyi5M0HCvz3lGErCTnpL9GBPjsWCSZOK55D/BSxL4NRSBqzsv4N
25SQOP2NgIqabRsYqYhTCRWK0n1h3IBAVh6fVQ2CCStd4gkuDUepTfM+R7mcYR9g
u2hn4kn+1i8y+Uj0z6yN48/i9Cnz3Sq/e8Z48Rbjut5Rx32ldFvHIkdtFjjkgv47
LbVKaYH4uqQF2xs3tAPuqq/QXNOn8Ie9yHv0MeJiPymIPAk6GBrUOA/Br4kof15v
uEbxeR/nnrzm+eyWMn4dsE0n7GA6wm2gMGENK4E8WK0sYujIAPtG8LHfShEv5f/j
77+3tAcigec39bau4yTkXBV8op1iMPBtEejLD0B5RKZig17Bfdw5v2TP+yGbzD5d
PwhAxn4aVK8zXFdYmwNfXNXBpLaEILxYFpeExaA9Gr5Mn/h+vD987GTW9F4fBhht
MtkfvRA=
-----END CERTIFICATE-----

View File

@@ -0,0 +1,51 @@
-----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY-----

View File

@@ -19,7 +19,7 @@ keyUsage = critical,digitalSignature,keyEncipherment,keyAgreement
subjectAltName = @server_alt_names
[server_alt_names]
DNS.1 = *.test.example.com
DNS.1 = *.httprunner.com
[test_client]
basicConstraints = critical,CA:FALSE

View File

@@ -0,0 +1,32 @@
-----BEGIN CERTIFICATE-----
MIIFdjCCA16gAwIBAgICA+gwDQYJKoZIhvcNAQELBQAwUDELMAkGA1UEBhMCVVMx
CzAJBgNVBAgMAkNBMQwwCgYDVQQHDANTVkwxDTALBgNVBAoMBGdSUEMxFzAVBgNV
BAMMDnRlc3Qtc2VydmVyX2NhMB4XDTIyMDcxMDA0MzAxNFoXDTMyMDcwNzA0MzAx
NFowTjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQwwCgYDVQQHDANTVkwxDTAL
BgNVBAoMBGdSUEMxFTATBgNVBAMMDHRlc3Qtc2VydmVyMTCCAiIwDQYJKoZIhvcN
AQEBBQADggIPADCCAgoCggIBAL0HTaTaYQ1GbvZ/Py3NJf3WSOzXdm/qh9Fv7hAs
8FGPEEDCRhrvFMjWqAwp3EiQkRavLgTv4t1hkga9y/hc7t/q9ATFm8SC3Dtdkg2X
0YdxsyotPaWgUSmsIJ0uwCIMkU5oGE1J2fopdBxG87T+QGUo1r4QxDQGQ2H9CMsD
217Ca+PdrdldctNs/D2AVkXTew1Bd/nNaOXh3vc14/4b86Y7A2HOFFyRi3QaemJJ
ksnH0CmhydRob5rAZQRClftzjri9gaUfJW5LSUYBXn3Yx1gam6lM5LcPlgWLmXs9
wthfksY6YlpCa1NtdnNbZIY+6cCHN6ytSPj/1BY8+C954cySSuNVSsAAvm8C80Zz
hnNaivhdouvmWTZM8febnrrt6qo0SEtnn+RkzUznOjVVxyPffgjI8s4gNc3DAIbf
oDwrAgxNF9nXAoeYTVOUxeGcjeG8fIKcfC7pxfI6/ejMiUU7LkL5rEIbfT2bF6EW
ntGyrxYRNdw+VX2MxNNvPKHUUu90JTCxzjaUCSnR4lhatcQPKeYVnn5I+jv6kMm5
FAkjVwk4U/u7W1DtCedaN9nUJNRWwptHqX2VXcnM0k9tA5yBtBM55yf0zYHz/fOz
RJ/bqHzbs5+il07u1uedMUJ9X9pp85Pm0PFD1zbv8MwZetTJigA4CdU4XU8K56Nz
Avc1AgMBAAGjXDBaMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFI0rfKZ3rjLJZ3R4
tv5NeYgJyiaqMA4GA1UdDwEB/wQEAwIDqDAbBgNVHREEFDASghAqLmh0dHBydW5u
ZXIuY29tMA0GCSqGSIb3DQEBCwUAA4ICAQCYbWsz11jUxABZDkQDNqGGpdAEJuaD
gAe3Ko28ntT+pjEdInD/YrfEjGI3KQhT00yMVkiWXiK8bBynZB3TpDUfG4OTBhAV
PZy/jQ08wOfmgFQco3asxQovimmKXVwbeJBOlZBfZoseB3h4zz7PcfLI9Xr8dz34
Pbilg+XOZywoxdHWd1To13ycKi9DPh81cRWu7QACS92wGGsX/eYVW7YKFmjcnj0I
2+WJl7nHD7h+Qyy6QiHmHa6/ZKAx2vkf2ALAHr4zKvIf+LLlQVTKGxtkyRMusiP+
sZuDq7RN5oYE5G1P5tF6Xb6AUGFrazaiC3kI0K3njs0xifjxiM+7KyfXQHOWV/a6
NNk9CX9twaKhq8Ay5jjILSUoXWgyl1OXOyIHIpWmsJMyGrQCapS5BZHGwc/K/6yW
TETmn6frJUh8VHJ+gjLvoUVMQvkJbV5IecMQaIfHBegRobi9TDkmjGC1v6+rpfjc
tVhQ7rUQgYtkuoOfRjwvCvY0UQ3hf73u/FCG/+Lw1b/Wcp8PMU+6vpZqlAaaFGVr
WHdrPHC0B0Sc3Pr6dmJp70KVb4gx45icRaJnPLR7sr5CBkorZs9NKXUzNnf9oZWF
Nfm5/isLCqLfwA+VTk78vyWqRycdDJ0lswxZt5pvwI3gXitOhlE6zXtsA883TwZ9
TxGOtJdjo0IEAQ==
-----END CERTIFICATE-----

View File

@@ -0,0 +1,51 @@
-----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY-----

View File

@@ -0,0 +1,567 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.28.0
// protoc v3.19.4
// source: grpc/proto/messager.proto
package messager
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type StreamRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"`
Data map[string]int64 `protobuf:"bytes,2,rep,name=data,proto3" json:"data,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"`
NodeID string `protobuf:"bytes,3,opt,name=NodeID,proto3" json:"NodeID,omitempty"`
}
func (x *StreamRequest) Reset() {
*x = StreamRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_grpc_proto_messager_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *StreamRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*StreamRequest) ProtoMessage() {}
func (x *StreamRequest) ProtoReflect() protoreflect.Message {
mi := &file_grpc_proto_messager_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use StreamRequest.ProtoReflect.Descriptor instead.
func (*StreamRequest) Descriptor() ([]byte, []int) {
return file_grpc_proto_messager_proto_rawDescGZIP(), []int{0}
}
func (x *StreamRequest) GetType() string {
if x != nil {
return x.Type
}
return ""
}
func (x *StreamRequest) GetData() map[string]int64 {
if x != nil {
return x.Data
}
return nil
}
func (x *StreamRequest) GetNodeID() string {
if x != nil {
return x.NodeID
}
return ""
}
type StreamResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"`
Profile []byte `protobuf:"bytes,2,opt,name=profile,proto3" json:"profile,omitempty"`
Data map[string]int64 `protobuf:"bytes,3,rep,name=data,proto3" json:"data,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"`
NodeID string `protobuf:"bytes,4,opt,name=NodeID,proto3" json:"NodeID,omitempty"`
Tasks []byte `protobuf:"bytes,5,opt,name=tasks,proto3" json:"tasks,omitempty"`
}
func (x *StreamResponse) Reset() {
*x = StreamResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_grpc_proto_messager_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *StreamResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*StreamResponse) ProtoMessage() {}
func (x *StreamResponse) ProtoReflect() protoreflect.Message {
mi := &file_grpc_proto_messager_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use StreamResponse.ProtoReflect.Descriptor instead.
func (*StreamResponse) Descriptor() ([]byte, []int) {
return file_grpc_proto_messager_proto_rawDescGZIP(), []int{1}
}
func (x *StreamResponse) GetType() string {
if x != nil {
return x.Type
}
return ""
}
func (x *StreamResponse) GetProfile() []byte {
if x != nil {
return x.Profile
}
return nil
}
func (x *StreamResponse) GetData() map[string]int64 {
if x != nil {
return x.Data
}
return nil
}
func (x *StreamResponse) GetNodeID() string {
if x != nil {
return x.NodeID
}
return ""
}
func (x *StreamResponse) GetTasks() []byte {
if x != nil {
return x.Tasks
}
return nil
}
type RegisterRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
NodeID string `protobuf:"bytes,1,opt,name=NodeID,proto3" json:"NodeID,omitempty"`
}
func (x *RegisterRequest) Reset() {
*x = RegisterRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_grpc_proto_messager_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *RegisterRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RegisterRequest) ProtoMessage() {}
func (x *RegisterRequest) ProtoReflect() protoreflect.Message {
mi := &file_grpc_proto_messager_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RegisterRequest.ProtoReflect.Descriptor instead.
func (*RegisterRequest) Descriptor() ([]byte, []int) {
return file_grpc_proto_messager_proto_rawDescGZIP(), []int{2}
}
func (x *RegisterRequest) GetNodeID() string {
if x != nil {
return x.NodeID
}
return ""
}
type RegisterResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Code string `protobuf:"bytes,1,opt,name=code,proto3" json:"code,omitempty"`
Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"`
}
func (x *RegisterResponse) Reset() {
*x = RegisterResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_grpc_proto_messager_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *RegisterResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RegisterResponse) ProtoMessage() {}
func (x *RegisterResponse) ProtoReflect() protoreflect.Message {
mi := &file_grpc_proto_messager_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RegisterResponse.ProtoReflect.Descriptor instead.
func (*RegisterResponse) Descriptor() ([]byte, []int) {
return file_grpc_proto_messager_proto_rawDescGZIP(), []int{3}
}
func (x *RegisterResponse) GetCode() string {
if x != nil {
return x.Code
}
return ""
}
func (x *RegisterResponse) GetMessage() string {
if x != nil {
return x.Message
}
return ""
}
type SignOutRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
NodeID string `protobuf:"bytes,1,opt,name=NodeID,proto3" json:"NodeID,omitempty"`
}
func (x *SignOutRequest) Reset() {
*x = SignOutRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_grpc_proto_messager_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *SignOutRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SignOutRequest) ProtoMessage() {}
func (x *SignOutRequest) ProtoReflect() protoreflect.Message {
mi := &file_grpc_proto_messager_proto_msgTypes[4]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SignOutRequest.ProtoReflect.Descriptor instead.
func (*SignOutRequest) Descriptor() ([]byte, []int) {
return file_grpc_proto_messager_proto_rawDescGZIP(), []int{4}
}
func (x *SignOutRequest) GetNodeID() string {
if x != nil {
return x.NodeID
}
return ""
}
type SignOutResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Code string `protobuf:"bytes,1,opt,name=code,proto3" json:"code,omitempty"`
Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"`
}
func (x *SignOutResponse) Reset() {
*x = SignOutResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_grpc_proto_messager_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *SignOutResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SignOutResponse) ProtoMessage() {}
func (x *SignOutResponse) ProtoReflect() protoreflect.Message {
mi := &file_grpc_proto_messager_proto_msgTypes[5]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SignOutResponse.ProtoReflect.Descriptor instead.
func (*SignOutResponse) Descriptor() ([]byte, []int) {
return file_grpc_proto_messager_proto_rawDescGZIP(), []int{5}
}
func (x *SignOutResponse) GetCode() string {
if x != nil {
return x.Code
}
return ""
}
func (x *SignOutResponse) GetMessage() string {
if x != nil {
return x.Message
}
return ""
}
var File_grpc_proto_messager_proto protoreflect.FileDescriptor
var file_grpc_proto_messager_proto_rawDesc = []byte{
0x0a, 0x19, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x6d, 0x65, 0x73,
0x73, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x07, 0x6d, 0x65, 0x73,
0x73, 0x61, 0x67, 0x65, 0x22, 0xaa, 0x01, 0x0a, 0x0d, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x34, 0x0a, 0x04, 0x64, 0x61,
0x74, 0x61, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61,
0x67, 0x65, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x2e, 0x44, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61,
0x12, 0x16, 0x0a, 0x06, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x44, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
0x52, 0x06, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x44, 0x1a, 0x37, 0x0a, 0x09, 0x44, 0x61, 0x74, 0x61,
0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38,
0x01, 0x22, 0xdc, 0x01, 0x0a, 0x0e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70,
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x66,
0x69, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x66, 0x69,
0x6c, 0x65, 0x12, 0x35, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b,
0x32, 0x21, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61,
0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x45, 0x6e,
0x74, 0x72, 0x79, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x16, 0x0a, 0x06, 0x4e, 0x6f, 0x64,
0x65, 0x49, 0x44, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x4e, 0x6f, 0x64, 0x65, 0x49,
0x44, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c,
0x52, 0x05, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x1a, 0x37, 0x0a, 0x09, 0x44, 0x61, 0x74, 0x61, 0x45,
0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28,
0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18,
0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01,
0x22, 0x29, 0x0a, 0x0f, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x44, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x06, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x44, 0x22, 0x40, 0x0a, 0x10, 0x52,
0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x63,
0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02,
0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x28, 0x0a,
0x0e, 0x53, 0x69, 0x67, 0x6e, 0x4f, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
0x16, 0x0a, 0x06, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x06, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x44, 0x22, 0x3f, 0x0a, 0x0f, 0x53, 0x69, 0x67, 0x6e, 0x4f,
0x75, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f,
0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x18,
0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x32, 0xe4, 0x01, 0x0a, 0x07, 0x4d, 0x65, 0x73,
0x73, 0x61, 0x67, 0x65, 0x12, 0x41, 0x0a, 0x08, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72,
0x12, 0x18, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73,
0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x6d, 0x65, 0x73,
0x73, 0x61, 0x67, 0x65, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3e, 0x0a, 0x07, 0x53, 0x69, 0x67, 0x6e, 0x4f,
0x75, 0x74, 0x12, 0x17, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x53, 0x69, 0x67,
0x6e, 0x4f, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x6d, 0x65,
0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x4f, 0x75, 0x74, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x56, 0x0a, 0x1d, 0x42, 0x69, 0x64, 0x69, 0x72,
0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e,
0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x16, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61,
0x67, 0x65, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x1a, 0x17, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61,
0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x42,
0x0f, 0x5a, 0x0d, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x72,
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_grpc_proto_messager_proto_rawDescOnce sync.Once
file_grpc_proto_messager_proto_rawDescData = file_grpc_proto_messager_proto_rawDesc
)
func file_grpc_proto_messager_proto_rawDescGZIP() []byte {
file_grpc_proto_messager_proto_rawDescOnce.Do(func() {
file_grpc_proto_messager_proto_rawDescData = protoimpl.X.CompressGZIP(file_grpc_proto_messager_proto_rawDescData)
})
return file_grpc_proto_messager_proto_rawDescData
}
var file_grpc_proto_messager_proto_msgTypes = make([]protoimpl.MessageInfo, 8)
var file_grpc_proto_messager_proto_goTypes = []interface{}{
(*StreamRequest)(nil), // 0: message.StreamRequest
(*StreamResponse)(nil), // 1: message.StreamResponse
(*RegisterRequest)(nil), // 2: message.RegisterRequest
(*RegisterResponse)(nil), // 3: message.RegisterResponse
(*SignOutRequest)(nil), // 4: message.SignOutRequest
(*SignOutResponse)(nil), // 5: message.SignOutResponse
nil, // 6: message.StreamRequest.DataEntry
nil, // 7: message.StreamResponse.DataEntry
}
var file_grpc_proto_messager_proto_depIdxs = []int32{
6, // 0: message.StreamRequest.data:type_name -> message.StreamRequest.DataEntry
7, // 1: message.StreamResponse.data:type_name -> message.StreamResponse.DataEntry
2, // 2: message.Message.Register:input_type -> message.RegisterRequest
4, // 3: message.Message.SignOut:input_type -> message.SignOutRequest
0, // 4: message.Message.BidirectionalStreamingMessage:input_type -> message.StreamRequest
3, // 5: message.Message.Register:output_type -> message.RegisterResponse
5, // 6: message.Message.SignOut:output_type -> message.SignOutResponse
1, // 7: message.Message.BidirectionalStreamingMessage:output_type -> message.StreamResponse
5, // [5:8] is the sub-list for method output_type
2, // [2:5] is the sub-list for method input_type
2, // [2:2] is the sub-list for extension type_name
2, // [2:2] is the sub-list for extension extendee
0, // [0:2] is the sub-list for field type_name
}
func init() { file_grpc_proto_messager_proto_init() }
func file_grpc_proto_messager_proto_init() {
if File_grpc_proto_messager_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_grpc_proto_messager_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*StreamRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_grpc_proto_messager_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*StreamResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_grpc_proto_messager_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*RegisterRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_grpc_proto_messager_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*RegisterResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_grpc_proto_messager_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*SignOutRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_grpc_proto_messager_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*SignOutResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_grpc_proto_messager_proto_rawDesc,
NumEnums: 0,
NumMessages: 8,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_grpc_proto_messager_proto_goTypes,
DependencyIndexes: file_grpc_proto_messager_proto_depIdxs,
MessageInfos: file_grpc_proto_messager_proto_msgTypes,
}.Build()
File_grpc_proto_messager_proto = out.File
file_grpc_proto_messager_proto_rawDesc = nil
file_grpc_proto_messager_proto_goTypes = nil
file_grpc_proto_messager_proto_depIdxs = nil
}

View File

@@ -0,0 +1,210 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.2.0
// - protoc v3.19.4
// source: grpc/proto/messager.proto
package messager
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
// MessageClient is the client API for Message service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type MessageClient interface {
Register(ctx context.Context, in *RegisterRequest, opts ...grpc.CallOption) (*RegisterResponse, error)
SignOut(ctx context.Context, in *SignOutRequest, opts ...grpc.CallOption) (*SignOutResponse, error)
BidirectionalStreamingMessage(ctx context.Context, opts ...grpc.CallOption) (Message_BidirectionalStreamingMessageClient, error)
}
type messageClient struct {
cc grpc.ClientConnInterface
}
func NewMessageClient(cc grpc.ClientConnInterface) MessageClient {
return &messageClient{cc}
}
func (c *messageClient) Register(ctx context.Context, in *RegisterRequest, opts ...grpc.CallOption) (*RegisterResponse, error) {
out := new(RegisterResponse)
err := c.cc.Invoke(ctx, "/message.Message/Register", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *messageClient) SignOut(ctx context.Context, in *SignOutRequest, opts ...grpc.CallOption) (*SignOutResponse, error) {
out := new(SignOutResponse)
err := c.cc.Invoke(ctx, "/message.Message/SignOut", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *messageClient) BidirectionalStreamingMessage(ctx context.Context, opts ...grpc.CallOption) (Message_BidirectionalStreamingMessageClient, error) {
stream, err := c.cc.NewStream(ctx, &Message_ServiceDesc.Streams[0], "/message.Message/BidirectionalStreamingMessage", opts...)
if err != nil {
return nil, err
}
x := &messageBidirectionalStreamingMessageClient{stream}
return x, nil
}
type Message_BidirectionalStreamingMessageClient interface {
Send(*StreamRequest) error
Recv() (*StreamResponse, error)
grpc.ClientStream
}
type messageBidirectionalStreamingMessageClient struct {
grpc.ClientStream
}
func (x *messageBidirectionalStreamingMessageClient) Send(m *StreamRequest) error {
return x.ClientStream.SendMsg(m)
}
func (x *messageBidirectionalStreamingMessageClient) Recv() (*StreamResponse, error) {
m := new(StreamResponse)
if err := x.ClientStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}
// MessageServer is the server API for Message service.
// All implementations must embed UnimplementedMessageServer
// for forward compatibility
type MessageServer interface {
Register(context.Context, *RegisterRequest) (*RegisterResponse, error)
SignOut(context.Context, *SignOutRequest) (*SignOutResponse, error)
BidirectionalStreamingMessage(Message_BidirectionalStreamingMessageServer) error
mustEmbedUnimplementedMessageServer()
}
// UnimplementedMessageServer must be embedded to have forward compatible implementations.
type UnimplementedMessageServer struct {
}
func (UnimplementedMessageServer) Register(context.Context, *RegisterRequest) (*RegisterResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Register not implemented")
}
func (UnimplementedMessageServer) SignOut(context.Context, *SignOutRequest) (*SignOutResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method SignOut not implemented")
}
func (UnimplementedMessageServer) BidirectionalStreamingMessage(Message_BidirectionalStreamingMessageServer) error {
return status.Errorf(codes.Unimplemented, "method BidirectionalStreamingMessage not implemented")
}
func (UnimplementedMessageServer) mustEmbedUnimplementedMessageServer() {}
// UnsafeMessageServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to MessageServer will
// result in compilation errors.
type UnsafeMessageServer interface {
mustEmbedUnimplementedMessageServer()
}
func RegisterMessageServer(s grpc.ServiceRegistrar, srv MessageServer) {
s.RegisterService(&Message_ServiceDesc, srv)
}
func _Message_Register_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(RegisterRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(MessageServer).Register(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/message.Message/Register",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(MessageServer).Register(ctx, req.(*RegisterRequest))
}
return interceptor(ctx, in, info, handler)
}
func _Message_SignOut_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(SignOutRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(MessageServer).SignOut(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/message.Message/SignOut",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(MessageServer).SignOut(ctx, req.(*SignOutRequest))
}
return interceptor(ctx, in, info, handler)
}
func _Message_BidirectionalStreamingMessage_Handler(srv interface{}, stream grpc.ServerStream) error {
return srv.(MessageServer).BidirectionalStreamingMessage(&messageBidirectionalStreamingMessageServer{stream})
}
type Message_BidirectionalStreamingMessageServer interface {
Send(*StreamResponse) error
Recv() (*StreamRequest, error)
grpc.ServerStream
}
type messageBidirectionalStreamingMessageServer struct {
grpc.ServerStream
}
func (x *messageBidirectionalStreamingMessageServer) Send(m *StreamResponse) error {
return x.ServerStream.SendMsg(m)
}
func (x *messageBidirectionalStreamingMessageServer) Recv() (*StreamRequest, error) {
m := new(StreamRequest)
if err := x.ServerStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}
// Message_ServiceDesc is the grpc.ServiceDesc for Message service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var Message_ServiceDesc = grpc.ServiceDesc{
ServiceName: "message.Message",
HandlerType: (*MessageServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "Register",
Handler: _Message_Register_Handler,
},
{
MethodName: "SignOut",
Handler: _Message_SignOut_Handler,
},
},
Streams: []grpc.StreamDesc{
{
StreamName: "BidirectionalStreamingMessage",
Handler: _Message_BidirectionalStreamingMessage_Handler,
ServerStreams: true,
ClientStreams: true,
},
},
Metadata: "grpc/proto/messager.proto",
}

View File

@@ -5,6 +5,8 @@ package message;
option go_package = "grpc/messager";
service Message {
rpc Register(RegisterRequest) returns (RegisterResponse) {}
rpc SignOut(SignOutRequest) returns (SignOutResponse) {}
rpc BidirectionalStreamingMessage(stream StreamRequest) returns (stream StreamResponse){};
}
@@ -20,4 +22,22 @@ message StreamResponse{
map<string, int64> data = 3;
string NodeID = 4;
bytes tasks = 5;
}
message RegisterRequest{
string NodeID = 1;
}
message RegisterResponse{
string code = 1;
string message = 2;
}
message SignOutRequest{
string NodeID = 1;
}
message SignOutResponse{
string code = 1;
string message = 2;
}

View File

@@ -18,9 +18,9 @@ type genericMessage struct {
Tasks []byte `json:"tasks,omitempty"`
}
type profileMessage struct {
Profile *Profile `json:"profile,omitempty"`
Tasks []byte `json:"tasks,omitempty"`
type task struct {
Profile *Profile `json:"profile,omitempty"`
TestCases []byte `json:"testcases,omitempty"`
}
func newGenericMessage(t string, data map[string]int64, nodeID string) (msg *genericMessage) {

View File

@@ -10,6 +10,10 @@ import (
"sync/atomic"
"time"
"github.com/httprunner/httprunner/v4/hrp/internal/boomer/grpc/messager"
"github.com/httprunner/httprunner/v4/hrp/internal/builtin"
"github.com/jinzhu/copier"
"github.com/go-errors/errors"
"github.com/olekukonko/tablewriter"
@@ -203,9 +207,21 @@ type runner struct {
// close this channel will stop all running workers.
stopChan chan bool
stoppingChan chan bool
doneChan chan bool
reportChan chan bool
// close this channel will stop all goroutines used in runner.
closeChan chan bool
// wgMu blocks concurrent waitgroup mutation while server stopping
wgMu sync.RWMutex
// wg is used to wait for the goroutines that depends on the server state
// to exit when stopping the server.
wg sync.WaitGroup
outputs []Output
once *sync.Once
@@ -343,11 +359,12 @@ func (r *runner) reportTestResult() {
}
func (r *runner) reset() {
r.updateState(StateInit)
r.controller.reset()
r.stats.clearAll()
r.rebalance = make(chan bool)
r.stopChan = make(chan bool)
r.stoppingChan = make(chan bool)
r.doneChan = make(chan bool)
r.reportChan = make(chan bool)
}
func (r *runner) spawnWorkers(spawnCount int64, spawnRate float64, quit chan bool, spawnCompleteFunc func()) {
@@ -376,7 +393,7 @@ func (r *runner) spawnWorkers(spawnCount int64, spawnRate float64, quit chan boo
if r.loop != nil {
workerLoop = &Loop{loopCount: atomic.LoadInt64(&r.loop.loopCount) / r.controller.spawnCount}
}
go func() {
r.goAttach(func() {
for {
select {
case <-quit:
@@ -402,8 +419,7 @@ func (r *runner) spawnWorkers(spawnCount int64, spawnRate float64, quit chan boo
// finished count of single worker
workerLoop.increaseFinishedCount()
if r.loop.isFinished() {
r.stop()
close(r.rebalance)
go r.stop()
}
}
if r.controller.erase() {
@@ -411,7 +427,7 @@ func (r *runner) spawnWorkers(spawnCount int64, spawnRate float64, quit chan boo
}
}
}
}()
})
continue
}
@@ -433,6 +449,27 @@ func (r *runner) spawnWorkers(spawnCount int64, spawnRate float64, quit chan boo
}
}
// goAttach creates a goroutine on a given function and tracks it using
// the runner waitgroup.
// The passed function should interrupt on r.StoppingNotify().
func (r *runner) goAttach(f func()) {
r.wgMu.RLock() // this blocks with ongoing close(s.stopping)
defer r.wgMu.RUnlock()
select {
case <-r.stoppingChan:
log.Warn().Msg("server has stopped; skipping GoAttach")
return
default:
}
// now safe to add since waitgroup wait has not started yet
r.wg.Add(1)
go func() {
defer r.wg.Done()
f()
}()
}
// setTasks will set the runner's task list AND the total task weight
// which is used to get a random task later
func (r *runner) setTasks(t []*Task) {
@@ -496,6 +533,7 @@ func (r *runner) statsStart() {
case <-ticker.C:
r.reportStats()
if !r.isStarted() {
close(r.reportChan)
log.Info().Msg("Quitting statsStart")
return
}
@@ -506,13 +544,49 @@ func (r *runner) statsStart() {
func (r *runner) stop() {
// stop previous goroutines without blocking
// those goroutines will exit when r.safeRun returns
close(r.stopChan)
r.Stop()
if r.rateLimitEnabled {
r.rateLimiter.Stop()
}
r.updateState(StateStopped)
}
// HardStop stops the server without coordination with other members in the cluster.
func (r *runner) hardStop() {
select {
case r.stopChan <- true:
case <-r.doneChan:
return
}
<-r.doneChan
}
// Stop stops the server gracefully, and shuts down the running goroutine.
// Stop should be called after a Start(s), otherwise it will block forever.
// When stopping leader, Stop transfers its leadership to one of its peers
// before stopping the server.
// Stop terminates the Server and performs any necessary finalization.
// Do and Process cannot be called after Stop has been invoked.
func (r *runner) Stop() {
r.hardStop()
}
// StopNotify returns a channel that receives a empty struct
// when the server is stopped.
func (r *runner) StopNotify() <-chan bool { return r.stopChan }
// DoneNotify returns a channel that receives a empty struct
// when the server is stopped.
func (r *runner) DoneNotify() <-chan bool { return r.doneChan }
// StoppingNotify returns a channel that receives a empty struct
// when the server is being stopped.
func (r *runner) StoppingNotify() <-chan bool { return r.stoppingChan }
// RebalanceNotify returns a channel that receives a empty struct
// when the server is being stopped.
func (r *runner) RebalanceNotify() <-chan bool { return r.rebalance }
func (r *runner) getState() int32 {
return atomic.LoadInt32(&r.state)
}
@@ -541,13 +615,17 @@ func newLocalRunner(spawnCount int64, spawnRate float64) *localRunner {
spawnRate: spawnRate,
controller: &Controller{},
outputs: make([]Output, 0),
stopChan: make(chan bool),
closeChan: make(chan bool),
once: &sync.Once{},
wg: sync.WaitGroup{},
wgMu: sync.RWMutex{},
},
}
}
func (r *localRunner) start() {
r.updateState(StateInit)
// init localRunner
r.reset()
@@ -558,34 +636,40 @@ func (r *localRunner) start() {
// output setup
r.outputOnStart()
go r.spawnWorkers(r.getSpawnCount(), r.getSpawnRate(), r.stopChan, nil)
go r.spawnWorkers(r.getSpawnCount(), r.getSpawnRate(), r.stoppingChan, nil)
defer func() {
r.wgMu.Lock() // block concurrent waitgroup adds in GoAttach while stopping
close(r.stoppingChan)
close(r.rebalance)
r.wgMu.Unlock()
// wait for goroutines before closing
r.wg.Wait()
r.updateState(StateStopping)
<-r.reportChan
// report test result
r.reportTestResult()
// output teardown
r.outputOnStop()
close(r.doneChan)
r.updateState(StateQuitting)
}()
// start stats report
r.statsStart()
go r.statsStart()
// stop
<-r.stopChan
r.updateState(StateStopped)
// stop rate limiter
if r.rateLimitEnabled {
r.rateLimiter.Stop()
}
// report test result
r.reportTestResult()
// output teardown
r.outputOnStop()
r.updateState(StateQuitting)
return
}
func (r *localRunner) stop() {
if r.runner.isStarted() {
r.runner.stop()
close(r.rebalance)
}
}
@@ -600,7 +684,7 @@ type workerRunner struct {
profile *Profile
tasksChan chan *profileMessage
tasksChan chan *task
mutex sync.Mutex
ignoreQuit bool
@@ -612,13 +696,14 @@ func newWorkerRunner(masterHost string, masterPort int) (r *workerRunner) {
stats: newRequestStats(),
outputs: make([]Output, 0),
controller: &Controller{},
stopChan: make(chan bool),
closeChan: make(chan bool),
once: &sync.Once{},
},
masterHost: masterHost,
masterPort: masterPort,
nodeID: getNodeID(),
tasksChan: make(chan *profileMessage, 10),
tasksChan: make(chan *task, 10),
mutex: sync.Mutex{},
ignoreQuit: false,
}
@@ -643,9 +728,9 @@ func (r *workerRunner) onSpawnMessage(msg *genericMessage) {
if msg.Tasks == nil && len(r.tasks) == 0 {
log.Error().Msg("miss tasks")
}
r.tasksChan <- &profileMessage{
Profile: profile,
Tasks: msg.Tasks,
r.tasksChan <- &task{
Profile: profile,
TestCases: msg.Tasks,
}
log.Info().Msg("on spawn message successful")
}
@@ -658,7 +743,7 @@ func (r *workerRunner) onRebalanceMessage(msg *genericMessage) {
r.setSpawnCount(profile.SpawnCount)
r.setSpawnRate(profile.SpawnRate)
r.tasksChan <- &profileMessage{
r.tasksChan <- &task{
Profile: profile,
}
log.Info().Msg("on rebalance message successful")
@@ -672,6 +757,9 @@ func (r *workerRunner) onMessage(msg *genericMessage) {
case "spawn":
r.onSpawnMessage(msg)
case "quit":
if r.ignoreQuit {
break
}
r.close()
}
case StateSpawning:
@@ -698,8 +786,10 @@ func (r *workerRunner) onMessage(msg *genericMessage) {
switch msg.Type {
case "spawn":
r.onSpawnMessage(msg)
go r.start()
case "quit":
if r.ignoreQuit {
break
}
r.close()
}
}
@@ -725,57 +815,88 @@ func (r *workerRunner) startListener() {
// run worker service
func (r *workerRunner) run() {
println("\n========================= HttpRunner Worker for Distributed Load Testing ========================= ")
r.updateState(StateInit)
r.client = newClient(r.masterHost, r.masterPort, r.nodeID)
err := r.client.connect()
println(fmt.Sprintf("ready to connect master to %s:%d", r.masterHost, r.masterPort))
err := r.client.start()
if err != nil {
log.Printf("Failed to connect to master(%s:%d) with error %v\n", r.masterHost, r.masterPort, err)
log.Error().Err(err).Msg(fmt.Sprintf("failed to connect to master(%s:%d) with error %v\n", r.masterHost, r.masterPort))
}
if err = r.client.register(r.client.config.ctx); err != nil {
log.Error().Err(err).Msg("failed to register")
}
err = r.client.newBiStreamClient()
if err != nil {
log.Error().Err(err).Msg("failed to establish bidirectional stream, waiting master launched")
}
go r.client.recv()
go r.client.send()
defer func() {
r.wg.Wait()
var ticker = time.NewTicker(1 * time.Second)
if r.client != nil {
// waitting for quit message is sent to master
select {
case <-r.client.disconnectedChannel():
case <-ticker.C:
log.Warn().Msg("Timeout waiting for sending quit message to master, boomer will quit any way.")
}
if err = r.client.signOut(r.client.config.ctx); err != nil {
log.Error().Err(err).Msg("failed to sign out")
}
r.client.close()
}
}()
// listen to master
go r.startListener()
// register worker information to master
r.client.sendChannel() <- newGenericMessage("register", nil, r.nodeID)
// tell master, I'm ready
log.Info().Msg("send client ready signal")
r.client.sendChannel() <- newClientReadyMessageToMaster(r.nodeID)
// heartbeat
// See: https://github.com/locustio/locust/commit/a8c0d7d8c588f3980303358298870f2ea394ab93
go func() {
var ticker = time.NewTicker(heartbeatInterval)
for {
select {
case <-ticker.C:
if atomic.LoadInt32(&r.client.failCount) > 2 {
r.updateState(StateMissing)
}
if r.getState() == StateMissing {
if r.client.reConnect() == nil {
r.updateState(StateInit)
}
}
CPUUsage := GetCurrentCPUUsage()
data := map[string]int64{
"state": int64(r.getState()),
"current_cpu_usage": int64(CPUUsage),
"spawn_count": r.controller.getCurrentClientsNum(),
}
r.client.sendChannel() <- newGenericMessage("heartbeat", data, r.nodeID)
case <-r.closeChan:
return
var ticker = time.NewTicker(heartbeatInterval)
for {
select {
case <-ticker.C:
if atomic.LoadInt32(&r.client.failCount) > 2 {
r.updateState(StateMissing)
}
if r.getState() == StateMissing {
err = r.client.register(r.client.config.ctx)
if err != nil {
continue
}
if r.client.newBiStreamClient() == nil {
r.updateState(StateInit)
}
}
CPUUsage := GetCurrentCPUUsage()
data := map[string]int64{
"state": int64(r.getState()),
"current_cpu_usage": int64(CPUUsage),
"spawn_count": r.controller.getCurrentClientsNum(),
}
r.client.sendChannel() <- newGenericMessage("heartbeat", data, r.nodeID)
case <-r.closeChan:
return
}
}()
<-r.closeChan
}
}
// start load test
func (r *workerRunner) start() {
r.mutex.Lock()
defer r.mutex.Unlock()
r.updateState(StateInit)
r.reset()
// start rate limiter
@@ -785,38 +906,42 @@ func (r *workerRunner) start() {
r.once.Do(r.outputOnStart)
go r.spawnWorkers(r.getSpawnCount(), r.getSpawnRate(), r.stopChan, r.spawnComplete)
go r.spawnWorkers(r.getSpawnCount(), r.getSpawnRate(), r.stoppingChan, r.spawnComplete)
defer func() {
r.wgMu.Lock() // block concurrent waitgroup adds in GoAttach while stopping
close(r.stoppingChan)
close(r.rebalance)
r.wgMu.Unlock()
// wait for goroutines before closing
r.wg.Wait()
r.updateState(StateStopping)
<-r.reportChan
r.reportTestResult()
r.outputOnStop()
close(r.doneChan)
}()
// start stats report
r.statsStart()
go r.statsStart()
r.reportTestResult()
r.outputOnStop()
<-r.stopChan
}
func (r *workerRunner) stop() {
if r.isStarted() {
r.runner.stop()
close(r.rebalance)
}
}
func (r *workerRunner) close() {
// waiting report finished
time.Sleep(1 * time.Second)
r.onQuiting()
close(r.closeChan)
var ticker = time.NewTicker(1 * time.Second)
if r.client != nil {
// waitting for quit message is sent to master
select {
case <-r.client.disconnectedChannel():
break
case <-ticker.C:
log.Warn().Msg("Timeout waiting for sending quit message to master, boomer will quit any way.")
r.onQuiting()
}
r.client.close()
}
}
// masterRunner controls worker to spawn goroutines and collect stats.
@@ -835,15 +960,18 @@ type masterRunner struct {
parseTestCasesChan chan bool
testCaseBytes chan []byte
// set profile to worker
profileBytes chan []byte
tcb []byte
}
func newMasterRunner(masterBindHost string, masterBindPort int) *masterRunner {
return &masterRunner{
runner: runner{
state: StateInit,
closeChan: make(chan bool),
state: StateInit,
stoppingChan: make(chan bool),
doneChan: make(chan bool),
closeChan: make(chan bool),
wg: sync.WaitGroup{},
wgMu: sync.RWMutex{},
},
masterBindHost: masterBindHost,
masterBindPort: masterBindPort,
@@ -908,9 +1036,6 @@ func (r *masterRunner) clientListener() {
}
switch msg.Type {
case typeClientReady:
if workerInfo.getState() == StateInit {
break
}
workerInfo.setState(StateInit)
if r.getState() == StateRunning {
log.Warn().Str("worker id", workerInfo.ID).Msg("worker joined, ready to rebalance the load of each worker")
@@ -975,40 +1100,52 @@ func (r *masterRunner) run() {
return
}
// listen and deal message from worker
go r.clientListener()
// listen and record heartbeat from worker
go r.heartbeatWorker()
defer func() {
r.wgMu.Lock() // block concurrent waitgroup adds in GoAttach while stopping
close(r.stoppingChan)
r.wgMu.Unlock()
r.wg.Wait()
r.server.close()
close(r.doneChan)
}()
if r.autoStart {
log.Info().Msg("auto start, waiting expected workers joined")
var ticker = time.NewTicker(1 * time.Second)
var tickerMaxWait = time.NewTicker(time.Duration(r.expectWorkersMaxWait) * time.Second)
FOR:
for {
select {
case <-r.closeChan:
return
case <-ticker.C:
c := r.server.getClientsLength()
log.Info().Msg(fmt.Sprintf("expected worker number: %v, current worker count: %v", r.expectWorkers, c))
if c >= r.expectWorkers {
go func() {
r.goAttach(func() {
log.Info().Msg("auto start, waiting expected workers joined")
var ticker = time.NewTicker(1 * time.Second)
var tickerMaxWait = time.NewTicker(time.Duration(r.expectWorkersMaxWait) * time.Second)
for {
select {
case <-r.closeChan:
return
case <-ticker.C:
c := r.server.getClientsLength()
log.Info().Msg(fmt.Sprintf("expected worker number: %v, current worker count: %v", r.expectWorkers, c))
if c >= r.expectWorkers {
err = r.start()
if err != nil {
log.Error().Err(err).Msg("failed to run")
os.Exit(1)
}
}()
break FOR
return
}
case <-tickerMaxWait.C:
log.Warn().Msg("reached max wait time, quiting")
r.onQuiting()
os.Exit(1)
}
case <-tickerMaxWait.C:
log.Warn().Msg("reached max wait time, quiting")
r.onQuiting()
os.Exit(1)
}
}
})
}
// listen and deal message from worker
r.goAttach(r.clientListener)
// listen and record heartbeat from worker
r.heartbeatWorker()
<-r.closeChan
}
@@ -1018,17 +1155,48 @@ func (r *masterRunner) start() error {
return errors.New("current workers: 0")
}
log.Info().Msg("send spawn data to worker")
r.updateState(StateSpawning)
// fetching testcase
testcase, err := r.fetchTestCase()
if err != nil {
return err
}
profile := r.profile.dispatch(int64(numWorkers))
r.server.sendChannel() <- newMessageToWorker("spawn", ProfileToBytes(profile), nil, testcase)
log.Warn().Interface("profile", profile).Msg("send spawn data to worker successful")
workerProfile := &Profile{}
if err := copier.Copy(workerProfile, r.profile); err != nil {
log.Error().Err(err).Msg("copy workerProfile failed")
return err
}
cur := 0
ints := builtin.SplitInteger(int(r.profile.SpawnCount), numWorkers)
log.Info().Msg("send spawn data to worker")
r.updateState(StateSpawning)
r.server.clients.Range(func(key, value interface{}) bool {
if workerInfo, ok := value.(*WorkerNode); ok {
if workerInfo.getState() == StateQuitting || workerInfo.getState() == StateMissing {
return true
}
if workerProfile.SpawnCount > 0 {
workerProfile.SpawnCount = int64(ints[cur])
}
if workerProfile.SpawnRate > 0 {
workerProfile.SpawnRate = workerProfile.SpawnRate / float64(numWorkers)
}
if workerProfile.MaxRPS > 0 {
workerProfile.MaxRPS = workerProfile.MaxRPS / int64(numWorkers)
}
workerInfo.getStream() <- &messager.StreamResponse{
Type: "spawn",
Profile: ProfileToBytes(workerProfile),
Data: map[string]int64{},
NodeID: workerInfo.ID,
Tasks: testcase,
}
cur++
}
return true
})
log.Warn().Interface("profile", r.profile).Msg("send spawn data to worker successful")
return nil
}
@@ -1037,9 +1205,49 @@ func (r *masterRunner) rebalance() error {
if numWorkers == 0 {
return errors.New("current workers: 0")
}
profile := r.profile.dispatch(int64(numWorkers))
workerProfile := &Profile{}
if err := copier.Copy(workerProfile, r.profile); err != nil {
log.Error().Err(err).Msg("copy workerProfile failed")
return err
}
cur := 0
ints := builtin.SplitInteger(int(r.profile.SpawnCount), numWorkers)
log.Info().Msg("send spawn data to worker")
r.server.clients.Range(func(key, value interface{}) bool {
if workerInfo, ok := value.(*WorkerNode); ok {
if workerInfo.getState() == StateQuitting || workerInfo.getState() == StateMissing {
return true
}
if workerProfile.SpawnCount > 0 {
workerProfile.SpawnCount = int64(ints[cur])
}
if workerProfile.SpawnRate > 0 {
workerProfile.SpawnRate = workerProfile.SpawnRate / float64(numWorkers)
}
if workerProfile.MaxRPS > 0 {
workerProfile.MaxRPS = workerProfile.MaxRPS / int64(numWorkers)
}
if workerInfo.getState() == StateInit {
workerInfo.getStream() <- &messager.StreamResponse{
Type: "spawn",
Profile: ProfileToBytes(workerProfile),
Data: map[string]int64{},
NodeID: workerInfo.ID,
Tasks: r.tcb,
}
} else {
workerInfo.getStream() <- &messager.StreamResponse{
Type: "rebalance",
Profile: ProfileToBytes(workerProfile),
Data: map[string]int64{},
NodeID: workerInfo.ID,
}
}
cur++
}
return true
})
r.server.sendChannel() <- newMessageToWorker("rebalance", ProfileToBytes(profile), nil, nil)
log.Warn().Msg("send rebalance data to worker successful")
return nil
}
@@ -1054,6 +1262,7 @@ func (r *masterRunner) fetchTestCase() ([]byte, error) {
case <-ticker.C:
return nil, errors.New("parse testcases timeout")
case tcb := <-r.testCaseBytes:
r.tcb = tcb
return tcb, nil
}
}
@@ -1061,8 +1270,7 @@ func (r *masterRunner) fetchTestCase() ([]byte, error) {
func (r *masterRunner) stop() error {
if r.isStarted() {
r.updateState(StateStopping)
r.server.sendChannel() <- &genericMessage{Type: "stop", Data: map[string]int64{}}
r.updateState(StateStopped)
r.server.sendBroadcasts(&genericMessage{Type: "stop", Data: map[string]int64{}})
return nil
} else {
return errors.New("already stopped")
@@ -1071,24 +1279,22 @@ func (r *masterRunner) stop() error {
func (r *masterRunner) onQuiting() {
if r.getState() != StateQuitting {
r.server.sendChannel() <- &genericMessage{
r.server.sendBroadcasts(&genericMessage{
Type: "quit",
}
})
}
r.updateState(StateQuitting)
}
func (r *masterRunner) close() {
r.onQuiting()
r.server.wg.Wait()
close(r.closeChan)
r.server.close()
}
func (r *masterRunner) reportStats() {
currentTime := time.Now()
println()
println("===================== HttpRunner Master for Distributed Load Testing ===================== ")
println("========================= HttpRunner Master for Distributed Load Testing ========================= ")
println(fmt.Sprintf("Current time: %s, State: %v, Current Available Workers: %v, Target Users: %v",
currentTime.Format("2006/01/02 15:04:05"), getStateName(r.getState()), r.server.getClientsLength(), r.getSpawnCount()))
table := tablewriter.NewWriter(os.Stdout)

View File

@@ -6,6 +6,7 @@ import (
"testing"
"time"
"github.com/httprunner/httprunner/v4/hrp/internal/boomer/grpc/messager"
"github.com/stretchr/testify/assert"
)
@@ -113,6 +114,32 @@ func TestLoopCount(t *testing.T) {
}
}
func TestStopNotify(t *testing.T) {
r := &localRunner{
runner: runner{
stopChan: make(chan bool),
doneChan: make(chan bool),
},
}
go func() {
<-r.stopChan
close(r.doneChan)
}()
notifier := r.DoneNotify()
select {
case <-notifier:
t.Fatalf("received unexpected stop notification")
default:
}
r.Stop()
select {
case <-notifier:
default:
t.Fatalf("cannot receive stop notification")
}
}
func TestSpawnWorkers(t *testing.T) {
taskA := &Task{
Weight: 10,
@@ -239,7 +266,8 @@ func TestSpawnAndStop(t *testing.T) {
if msg.Type != "spawning_complete" {
t.Error("Runner should send spawning_complete message when spawning completed, got", msg.Type)
}
runner.stop()
go runner.stop()
close(runner.doneChan)
runner.onQuiting()
msg = <-runner.client.sendChannel()
@@ -260,10 +288,11 @@ func TestStop(t *testing.T) {
runner.reset()
runner.updateState(StateSpawning)
runner.stop()
go runner.stop()
close(runner.doneChan)
time.Sleep(1 * time.Second)
if runner.getState() != StateStopped {
t.Error("Expected runner state to be 5, was", runner.getState())
t.Error("Expected runner state to be 5, was", getStateName(runner.getState()))
}
}
@@ -305,7 +334,8 @@ func TestOnQuitMessage(t *testing.T) {
runner.reset()
runner.closeChan = make(chan bool)
runner.client.shutdownChan = make(chan bool)
runner.onMessage(newGenericMessage("quit", nil, runner.nodeID))
go runner.onMessage(newGenericMessage("quit", nil, runner.nodeID))
close(runner.doneChan)
<-runner.closeChan
if runner.getState() != StateQuitting {
t.Error("Runner's state should be StateQuitting")
@@ -359,7 +389,7 @@ func TestOnMessage(t *testing.T) {
t.Error("Runner should send spawning_complete message when spawn completed, got", msg.Type)
}
if runner.getState() != StateRunning {
t.Error("State of runner is not running after spawn, got", runner.getState())
t.Error("State of runner is not running after spawn, got", getStateName(runner.getState()))
}
// increase goroutines while running
@@ -368,7 +398,7 @@ func TestOnMessage(t *testing.T) {
time.Sleep(2 * time.Second)
if runner.getState() != StateRunning {
t.Error("State of runner is not running after spawn, got", runner.getState())
t.Error("State of runner is not running after spawn, got", getStateName(runner.getState()))
}
if runner.controller.getCurrentClientsNum() != 15 {
t.Error("Number of goroutines mismatches, expected: 15, current count:", runner.controller.getCurrentClientsNum())
@@ -377,7 +407,7 @@ func TestOnMessage(t *testing.T) {
// stop all the workers
runner.onMessage(newGenericMessage("stop", nil, runner.nodeID))
if runner.getState() != StateStopped {
t.Error("State of runner is not stopped, got", runner.getState())
t.Error("State of runner is not stopped, got", getStateName(runner.getState()))
}
msg = <-runner.client.sendChannel()
if msg.Type != "client_stopped" {
@@ -401,7 +431,7 @@ func TestOnMessage(t *testing.T) {
t.Error("Number of goroutines mismatches, expected: 10, current count:", runner.controller.getCurrentClientsNum())
}
if runner.getState() != StateRunning {
t.Error("State of runner is not running after spawn, got", runner.getState())
t.Error("State of runner is not running after spawn, got", getStateName(runner.getState()))
}
msg = <-runner.client.sendChannel()
if msg.Type != "spawning_complete" {
@@ -411,7 +441,7 @@ func TestOnMessage(t *testing.T) {
// stop all the workers
runner.onMessage(newGenericMessage("stop", nil, runner.nodeID))
if runner.getState() != StateStopped {
t.Error("State of runner is not stopped, got", runner.getState())
t.Error("State of runner is not stopped, got", getStateName(runner.getState()))
}
msg = <-runner.client.sendChannel()
if msg.Type != "client_stopped" {
@@ -430,8 +460,8 @@ func TestClientListener(t *testing.T) {
runner.setSpawnCount(10)
runner.setSpawnRate(10)
go runner.clientListener()
runner.server.clients.Store("testID1", &WorkerNode{ID: "testID1", Heartbeat: 3})
runner.server.clients.Store("testID2", &WorkerNode{ID: "testID2", Heartbeat: 3})
runner.server.clients.Store("testID1", &WorkerNode{ID: "testID1", Heartbeat: 3, stream: make(chan *messager.StreamResponse, 10)})
runner.server.clients.Store("testID2", &WorkerNode{ID: "testID2", Heartbeat: 3, stream: make(chan *messager.StreamResponse, 10)})
runner.server.recvChannel() <- &genericMessage{
Type: typeClientReady,
NodeID: "testID1",
@@ -470,7 +500,7 @@ func TestClientListener(t *testing.T) {
}
time.Sleep(time.Second)
if runner.getState() != StateStopped {
t.Error("State of master runner is not stopped, got", runner.getState())
t.Error("State of master runner is not stopped, got", getStateName(runner.getState()))
}
}
@@ -480,8 +510,8 @@ func TestHeartbeatWorker(t *testing.T) {
runner.updateState(StateInit)
runner.setSpawnCount(10)
runner.setSpawnRate(10)
runner.server.clients.Store("testID1", &WorkerNode{ID: "testID1", Heartbeat: 1, State: StateInit})
runner.server.clients.Store("testID2", &WorkerNode{ID: "testID2", Heartbeat: 1, State: StateInit})
runner.server.clients.Store("testID1", &WorkerNode{ID: "testID1", Heartbeat: 1, State: StateInit, stream: make(chan *messager.StreamResponse, 10)})
runner.server.clients.Store("testID2", &WorkerNode{ID: "testID2", Heartbeat: 1, State: StateInit, stream: make(chan *messager.StreamResponse, 10)})
go runner.clientListener()
go runner.heartbeatWorker()
time.Sleep(3 * time.Second)

View File

@@ -1 +0,0 @@
package boomer

View File

@@ -3,7 +3,6 @@ package boomer
import (
"context"
"fmt"
"io"
"net"
"strings"
"sync"
@@ -17,106 +16,11 @@ import (
"google.golang.org/grpc/reflection"
"google.golang.org/grpc/status"
"github.com/httprunner/httprunner/v4/hrp/internal/data"
"github.com/httprunner/httprunner/v4/hrp/internal/grpc/messager"
"github.com/httprunner/httprunner/v4/hrp/internal/boomer/data"
"github.com/httprunner/httprunner/v4/hrp/internal/boomer/grpc/messager"
"github.com/rs/zerolog/log"
)
var (
errMissingMetadata = status.Errorf(codes.InvalidArgument, "missing metadata")
errInvalidToken = status.Errorf(codes.Unauthenticated, "invalid token")
)
// valid validates the authorization.
func valid(authorization []string) bool {
if len(authorization) < 1 {
return false
}
token := strings.TrimPrefix(authorization[0], "Bearer ")
// Perform the token validation here. For the sake of this example, the code
// here forgoes any of the usual OAuth2 token validation and instead checks
// for a token matching an arbitrary string.
return token == "httprunner-secret-token"
}
func serverUnaryInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
// authentication (token verification)
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
return nil, errMissingMetadata
}
if !valid(md["authorization"]) {
return nil, errInvalidToken
}
m, err := handler(ctx, req)
if err != nil {
logger("RPC failed with error %v", err)
}
return m, err
}
// serverWrappedStream wraps around the embedded grpc.ServerStream, and intercepts the RecvMsg and
// SendMsg method call.
type serverWrappedStream struct {
grpc.ServerStream
}
func (w *serverWrappedStream) RecvMsg(m interface{}) error {
logger("Receive a message (Type: %T) at %s", m, time.Now().Format(time.RFC3339))
return w.ServerStream.RecvMsg(m)
}
func (w *serverWrappedStream) SendMsg(m interface{}) error {
logger("Send a message (Type: %T) at %v", m, time.Now().Format(time.RFC3339))
return w.ServerStream.SendMsg(m)
}
func newServerWrappedStream(s grpc.ServerStream) grpc.ServerStream {
return &serverWrappedStream{s}
}
func serverStreamInterceptor(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
// authentication (token verification)
md, ok := metadata.FromIncomingContext(ss.Context())
if !ok {
return errMissingMetadata
}
if !valid(md["authorization"]) {
return errInvalidToken
}
err := handler(srv, newServerWrappedStream(ss))
if err != nil {
logger("RPC failed with error %v", err)
}
return err
}
func (s *grpcServer) BidirectionalStreamingMessage(srv messager.Message_BidirectionalStreamingMessageServer) error {
s.wg.Add(1)
defer s.wg.Done()
req, err := srv.Recv()
switch err {
case nil:
break
case io.EOF:
return nil
default:
if err.Error() == status.Error(codes.Canceled, context.Canceled.Error()).Error() {
return nil
}
log.Error().Err(err).Msg("failed to get stream from client")
return err
}
wn := &WorkerNode{messenger: srv, ID: req.NodeID, Heartbeat: 3}
s.clients.Store(req.NodeID, wn)
log.Warn().Str("worker id", req.NodeID).Msg("worker joined")
<-s.disconnectedChannel()
s.clients.Delete(req.NodeID)
log.Warn().Str("worker id", req.NodeID).Msg("worker quited")
return nil
}
type WorkerNode struct {
ID string `json:"id"`
State int32 `json:"state"`
@@ -125,8 +29,14 @@ type WorkerNode struct {
CPUUsage float64 `json:"cpu_usage"`
CPUWarningEmitted bool `json:"cpu_warning_emitted"`
MemoryUsage float64 `json:"memory_usage"`
messenger messager.Message_BidirectionalStreamingMessageServer
stream chan *messager.StreamResponse
mutex sync.RWMutex
disconnectedChan chan bool
}
func newWorkerNode(id string) *WorkerNode {
stream := make(chan *messager.StreamResponse, 100)
return &WorkerNode{State: StateInit, ID: id, Heartbeat: 3, stream: stream, disconnectedChan: make(chan bool)}
}
func (w *WorkerNode) getState() int32 {
@@ -189,6 +99,18 @@ func (w *WorkerNode) getMemoryUsage() float64 {
return w.MemoryUsage
}
func (w *WorkerNode) setStream(stream chan *messager.StreamResponse) {
w.mutex.RLock()
defer w.mutex.RUnlock()
w.stream = stream
}
func (w *WorkerNode) getStream() chan *messager.StreamResponse {
w.mutex.RLock()
defer w.mutex.RUnlock()
return w.stream
}
func (w *WorkerNode) getWorkerInfo() WorkerNode {
w.mutex.RLock()
defer w.mutex.RUnlock()
@@ -208,25 +130,95 @@ type grpcServer struct {
masterHost string
masterPort int
server *grpc.Server
secure bool
clients *sync.Map
fromWorker chan *genericMessage
toWorker chan *genericMessage
disconnectedToWorker chan bool
shutdownChan chan bool
wg sync.WaitGroup
fromWorker chan *genericMessage
disconnectedChan chan bool
shutdownChan chan bool
wg *sync.WaitGroup
}
var (
errMissingMetadata = status.Errorf(codes.InvalidArgument, "missing metadata")
errInvalidToken = status.Errorf(codes.Unauthenticated, "invalid token")
)
func logger(format string, a ...interface{}) {
log.Info().Msg(fmt.Sprintf(format, a...))
}
// valid validates the authorization.
func valid(authorization []string) bool {
if len(authorization) < 1 {
return false
}
token := strings.TrimPrefix(authorization[0], "Bearer ")
return token == "httprunner-secret-token"
}
func serverUnaryInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
// authentication (token verification)
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
return nil, errMissingMetadata
}
if !valid(md["authorization"]) {
return nil, errInvalidToken
}
m, err := handler(ctx, req)
if err != nil {
logger("RPC failed with error %v", err)
}
return m, err
}
// serverWrappedStream wraps around the embedded grpc.ServerStream, and intercepts the RecvMsg and
// SendMsg method call.
type serverWrappedStream struct {
grpc.ServerStream
}
func (w *serverWrappedStream) RecvMsg(m interface{}) error {
logger("Receive a message (Type: %T) at %s", m, time.Now().Format(time.RFC3339))
return w.ServerStream.RecvMsg(m)
}
func (w *serverWrappedStream) SendMsg(m interface{}) error {
logger("Send a message (Type: %T) at %v", m, time.Now().Format(time.RFC3339))
return w.ServerStream.SendMsg(m)
}
func newServerWrappedStream(s grpc.ServerStream) grpc.ServerStream {
return &serverWrappedStream{s}
}
func serverStreamInterceptor(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
// authentication (token verification)
md, ok := metadata.FromIncomingContext(ss.Context())
if !ok {
return errMissingMetadata
}
if !valid(md["authorization"]) {
return errInvalidToken
}
err := handler(srv, newServerWrappedStream(ss))
if err != nil {
logger("RPC failed with error %v", err)
}
return err
}
func newServer(masterHost string, masterPort int) (server *grpcServer) {
log.Info().Msg("Boomer is built with grpc support.")
server = &grpcServer{
masterHost: masterHost,
masterPort: masterPort,
clients: &sync.Map{},
fromWorker: make(chan *genericMessage, 100),
toWorker: make(chan *genericMessage, 100),
disconnectedToWorker: make(chan bool),
shutdownChan: make(chan bool),
masterHost: masterHost,
masterPort: masterPort,
clients: &sync.Map{},
fromWorker: make(chan *genericMessage, 100),
disconnectedChan: make(chan bool),
shutdownChan: make(chan bool),
}
return server
}
@@ -250,25 +242,179 @@ func (s *grpcServer) start() (err error) {
return
}
// create gRPC server
serv := grpc.NewServer(opts...)
s.server = grpc.NewServer(opts...)
// register message server
messager.RegisterMessageServer(serv, s)
reflection.Register(serv)
messager.RegisterMessageServer(s.server, s)
reflection.Register(s.server)
// start grpc server
go func() {
err = serv.Serve(lis)
err = s.server.Serve(lis)
if err != nil {
log.Error().Err(err).Msg("failed to serve")
return
}
}()
go s.recv()
go s.send()
return nil
}
func (s *grpcServer) Register(_ context.Context, req *messager.RegisterRequest) (*messager.RegisterResponse, error) {
// store worker information
wn := newWorkerNode(req.NodeID)
s.clients.Store(req.NodeID, wn)
log.Warn().Str("worker id", req.NodeID).Msg("worker joined")
return &messager.RegisterResponse{Code: "0", Message: "register successfully"}, nil
}
func (s *grpcServer) SignOut(_ context.Context, req *messager.SignOutRequest) (*messager.SignOutResponse, error) {
// delete worker information
s.clients.Delete(req.NodeID)
log.Warn().Str("worker id", req.NodeID).Msg("worker quited")
return &messager.SignOutResponse{Code: "0", Message: "sign out successfully"}, nil
}
func (s *grpcServer) valid(token string) (isValid bool) {
s.clients.Range(func(key, value interface{}) bool {
if workerInfo, ok := value.(*WorkerNode); ok {
if workerInfo.ID == token {
isValid = true
}
}
return true
})
return
}
func (s *grpcServer) BidirectionalStreamingMessage(srv messager.Message_BidirectionalStreamingMessageServer) error {
token, ok := extractToken(srv.Context())
if !ok {
return status.Error(codes.Unauthenticated, "missing token header")
}
ok = s.valid(token)
if !ok {
return status.Error(codes.Unauthenticated, "invalid token")
}
go s.sendMsg(srv, token)
FOR:
for {
msg, err := srv.Recv()
if st, ok := status.FromError(err); ok {
switch st.Code() {
case codes.OK:
s.fromWorker <- newGenericMessage(msg.Type, msg.Data, msg.NodeID)
log.Info().
Str("nodeID", msg.NodeID).
Str("type", msg.Type).
Interface("data", msg.Data).
Msg("receive data from worker")
case codes.Unavailable, codes.Canceled, codes.DeadlineExceeded:
s.fromWorker <- newQuitMessage(token)
break FOR
default:
log.Error().Err(err).Msg("failed to get stream from client")
break FOR
}
}
}
// disconnected to worker
select {
case <-srv.Context().Done():
return srv.Context().Err()
case <-s.disconnectedChan:
}
log.Warn().Str("worker id", token).Msg("worker quited")
return nil
}
func (s *grpcServer) sendMsg(srv messager.Message_BidirectionalStreamingMessageServer, id string) {
stream := s.getWorkersByID(id).getStream()
for {
select {
case <-srv.Context().Done():
return
case res := <-stream:
if s, ok := status.FromError(srv.Send(res)); ok {
switch s.Code() {
case codes.OK:
log.Info().
Str("nodeID", res.NodeID).
Str("type", res.Type).
Interface("data", res.Data).
Interface("profile", res.Profile).
Msg("send data to worker")
case codes.Unavailable, codes.Canceled, codes.DeadlineExceeded:
log.Warn().Msg(fmt.Sprintf("client (%s) terminated connection", id))
return
default:
log.Warn().Msg(fmt.Sprintf("failed to send to client (%s): %v", id, s.Err()))
return
}
}
}
}
}
func (s *grpcServer) sendBroadcasts(msg *genericMessage) {
s.clients.Range(func(key, value interface{}) bool {
if workerInfo, ok := value.(*WorkerNode); ok {
if workerInfo.getState() == StateQuitting || workerInfo.getState() == StateMissing {
return true
}
workerInfo.getStream() <- &messager.StreamResponse{
Type: msg.Type,
Profile: msg.Profile,
Data: msg.Data,
NodeID: workerInfo.ID,
Tasks: msg.Tasks,
}
}
return true
})
}
func (s *grpcServer) stopServer(ctx context.Context) {
ch := make(chan struct{})
go func() {
defer close(ch)
// close listeners to stop accepting new connections,
// will block on any existing transports
s.server.GracefulStop()
}()
// wait until all pending RPCs are finished
select {
case <-ch:
case <-ctx.Done():
// took too long, manually close open transports
// e.g. watch streams
s.server.Stop()
// concurrent GracefulStop should be interrupted
<-ch
}
}
func (s *grpcServer) close() {
// close client requests with request timeout
timeout := 2 * time.Second
ctx, cancel := context.WithTimeout(context.Background(), timeout)
s.stopServer(ctx)
cancel()
}
func (s *grpcServer) recvChannel() chan *genericMessage {
return s.fromWorker
}
func (s *grpcServer) shutdownChannel() chan bool {
return s.shutdownChan
}
func (s *grpcServer) disconnectedChannel() chan bool {
return s.disconnectedChan
}
func (s *grpcServer) getWorkersByState(state int32) (wns []*WorkerNode) {
s.clients.Range(func(key, value interface{}) bool {
if workerInfo, ok := value.(*WorkerNode); ok {
@@ -281,6 +427,18 @@ func (s *grpcServer) getWorkersByState(state int32) (wns []*WorkerNode) {
return wns
}
func (s *grpcServer) getWorkersByID(id string) (wn *WorkerNode) {
s.clients.Range(func(key, value interface{}) bool {
if workerInfo, ok := value.(*WorkerNode); ok {
if workerInfo.ID == id {
wn = workerInfo
}
}
return true
})
return wn
}
func (s *grpcServer) getWorkersLengthByState(state int32) (l int) {
s.clients.Range(func(key, value interface{}) bool {
if workerInfo, ok := value.(*WorkerNode); ok {
@@ -318,113 +476,3 @@ func (s *grpcServer) getClientsLength() (l int) {
})
return
}
func (s *grpcServer) close() {
close(s.shutdownChan)
}
func (s *grpcServer) recvChannel() chan *genericMessage {
return s.fromWorker
}
func (s *grpcServer) shutdownChannel() chan bool {
return s.shutdownChan
}
func (s *grpcServer) recv() {
for {
select {
case <-s.shutdownChan:
return
default:
s.clients.Range(func(key, value interface{}) bool {
if workerInfo, ok := value.(*WorkerNode); ok {
if workerInfo.getState() == StateQuitting || workerInfo.getState() == StateMissing {
return true
}
msg, err := workerInfo.messenger.Recv()
switch err {
case nil:
if msg == nil {
return true
}
s.fromWorker <- newGenericMessage(msg.Type, msg.Data, msg.NodeID)
log.Info().
Str("nodeID", msg.NodeID).
Str("type", msg.Type).
Interface("data", msg.Data).
Msg("receive data from worker")
case io.EOF:
s.fromWorker <- newQuitMessage(workerInfo.ID)
default:
if err.Error() == status.Error(codes.Canceled, context.Canceled.Error()).Error() {
s.fromWorker <- newQuitMessage(workerInfo.ID)
return true
}
log.Error().Err(err).Msg("failed to get stream from client")
}
}
return true
})
}
}
}
func (s *grpcServer) sendChannel() chan *genericMessage {
return s.toWorker
}
func (s *grpcServer) send() {
for {
select {
case <-s.shutdownChan:
return
case msg := <-s.toWorker:
s.sendMessage(msg)
// We may send genericMessage to Worker.
if msg.Type == "quit" {
close(s.disconnectedToWorker)
}
}
}
}
func (s *grpcServer) sendMessage(msg *genericMessage) {
s.clients.Range(func(key, value interface{}) bool {
if workerInfo, ok := value.(*WorkerNode); ok {
if workerInfo.getState() == StateQuitting || workerInfo.getState() == StateMissing {
return true
}
err := workerInfo.messenger.Send(
&messager.StreamResponse{
Type: msg.Type,
Profile: msg.Profile,
Data: msg.Data,
NodeID: workerInfo.ID,
Tasks: msg.Tasks},
)
switch err {
case nil:
break
case io.EOF:
fallthrough
default:
s.fromWorker <- newQuitMessage(workerInfo.ID)
log.Error().Err(err).Msg("failed to send message")
return true
}
log.Info().
Str("nodeID", workerInfo.ID).
Str("type", msg.Type).
Interface("data", msg.Data).
Int32("state", workerInfo.getState()).
Msg("send data to worker")
}
return true
})
}
func (s *grpcServer) disconnectedChannel() chan bool {
return s.disconnectedToWorker
}

View File

@@ -94,12 +94,12 @@ func GetCurrentCPUUsage() float64 {
currentPid := os.Getpid()
p, err := process.NewProcess(int32(currentPid))
if err != nil {
log.Printf("Fail to get CPU percent, %v\n", err)
log.Error().Err(err).Msg(fmt.Sprintf("failed to get CPU percent\n"))
return 0.0
}
percent, err := p.CPUPercent()
if err != nil {
log.Printf("Fail to get CPU percent, %v\n", err)
log.Error().Err(err).Msg(fmt.Sprintf("failed to get CPU percent\n"))
return 0.0
}
return percent / float64(runtime.NumCPU())

View File

@@ -504,3 +504,25 @@ func Bytes2File(data []byte, filename string) error {
log.Info().Msg(fmt.Sprintf("write file %s len: %d \n", filename, count))
return nil
}
func SplitInteger(m, n int) (ints []int) {
quotient := m / n
remainder := m % n
if remainder >= 0 {
for i := 0; i < n-remainder; i++ {
ints = append(ints, quotient)
}
for i := 0; i < remainder; i++ {
ints = append(ints, quotient+1)
}
return
} else if remainder < 0 {
for i := 0; i < -remainder; i++ {
ints = append(ints, quotient-1)
}
for i := 0; i < n+remainder; i++ {
ints = append(ints, quotient)
}
}
return
}

View File

@@ -1,34 +0,0 @@
-----BEGIN CERTIFICATE-----
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
-----END CERTIFICATE-----

View File

@@ -1,52 +0,0 @@
-----BEGIN PRIVATE KEY-----
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
qQCK9iiN08MAFNia/0/Bj4D7XKurNRY=
-----END PRIVATE KEY-----

View File

@@ -1,34 +0,0 @@
-----BEGIN CERTIFICATE-----
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
-----END CERTIFICATE-----

View File

@@ -1,52 +0,0 @@
-----BEGIN PRIVATE KEY-----
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
D6kBMuZ4gkKW24IYzXzOni0/BOnpOfM=
-----END PRIVATE KEY-----

View File

@@ -1,32 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIFcTCCA1mgAwIBAgICA+gwDQYJKoZIhvcNAQELBQAwUDELMAkGA1UEBhMCVVMx
CzAJBgNVBAgMAkNBMQwwCgYDVQQHDANTVkwxDTALBgNVBAoMBGdSUEMxFzAVBgNV
BAMMDnRlc3QtY2xpZW50X2NhMB4XDTIyMDMxODIxNDQ1OVoXDTMyMDMxNTIxNDQ1
OVowTjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQwwCgYDVQQHDANTVkwxDTAL
BgNVBAoMBGdSUEMxFTATBgNVBAMMDHRlc3QtY2xpZW50MTCCAiIwDQYJKoZIhvcN
AQEBBQADggIPADCCAgoCggIBAL2ec6a93OYIioefCs3KRz752E5VfJPyVuxalBMc
7Dx84NsdwpbUyDT6fO7ePYM8IvYAsLc5coLCP1HKGGRmYm423WZf8Kn93BDl0XcN
4bgtW9ZrekvYcXqSzygz3ifdQeZljZrqW43dkkYR2vWc+uJXs+vrRVZyUSLLbe97
9zUbWbOfHBc1jK1vTUakl08VhllYbO0m0SYZIni0sioItVdVWTz9XE2COavLqwwL
MIq8N7JXEdYJC49JWfdzvqZYTxOn5FSTCWen7/mcZmuLYPwUCkSu05M5T2o1ygkd
ohA+/X9yjToPJ7NO509lKHWo7+sp9if6jZsiOU45/t84pD6juVZSZ20/A9i6hjtj
C0SqYk2iQEtRp+lT6yYa5ffeNllFUGtM+xq2are2n93PnXwMTUlYGuTtkyRPG717
ZtQjKQuwfdJNoNbJl2cfQpmtLdm4Jzrg5cWiiFro+aqnZxIfUEEDkIBaUjYmwMkS
Qq+S32L4f4u7rtbnzdo/jVwq0wpSjTGQJEab+v2wZpDhVbQblTyI30A+TvBIzLil
09OX49/teZCp05kOJy0V/yXdQtPwlQGXdsCUmD6dnGav17fB1witXDdG+4SNoyF/
PN+8wtlMQ8fWvLdxLsd/Rq6CEZQV9mBhrQxXUmFFDhd0O6wfxR/lVFxIWg70Fz7P
+z7tAgMBAAGjVzBVMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFG0psrHrGny8ziVm
RtulG3f9ROrhMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSUBAf8EDDAKBggrBgEFBQcD
AjANBgkqhkiG9w0BAQsFAAOCAgEAtr1dzSQswIOlEGlLtoAwkL7ys/gP2fcdh7Jl
ggiPs266yzZFyGGdd2GKo6tcjdBNjfnO8T5h8eLzj7QlzKPqA/l0BgAW7s7WX9QF
wCivw1DHE815ujlQNo3yve38pd2/I0hdf9GtQLGyOirYpwW5YcHvpmLezrW6J3UU
CWIfYhqO6bSs+HCLkvQdsCG1TpveWYXfC9aXHjw+ZGOjBMEt6AgdWctwzTjQfZub
VjZosBC3ZkDjkA9LTqKP5f8XSWt89J4JCYkiFRiJuYYiNYcZpb0Ug93XjEHIHXMG
N/cD9fCB2HovoVu8YnezpSrqEhqEikHSq80fwbf+NaT0CEbPMx3UMzt8d8gwUiwE
nzzf/o4uOwoofNWfka0J1VPY1AtjUDvz44LyVhp4uvkEJEK1WQ46mM68H/EOUmpd
fHANEbV8HLq2iOjR78n5+MCHRcX7duScp5wT0ajfDg41VrhvV/u7YctFj8ynQJg5
cqbH+GgTrEfAFFm5mZH1SGqNPyxr1eQFWXMRGE7R/NoyQo2uqrSRmz6JFXlnWtxF
YmLhnOdQaytcpiYN2YVyC/rLK3l3Tbh4u5axvlZP/hi+nQluiZzkH97iUqXcBU/9
jYNohnJzXMHTIZM8FQY+9uGw9ErdDo7FmX5Xkp4TzEz9k10m1fnt0njSEzITtqpg
MoO9n00=
-----END CERTIFICATE-----

View File

@@ -1,51 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY-----

View File

@@ -1,32 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIFeDCCA2CgAwIBAgICA+gwDQYJKoZIhvcNAQELBQAwUDELMAkGA1UEBhMCVVMx
CzAJBgNVBAgMAkNBMQwwCgYDVQQHDANTVkwxDTALBgNVBAoMBGdSUEMxFzAVBgNV
BAMMDnRlc3Qtc2VydmVyX2NhMB4XDTIyMDMxODIxNDQ1OFoXDTMyMDMxNTIxNDQ1
OFowTjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQwwCgYDVQQHDANTVkwxDTAL
BgNVBAoMBGdSUEMxFTATBgNVBAMMDHRlc3Qtc2VydmVyMTCCAiIwDQYJKoZIhvcN
AQEBBQADggIPADCCAgoCggIBAL5GBWw+qfXyelelYL/RDA/Fk4GA8DlcBQgBOjBa
XCVDMAJj63sN+ubKBtphWe6Y9SWLJa2mt8a/ZTQZm2R5FPSp9rwdr04UQgmL11wh
DCmO+wkRUeTYwsqcidEHRwOxoctyO+lwgYw983T/fp83qtNS4bw+1kJwrLtFdgok
Kd9UGIugs8BTFqE/7CxFRXTYsNy/gj0pp411Dtgknl1UefPdjco2Qon8f3Dm5iDf
AyUM1oL8+fnRQj/r6P3XC4AOiBsF3duxiBzUp87YgmwDOaa8paKOx2UNLA/eP/aP
Uhd7HkygqOX+tc3H8dvYONo6lhwQD1JqyG6IOOWe2uf5YXKK2TphPPRnCW4QIED4
PuXYHjIvGYA4Kf0Wmb2hPk6bxJidNoLp9lsJyqGfk3QnT5PRJVgO0mlzo/UsZo77
5j+yq87yLe5OL2HrZd1KTfg7SKOtMJ9N6tm2Hw2jwypKz+x2jlEZOgXHmYb5aUaI
+4xG+9fqc8x3ScoHQGNujF3qHO5SxnXkufNUSVbWbv1Ble8peiKyG6AFQvtcs7KG
pEoFztGSlaABwSvxO8J3aJPAEok4OI5IAGJNy92XaBMLtyt270FC8JtUnL+JEubV
t8tY5cCcGK7EtRHb47mM0K8HEq+IU2nAq6/29Ka0IZlkb5fPoWzQAZEIVKgLNHt4
96g9AgMBAAGjXjBcMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFNx36JXsCIzVWCOw
1ETtaxlN79XrMA4GA1UdDwEB/wQEAwIDqDAdBgNVHREEFjAUghIqLnRlc3QuZXhh
bXBsZS5jb20wDQYJKoZIhvcNAQELBQADggIBAAEEZln7lsS/HIysNPJktc0Gdu3n
X1BcA3wXh95YTugcxSSeLLx2SykXnwX+cJncc1OKbboO9DA5mZ+huCesGIOKeUkg
azQZL6FAdw9PQKdqKg3RgSQ4XhK990fPcmmBhSXY24jNNhRHxGw5lGBrD6X2SdW3
m66yYzn9hMXL4yrweGO7OC4bdyISDrJiP+St/xeCoIcXP2s07dE6jl2VorJCWn4J
SxKfDhPPohZKl6dL9npkmPcpz2zRAYpo4tsVdAAQDBRui44Vvm1eBPUo7EH2UOEh
/3JtTeDUpldM8fDaKE0kTa1Ttxzs2e0Jm3M4/FMOxqSesyJldw54F4+4m24e/iQU
gceArYMFVFTipgrLfUuRvRxx/7D7V92pqTyuD3T78+KdTqrlxvCTOqSHhFE05jWD
RdynS6Ev/1QZLlnWgMwhQAnjhc1NKkso+namF1ZmHH9owiTRBlWDMNcHMDReaELd
QmFUvutHUpjidt1z+G6lzbP0XB5w+0vW4BsT0FqaYsFbK5ftryj1/K0VctrSd/ke
GI0vxrErAyLG2B8bdK88u2w7DCuXjAOp+CeA7HUmk93TsPEAhrxQ6lR51IC6LcK0
gACSdnQDPGtkoRX00DTvdcOpzmkSgaGr/mXTqp2lR9IuZIhwKbhS3lDKsAZ/hinB
yaBwLiXfcvZrZOwy
-----END CERTIFICATE-----

View File

@@ -1,51 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY-----

View File

@@ -1,291 +0,0 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.28.0
// protoc v3.20.0
// source: grpc/proto/messager.proto
package messager
import (
context "context"
grpc "google.golang.org/grpc"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type StreamRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"`
Data map[string]int64 `protobuf:"bytes,2,rep,name=data,proto3" json:"data,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"`
NodeID string `protobuf:"bytes,3,opt,name=NodeID,proto3" json:"NodeID,omitempty"`
}
func (x *StreamRequest) Reset() {
*x = StreamRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_grpc_proto_messager_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *StreamRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*StreamRequest) ProtoMessage() {}
func (x *StreamRequest) ProtoReflect() protoreflect.Message {
mi := &file_grpc_proto_messager_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use StreamRequest.ProtoReflect.Descriptor instead.
func (*StreamRequest) Descriptor() ([]byte, []int) {
return file_grpc_proto_messager_proto_rawDescGZIP(), []int{0}
}
func (x *StreamRequest) GetType() string {
if x != nil {
return x.Type
}
return ""
}
func (x *StreamRequest) GetData() map[string]int64 {
if x != nil {
return x.Data
}
return nil
}
func (x *StreamRequest) GetNodeID() string {
if x != nil {
return x.NodeID
}
return ""
}
type StreamResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"`
Profile []byte `protobuf:"bytes,2,opt,name=profile,proto3" json:"profile,omitempty"`
Data map[string]int64 `protobuf:"bytes,3,rep,name=data,proto3" json:"data,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"`
NodeID string `protobuf:"bytes,4,opt,name=NodeID,proto3" json:"NodeID,omitempty"`
Tasks []byte `protobuf:"bytes,5,opt,name=tasks,proto3" json:"tasks,omitempty"`
}
func (x *StreamResponse) Reset() {
*x = StreamResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_grpc_proto_messager_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *StreamResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*StreamResponse) ProtoMessage() {}
func (x *StreamResponse) ProtoReflect() protoreflect.Message {
mi := &file_grpc_proto_messager_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use StreamResponse.ProtoReflect.Descriptor instead.
func (*StreamResponse) Descriptor() ([]byte, []int) {
return file_grpc_proto_messager_proto_rawDescGZIP(), []int{1}
}
func (x *StreamResponse) GetType() string {
if x != nil {
return x.Type
}
return ""
}
func (x *StreamResponse) GetProfile() []byte {
if x != nil {
return x.Profile
}
return nil
}
func (x *StreamResponse) GetData() map[string]int64 {
if x != nil {
return x.Data
}
return nil
}
func (x *StreamResponse) GetNodeID() string {
if x != nil {
return x.NodeID
}
return ""
}
func (x *StreamResponse) GetTasks() []byte {
if x != nil {
return x.Tasks
}
return nil
}
var File_grpc_proto_messager_proto protoreflect.FileDescriptor
var file_grpc_proto_messager_proto_rawDesc = []byte{
0x0a, 0x19, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x6d, 0x65, 0x73,
0x73, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x07, 0x6d, 0x65, 0x73,
0x73, 0x61, 0x67, 0x65, 0x22, 0xaa, 0x01, 0x0a, 0x0d, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x34, 0x0a, 0x04, 0x64, 0x61,
0x74, 0x61, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61,
0x67, 0x65, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x2e, 0x44, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61,
0x12, 0x16, 0x0a, 0x06, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x44, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
0x52, 0x06, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x44, 0x1a, 0x37, 0x0a, 0x09, 0x44, 0x61, 0x74, 0x61,
0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38,
0x01, 0x22, 0xdc, 0x01, 0x0a, 0x0e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70,
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x66,
0x69, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x66, 0x69,
0x6c, 0x65, 0x12, 0x35, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b,
0x32, 0x21, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61,
0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x45, 0x6e,
0x74, 0x72, 0x79, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x16, 0x0a, 0x06, 0x4e, 0x6f, 0x64,
0x65, 0x49, 0x44, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x4e, 0x6f, 0x64, 0x65, 0x49,
0x44, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c,
0x52, 0x05, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x1a, 0x37, 0x0a, 0x09, 0x44, 0x61, 0x74, 0x61, 0x45,
0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28,
0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18,
0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01,
0x32, 0x61, 0x0a, 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x56, 0x0a, 0x1d, 0x42,
0x69, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x72, 0x65,
0x61, 0x6d, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x16, 0x2e, 0x6d,
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x53,
0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x28,
0x01, 0x30, 0x01, 0x42, 0x0f, 0x5a, 0x0d, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x6d, 0x65, 0x73, 0x73,
0x61, 0x67, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_grpc_proto_messager_proto_rawDescOnce sync.Once
file_grpc_proto_messager_proto_rawDescData = file_grpc_proto_messager_proto_rawDesc
)
func file_grpc_proto_messager_proto_rawDescGZIP() []byte {
file_grpc_proto_messager_proto_rawDescOnce.Do(func() {
file_grpc_proto_messager_proto_rawDescData = protoimpl.X.CompressGZIP(file_grpc_proto_messager_proto_rawDescData)
})
return file_grpc_proto_messager_proto_rawDescData
}
var file_grpc_proto_messager_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_grpc_proto_messager_proto_goTypes = []interface{}{
(*StreamRequest)(nil), // 0: message.StreamRequest
(*StreamResponse)(nil), // 1: message.StreamResponse
nil, // 2: message.StreamRequest.DataEntry
nil, // 3: message.StreamResponse.DataEntry
}
var file_grpc_proto_messager_proto_depIdxs = []int32{
2, // 0: message.StreamRequest.data:type_name -> message.StreamRequest.DataEntry
3, // 1: message.StreamResponse.data:type_name -> message.StreamResponse.DataEntry
0, // 2: message.Message.BidirectionalStreamingMessage:input_type -> message.StreamRequest
1, // 3: message.Message.BidirectionalStreamingMessage:output_type -> message.StreamResponse
3, // [3:4] is the sub-list for method output_type
2, // [2:3] is the sub-list for method input_type
2, // [2:2] is the sub-list for extension type_name
2, // [2:2] is the sub-list for extension extendee
0, // [0:2] is the sub-list for field type_name
}
func init() { file_grpc_proto_messager_proto_init() }
func file_grpc_proto_messager_proto_init() {
if File_grpc_proto_messager_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_grpc_proto_messager_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*StreamRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_grpc_proto_messager_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*StreamResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_grpc_proto_messager_proto_rawDesc,
NumEnums: 0,
NumMessages: 4,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_grpc_proto_messager_proto_goTypes,
DependencyIndexes: file_grpc_proto_messager_proto_depIdxs,
MessageInfos: file_grpc_proto_messager_proto_msgTypes,
}.Build()
File_grpc_proto_messager_proto = out.File
file_grpc_proto_messager_proto_rawDesc = nil
file_grpc_proto_messager_proto_goTypes = nil
file_grpc_proto_messager_proto_depIdxs = nil
}
// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConnInterface

View File

@@ -1,122 +0,0 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.2.0
// - protoc v3.20.0
// source: grpc/proto/messager.proto
package messager
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion6
// MessageClient is the client API for Message service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type MessageClient interface {
BidirectionalStreamingMessage(ctx context.Context, opts ...grpc.CallOption) (Message_BidirectionalStreamingMessageClient, error)
}
type messageClient struct {
cc grpc.ClientConnInterface
}
func NewMessageClient(cc grpc.ClientConnInterface) MessageClient {
return &messageClient{cc}
}
func (c *messageClient) BidirectionalStreamingMessage(ctx context.Context, opts ...grpc.CallOption) (Message_BidirectionalStreamingMessageClient, error) {
stream, err := c.cc.NewStream(ctx, &_Message_serviceDesc.Streams[0], "/message.Message/BidirectionalStreamingMessage", opts...)
if err != nil {
return nil, err
}
x := &messageBidirectionalStreamingMessageClient{stream}
return x, nil
}
type Message_BidirectionalStreamingMessageClient interface {
Send(*StreamRequest) error
Recv() (*StreamResponse, error)
grpc.ClientStream
}
type messageBidirectionalStreamingMessageClient struct {
grpc.ClientStream
}
func (x *messageBidirectionalStreamingMessageClient) Send(m *StreamRequest) error {
return x.ClientStream.SendMsg(m)
}
func (x *messageBidirectionalStreamingMessageClient) Recv() (*StreamResponse, error) {
m := new(StreamResponse)
if err := x.ClientStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}
// MessageServer is the server API for Message service.
type MessageServer interface {
BidirectionalStreamingMessage(Message_BidirectionalStreamingMessageServer) error
}
// UnimplementedMessageServer can be embedded to have forward compatible implementations.
type UnimplementedMessageServer struct {
}
func (*UnimplementedMessageServer) BidirectionalStreamingMessage(Message_BidirectionalStreamingMessageServer) error {
return status.Errorf(codes.Unimplemented, "method BidirectionalStreamingMessage not implemented")
}
func RegisterMessageServer(s *grpc.Server, srv MessageServer) {
s.RegisterService(&_Message_serviceDesc, srv)
}
func _Message_BidirectionalStreamingMessage_Handler(srv interface{}, stream grpc.ServerStream) error {
return srv.(MessageServer).BidirectionalStreamingMessage(&messageBidirectionalStreamingMessageServer{stream})
}
type Message_BidirectionalStreamingMessageServer interface {
Send(*StreamResponse) error
Recv() (*StreamRequest, error)
grpc.ServerStream
}
type messageBidirectionalStreamingMessageServer struct {
grpc.ServerStream
}
func (x *messageBidirectionalStreamingMessageServer) Send(m *StreamResponse) error {
return x.ServerStream.SendMsg(m)
}
func (x *messageBidirectionalStreamingMessageServer) Recv() (*StreamRequest, error) {
m := new(StreamRequest)
if err := x.ServerStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}
var _Message_serviceDesc = grpc.ServiceDesc{
ServiceName: "message.Message",
HandlerType: (*MessageServer)(nil),
Methods: []grpc.MethodDesc{},
Streams: []grpc.StreamDesc{
{
StreamName: "BidirectionalStreamingMessage",
Handler: _Message_BidirectionalStreamingMessage_Handler,
ServerStreams: true,
ClientStreams: true,
},
},
Metadata: "grpc/proto/messager.proto",
}

View File

@@ -63,13 +63,6 @@ func writeJSON(w http.ResponseWriter, body []byte, status int) {
writeResponse(w, status, jsonContentType, body)
}
type StartRequestBody struct {
boomer.Profile `mapstructure:",squash"`
Worker string `json:"worker,omitempty" yaml:"worker,omitempty" mapstructure:"worker"` // all
TestCasePath string `json:"testcase-path" yaml:"testcase-path" mapstructure:"testcase-path"`
Other map[string]interface{} `mapstructure:",remain"`
}
type ServerCode int
// server response code
@@ -119,6 +112,13 @@ func CustomAPIResponse(errCode ServerCode, errMsg string) ServerStatus {
}
}
type StartRequestBody struct {
boomer.Profile `mapstructure:",squash"`
Worker string `json:"worker,omitempty" yaml:"worker,omitempty" mapstructure:"worker"` // all
TestCasePath string `json:"testcase-path" yaml:"testcase-path" mapstructure:"testcase-path"`
Other map[string]interface{} `mapstructure:",remain"`
}
type RebalanceRequestBody struct {
boomer.Profile `mapstructure:",squash"`
Worker string `json:"worker,omitempty" yaml:"worker,omitempty" mapstructure:"worker"`