Skip to content

Commit

Permalink
Open source bench tests (Part 1) (cadence-workflow#3990)
Browse files Browse the repository at this point in the history
  • Loading branch information
yycptt authored Feb 17, 2021
1 parent 3c03ea2 commit 117d6c1
Show file tree
Hide file tree
Showing 20 changed files with 1,438 additions and 3 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,6 @@ test_eventsV2_xdc.log
/cadence
/cadence-server
/cadence-canary
/cadence-bench
/cadence-cassandra-tool
/cadence-sql-tool
10 changes: 9 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,10 @@ cadence-canary: $(ALL_SRC)
@echo "compiling cadence-canary with OS: $(GOOS), ARCH: $(GOARCH)"
go build -o cadence-canary cmd/canary/main.go

cadence-bench: $(ALL_SRC)
@echo "compling cadence-bench with OS: $(GOOS), ARCH: $(GOARCH)"
go build -o cadence-bench cmd/bench/main.go

go-generate-format: go-generate fmt

go-generate: $(BIN)/mockgen $(BIN)/enumer
Expand All @@ -278,7 +282,7 @@ fmt: $(BIN)/goimports $(ALL_SRC)
@# use FRESH_ALL_SRC so it won't miss any generated files produced earlier
@$(BIN)/goimports -local "github.com/uber/cadence" -w $(FRESH_ALL_SRC)

bins_nothrift: fmt lint copyright cadence-cassandra-tool cadence-sql-tool cadence cadence-server cadence-canary
bins_nothrift: fmt lint copyright cadence-cassandra-tool cadence-sql-tool cadence cadence-server cadence-canary cadence-bench

bins: thriftc bins_nothrift ## Build, format, and lint everything. Also regenerates thrift.

Expand Down Expand Up @@ -360,6 +364,7 @@ clean: ## Clean binaries and build folder
rm -f cadence
rm -f cadence-server
rm -f cadence-canary
rm -f cadence-bench
rm -f cadence-sql-tool
rm -f cadence-cassandra-tool
rm -Rf $(BUILD)
Expand Down Expand Up @@ -428,6 +433,9 @@ start-cdc-other: bins
start-canary: bins
./cadence-canary start

start-bench: bins
./cadence-bench start

start-mysql: bins
./cadence-server --zone mysql start

Expand Down
128 changes: 128 additions & 0 deletions bench/lib/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
// Copyright (c) 2017-2021 Uber Technologies Inc.

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

package lib

import (
"context"
"fmt"

"go.uber.org/cadence/.gen/go/cadence/workflowserviceclient"
"go.uber.org/cadence/.gen/go/shared"
"go.uber.org/cadence/client"
"go.uber.org/yarpc"
"go.uber.org/yarpc/transport/tchannel"
)

const workflowRetentionDays = 1

// CadenceClient is an abstraction on top of
// the cadence library client that serves as
// a union of all the client interfaces that
// the library exposes
type CadenceClient struct {
client.Client
// domainClient only exposes domain API
client.DomainClient
// this is the service needed to start the workers
Service workflowserviceclient.Interface
}

// CreateDomain creates a cadence domain with the given name and description
// if the domain already exist, this method silently returns success
func (client CadenceClient) CreateDomain(name string, desc string, owner string) error {
emitMetric := true
isGlobalDomain := false
retention := int32(workflowRetentionDays)
req := &shared.RegisterDomainRequest{
Name: &name,
Description: &desc,
OwnerEmail: &owner,
WorkflowExecutionRetentionPeriodInDays: &retention,
EmitMetric: &emitMetric,
IsGlobalDomain: &isGlobalDomain,
}
err := client.Register(context.Background(), req)
if err != nil {
if _, ok := err.(*shared.DomainAlreadyExistsError); !ok {
return err
}
}
return nil
}

// NewCadenceClients builds a CadenceClient for each domain from the runtimeContext
func NewCadenceClients(runtime *RuntimeContext) (map[string]CadenceClient, error) {
cadenceClients := make(map[string]CadenceClient)
for _, domain := range runtime.Bench.Domains {
client, err := NewCadenceClientForDomain(runtime, domain)
if err != nil {
return nil, err
}

cadenceClients[domain] = client
}

return cadenceClients, nil
}

// NewCadenceClientForDomain builds a CadenceClient for a specified domain based on runtimeContext
func NewCadenceClientForDomain(
runtime *RuntimeContext,
domain string,
) (CadenceClient, error) {

ch, err := tchannel.NewChannelTransport(
tchannel.ServiceName(runtime.Bench.Name),
)
if err != nil {
return CadenceClient{}, fmt.Errorf("failed to create transport channel: %v", err)
}

dispatcher := yarpc.NewDispatcher(yarpc.Config{
Name: runtime.Bench.Name,
Outbounds: yarpc.Outbounds{
runtime.Cadence.ServiceName: {Unary: ch.NewSingleOutbound(runtime.Cadence.HostNameAndPort)},
},
})

if err := dispatcher.Start(); err != nil {
dispatcher.Stop()
return CadenceClient{}, fmt.Errorf("failed to create outbound transport channel: %v", err)
}

var cadenceClient CadenceClient
cadenceClient.Service = workflowserviceclient.New(dispatcher.ClientConfig(runtime.Cadence.ServiceName))
cadenceClient.Client = client.NewClient(
cadenceClient.Service,
domain,
&client.Options{
MetricsScope: runtime.Metrics,
},
)
cadenceClient.DomainClient = client.NewDomainClient(
cadenceClient.Service,
&client.Options{
MetricsScope: runtime.Metrics,
},
)

return cadenceClient, nil
}
79 changes: 79 additions & 0 deletions bench/lib/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// Copyright (c) 2017-2021 Uber Technologies Inc.

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

package lib

import (
"errors"

"github.com/uber/cadence/common/service/config"
)

type (
// Config contains the configuration for cadence bench
Config struct {
Bench Bench `yaml:"bench"`
Cadence Cadence `yaml:"cadence"`
Log config.Logger `yaml:"log"`
Metrics config.Metrics `yaml:"metrics"`
}

// Cadence contains the configuration for cadence service
Cadence struct {
ServiceName string `yaml:"service"`
HostNameAndPort string `yaml:"host"`
}

// Bench contains the configuration for bench tests
Bench struct {
Name string `yaml:"name"`
Domains []string `yaml:"domains"`
NumTaskLists int `yaml:"numTaskLists"`
}

// BasicTestConfig contains the configuration for running the Basic test scenario
// TODO: update comment
BasicTestConfig struct {
TotalLaunchCount int `yaml:"totalLaunchCount"`
RoutineCount int `yaml:"routineCount"`
ChainSequence int `yaml:"chainSequence"`
ConcurrentCount int `yaml:"concurrentCount"`
PayloadSizeBytes int `yaml:"payloadSizeBytes"`
MinCadenceSleepInSeconds int `yaml:"minCadenceSleepInSeconds"`
MaxCadenceSleepInSeconds int `yaml:"maxCadenceSleepInSeconds"`
ExecutionStartToCloseTimeoutInSeconds int `yaml:"executionStartToCloseTimeoutInSeconds"` // default 5m
ContextTimeoutInSeconds int `yaml:"contextTimeoutInSeconds"` // default 3s
PanicStressWorkflow bool `yaml:"panicStressWorkflow"` // default false
FailureThreshold float64 `yaml:"failureThreshold"`
}
)

func (c *Config) Validate() error {
if len(c.Bench.Name) == 0 {
return errors.New("missing value for bench service name")
}
if len(c.Bench.Domains) == 0 {
return errors.New("missing value for domains property")
}
if c.Bench.NumTaskLists == 0 {
return errors.New("number of taskLists can not be 0")
}
return nil
}
59 changes: 59 additions & 0 deletions bench/lib/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Copyright (c) 2017-2021 Uber Technologies Inc.

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

package lib

import (
"testing"

"github.com/stretchr/testify/suite"
)

type ConfigTestSuite struct {
suite.Suite
}

func TestConfigTestSuite(t *testing.T) {
suite.Run(t, new(ConfigTestSuite))
}

func (s *ConfigTestSuite) TestValidate() {
testCases := []func(*Config){
func(c *Config) { c.Bench.Name = "" },
func(c *Config) { c.Bench.Domains = []string{} },
func(c *Config) { c.Bench.NumTaskLists = 0 },
}

for _, tc := range testCases {
config := s.buildConfig()
tc(&config)
s.Error(config.Validate())
}
}

func (s *ConfigTestSuite) buildConfig() Config {
return Config{
Bench: Bench{
Name: "cadence-bench",
Domains: []string{"cadence-bench"},
NumTaskLists: 1,
},
}
}
75 changes: 75 additions & 0 deletions bench/lib/context.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Copyright (c) 2017-2021 Uber Technologies Inc.

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

package lib

import (
"github.com/uber-go/tally"
"go.uber.org/zap"

"github.com/uber/cadence/common/log/loggerimpl"
)

const (
defaultCadenceLocalHostPort = "127.0.0.1:7933"
defaultCadenceServiceName = "cadence-frontend"
)

// ContextKey is an alias for string, used as context key
type ContextKey string

const (
// CtxKeyRuntimeContext is the name of the context key whose value is the RuntimeContext
CtxKeyRuntimeContext = ContextKey("ctxKeyRuntimeCtx")

// CtxKeyCadenceClient is the name of the context key for the cadence client this cadence worker listens to
CtxKeyCadenceClient = ContextKey("ctxKeyCadenceClient")
)

// RuntimeContext contains all of the context information
// needed at cadence bench runtime
type RuntimeContext struct {
Bench Bench
Cadence Cadence
Logger *zap.Logger
Metrics tally.Scope
}

// NewRuntimeContext builds a runtime context from the config
func NewRuntimeContext(cfg *Config) (*RuntimeContext, error) {
logger := cfg.Log.NewZapLogger()

metricsScope := cfg.Metrics.NewScope(loggerimpl.NewLogger(logger), cfg.Bench.Name)

if cfg.Cadence.ServiceName == "" {
cfg.Cadence.ServiceName = defaultCadenceServiceName
}

if cfg.Cadence.HostNameAndPort == "" {
cfg.Cadence.HostNameAndPort = defaultCadenceLocalHostPort
}

return &RuntimeContext{
Bench: cfg.Bench,
Cadence: cfg.Cadence,
Logger: logger,
Metrics: metricsScope,
}, nil
}
Loading

0 comments on commit 117d6c1

Please sign in to comment.