Skip to content

Commit

Permalink
[FAB-5016] Configurable connection timeouts
Browse files Browse the repository at this point in the history
Change-Id: I637abb8ebdfd2c09e9a6b3e1a63795d780d9f87e
Signed-off-by: Divyank Katira <Divyank.Katira@securekey.com>
  • Loading branch information
d1vyank committed Jul 14, 2017
1 parent a24a856 commit 3da99de
Show file tree
Hide file tree
Showing 14 changed files with 150 additions and 26 deletions.
16 changes: 16 additions & 0 deletions api/apiconfig/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ package apiconfig

import (
"crypto/x509"
"time"

bccspFactory "github.com/hyperledger/fabric/bccsp/factory"
)
Expand All @@ -18,6 +19,7 @@ type Config interface {
CAServerCertFiles(org string) ([]string, error)
CAClientKeyFile(org string) (string, error)
CAClientCertFile(org string) (string, error)
TimeoutOrDefault(ConnectionType) time.Duration
MspID(org string) (string, error)
OrderersConfig() ([]OrdererConfig, error)
RandomOrdererConfig() (*OrdererConfig, error)
Expand All @@ -37,3 +39,17 @@ type Config interface {
CryptoConfigPath() string
CSPConfig() *bccspFactory.FactoryOpts
}

// ConnectionType enumerates the different types of outgoing connections
type ConnectionType int

const (
// Endorser connection
Endorser ConnectionType = iota
// EventHub connection
EventHub
// EventReg connection
EventReg
// Orderer connection
Orderer
)
13 changes: 13 additions & 0 deletions api/apiconfig/mocks/mockconfig.gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 24 additions & 1 deletion pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ var format = logging.MustStringFormatter(
`%{color}%{time:15:04:05.000} [%{module}] %{level:.4s} : %{color:reset} %{message}`,
)

const cmdRoot = "fabric_sdk"
const (
cmdRoot = "fabric_sdk"
defaultTimeout = time.Second * 5
)

// Config represents the configuration for the client
type Config struct {
Expand Down Expand Up @@ -133,6 +136,26 @@ func (c *Config) CAClientCertFile(org string) (string, error) {
"$GOPATH", os.Getenv("GOPATH"), -1), nil
}

// TimeoutOrDefault reads connection timeouts for the given connection type
func (c *Config) TimeoutOrDefault(conn apiconfig.ConnectionType) time.Duration {
var timeout time.Duration
switch conn {
case apiconfig.Endorser:
timeout = myViper.GetDuration("connection.timeout.peer.endorser")
case apiconfig.EventHub:
timeout = myViper.GetDuration("connection.timeout.peer.eventhub")
case apiconfig.EventReg:
timeout = myViper.GetDuration("connection.timeout.peer.eventreg")
case apiconfig.Orderer:
timeout = myViper.GetDuration("connection.timeout.orderer")
}
if timeout == 0 {
timeout = defaultTimeout
}

return timeout
}

// MspID returns the MSP ID for the requested organization
func (c *Config) MspID(org string) (string, error) {
config, err := c.NetworkConfig()
Expand Down
31 changes: 31 additions & 0 deletions pkg/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"path/filepath"
"strings"
"testing"
"time"

api "github.com/hyperledger/fabric-sdk-go/api/apiconfig"
"github.com/spf13/viper"
Expand Down Expand Up @@ -208,6 +209,36 @@ func TestTLSACAConfig(t *testing.T) {
}
}

func TestTimeouts(t *testing.T) {
myViper.Set("connection.timeout.peer.endorser", "2s")
myViper.Set("connection.timeout.peer.eventhub", "2m")
myViper.Set("connection.timeout.peer.eventreg", "2h")
myViper.Set("connection.timeout.orderer", "2ms")

t1 := configImpl.TimeoutOrDefault(api.Endorser)
if t1 != time.Second*2 {
t.Fatalf("Timeout not read correctly. Got: %s", t1)
}
t2 := configImpl.TimeoutOrDefault(api.EventHub)
if t2 != time.Minute*2 {
t.Fatalf("Timeout not read correctly. Got: %s", t2)
}
t3 := configImpl.TimeoutOrDefault(api.EventReg)
if t3 != time.Hour*2 {
t.Fatalf("Timeout not read correctly. Got: %s", t3)
}
t4 := configImpl.TimeoutOrDefault(api.Orderer)
if t4 != time.Millisecond*2 {
t.Fatalf("Timeout not read correctly. Got: %s", t4)
}
// Test default
myViper.Set("connection.timeout.orderer", "")
t5 := configImpl.TimeoutOrDefault(api.Orderer)
if t5 != time.Second*5 {
t.Fatalf("Timeout not read correctly. Got: %s", t5)
}
}

func TestOrdererConfig(t *testing.T) {
oConfig, err := configImpl.RandomOrdererConfig()

Expand Down
6 changes: 6 additions & 0 deletions pkg/fabric-ca-client/mocks/mockconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ package mocks

import (
"crypto/x509"
"time"

"github.com/hyperledger/fabric-sdk-go/api/apiconfig"

Expand Down Expand Up @@ -51,6 +52,11 @@ func (c *MockConfig) FabricClientViper() *viper.Viper {
return nil
}

//TimeoutOrDefault not implemented
func (c *MockConfig) TimeoutOrDefault(apiconfig.ConnectionType) time.Duration {
return 0
}

// PeersConfig Retrieves the fabric peers from the config file provided
func (c *MockConfig) PeersConfig(org string) ([]apiconfig.PeerConfig, error) {
return nil, nil
Expand Down
2 changes: 1 addition & 1 deletion pkg/fabric-client/events/consumer/consumer.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func NewEventsClient(client fab.FabricClient, peerAddress string, certificate st
//newEventsClientConnectionWithAddress Returns a new grpc.ClientConn to the configured local PEER.
func newEventsClientConnectionWithAddress(peerAddress string, certificate string, serverhostoverride string, config apiconfig.Config) (*grpc.ClientConn, error) {
var opts []grpc.DialOption
opts = append(opts, grpc.WithTimeout(time.Second*3))
opts = append(opts, grpc.WithTimeout(config.TimeoutOrDefault(apiconfig.EventHub)))
if config.IsTLSEnabled() {
tlsCaCertPool, err := config.TLSCACertPool(certificate)
if err != nil {
Expand Down
5 changes: 4 additions & 1 deletion pkg/fabric-client/events/eventhub.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"time"

"github.com/golang/protobuf/proto"
"github.com/hyperledger/fabric-sdk-go/api/apiconfig"
fab "github.com/hyperledger/fabric-sdk-go/api/apifabclient"
"github.com/hyperledger/fabric-sdk-go/api/apitxn"
consumer "github.com/hyperledger/fabric-sdk-go/pkg/fabric-client/events/consumer"
Expand Down Expand Up @@ -245,7 +246,9 @@ func (eventHub *EventHub) Connect() error {
}

if eventHub.grpcClient == nil {
eventsClient, _ := eventHub.eventsClientFactory.newEventsClient(eventHub.client, eventHub.peerAddr, eventHub.peerTLSCertificate, eventHub.peerTLSServerHostOverride, 5, eventHub)
eventsClient, _ := eventHub.eventsClientFactory.newEventsClient(eventHub.client,
eventHub.peerAddr, eventHub.peerTLSCertificate, eventHub.peerTLSServerHostOverride,
eventHub.client.Config().TimeoutOrDefault(apiconfig.EventReg), eventHub)
eventHub.grpcClient = eventsClient
}

Expand Down
6 changes: 6 additions & 0 deletions pkg/fabric-client/mocks/mockconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ package mocks

import (
"crypto/x509"
"time"

config "github.com/hyperledger/fabric-sdk-go/api/apiconfig"

Expand Down Expand Up @@ -53,6 +54,11 @@ func (c *MockConfig) CAClientCertFile(org string) (string, error) {
return "", nil
}

//TimeoutOrDefault not implemented
func (c *MockConfig) TimeoutOrDefault(config.ConnectionType) time.Duration {
return 0
}

// FabricClientViper returns the internal viper instance used by the
// SDK to read configuration options
func (c *MockConfig) FabricClientViper() *viper.Viper {
Expand Down
7 changes: 3 additions & 4 deletions pkg/fabric-client/orderer/orderer.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@ package orderer

import (
"fmt"
"time"

config "github.com/hyperledger/fabric-sdk-go/api/apiconfig"
"github.com/hyperledger/fabric-sdk-go/api/apiconfig"
fab "github.com/hyperledger/fabric-sdk-go/api/apifabclient"
"google.golang.org/grpc/credentials"

Expand All @@ -30,9 +29,9 @@ type Orderer struct {
}

// NewOrderer Returns a Orderer instance
func NewOrderer(url string, certificate string, serverHostOverride string, config config.Config) (*Orderer, error) {
func NewOrderer(url string, certificate string, serverHostOverride string, config apiconfig.Config) (*Orderer, error) {
var opts []grpc.DialOption
opts = append(opts, grpc.WithTimeout(time.Second*3))
opts = append(opts, grpc.WithTimeout(config.TimeoutOrDefault(apiconfig.Orderer)))
if config.IsTLSEnabled() {
tlsCaCertPool, err := config.TLSCACertPool(certificate)
if err != nil {
Expand Down
6 changes: 2 additions & 4 deletions pkg/fabric-client/peer/peer.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ package peer

import (
"encoding/pem"
"time"

"github.com/hyperledger/fabric-sdk-go/api/apiconfig"
fab "github.com/hyperledger/fabric-sdk-go/api/apifabclient"
Expand All @@ -19,7 +18,6 @@ import (
var logger = logging.MustGetLogger("fabric_sdk_go")

const (
connTimeout = time.Second * 10 // TODO: should be configurable
connBlocking = true
)

Expand All @@ -40,7 +38,7 @@ type Peer struct {
// serverNameOverride is passed to NewClientTLSFromCert in grpc/credentials.
func NewPeerTLSFromCert(url string, certificate string, serverHostOverride string, config apiconfig.Config) (*Peer, error) {
// TODO: config is declaring TLS but cert & serverHostOverride is being passed-in...
conn, err := newPeerEndorser(url, certificate, serverHostOverride, connTimeout, connBlocking, config)
conn, err := newPeerEndorser(url, certificate, serverHostOverride, connBlocking, config)
if err != nil {
return nil, err
}
Expand All @@ -51,7 +49,7 @@ func NewPeerTLSFromCert(url string, certificate string, serverHostOverride strin
// NewPeer constructs a Peer given its endpoint configuration settings.
// url is the URL with format of "host:port".
func NewPeer(url string, config apiconfig.Config) (*Peer, error) {
conn, err := newPeerEndorser(url, "", "", connTimeout, connBlocking, config)
conn, err := newPeerEndorser(url, "", "", connBlocking, config)
if err != nil {
return nil, err
}
Expand Down
12 changes: 12 additions & 0 deletions pkg/fabric-client/peer/peer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ import (
"io/ioutil"
"reflect"
"testing"
"time"

"github.com/golang/mock/gomock"
"github.com/hyperledger/fabric-sdk-go/api/apiconfig"
"github.com/hyperledger/fabric-sdk-go/api/apiconfig/mocks"
fab "github.com/hyperledger/fabric-sdk-go/api/apifabclient"
"github.com/hyperledger/fabric-sdk-go/api/apitxn"
Expand All @@ -26,6 +28,7 @@ func TestNewPeerWithCertNoTLS(t *testing.T) {
defer mockCtrl.Finish()
config := mock_apiconfig.NewMockConfig(mockCtrl)
config.EXPECT().IsTLSEnabled().Return(false)
config.EXPECT().TimeoutOrDefault(apiconfig.Endorser).Return(time.Second * 5)

url := "http://example.com"
p, err := NewPeer("http://example.com", config)
Expand All @@ -49,6 +52,7 @@ func TestNewPeerTLSFromCert(t *testing.T) {
config.EXPECT().IsTLSEnabled().Return(true)
config.EXPECT().TLSCACertPool("cert").Return(certPool, nil)
config.EXPECT().TLSCACertPool("").Return(certPool, nil)
config.EXPECT().TimeoutOrDefault(apiconfig.Endorser).Return(time.Second * 5)

url := "0.0.0.0:1234"
// TODO - test actual parameters and test server name override
Expand Down Expand Up @@ -80,6 +84,7 @@ func TestNewPeerTLSFromCertBad(t *testing.T) {

config.EXPECT().IsTLSEnabled().Return(true)
config.EXPECT().TLSCACertPool("").Return(x509.NewCertPool(), nil)
config.EXPECT().TimeoutOrDefault(apiconfig.Endorser).Return(time.Second * 5)

url := "0.0.0.0:1234"
_, err := NewPeerTLSFromCert(url, "", "", config)
Expand All @@ -95,6 +100,7 @@ func TestEnrollmentCert(t *testing.T) {
defer mockCtrl.Finish()
config := mock_apiconfig.NewMockConfig(mockCtrl)
config.EXPECT().IsTLSEnabled().Return(false)
config.EXPECT().TimeoutOrDefault(apiconfig.Endorser).Return(time.Second * 5)

peer, err := NewPeer(peer1URL, config)
if err != nil {
Expand Down Expand Up @@ -125,6 +131,7 @@ func TestRoles(t *testing.T) {
defer mockCtrl.Finish()
config := mock_apiconfig.NewMockConfig(mockCtrl)
config.EXPECT().IsTLSEnabled().Return(false)
config.EXPECT().TimeoutOrDefault(apiconfig.Endorser).Return(time.Second * 5)

peer, err := NewPeer(peer1URL, config)
if err != nil {
Expand All @@ -151,6 +158,7 @@ func TestNames(t *testing.T) {
defer mockCtrl.Finish()
config := mock_apiconfig.NewMockConfig(mockCtrl)
config.EXPECT().IsTLSEnabled().Return(false)
config.EXPECT().TimeoutOrDefault(apiconfig.Endorser).Return(time.Second * 5)

peer, err := NewPeer(peer1URL, config)
if err != nil {
Expand All @@ -174,6 +182,7 @@ func TestMSPIDs(t *testing.T) {
defer mockCtrl.Finish()
config := mock_apiconfig.NewMockConfig(mockCtrl)
config.EXPECT().IsTLSEnabled().Return(false)
config.EXPECT().TimeoutOrDefault(apiconfig.Endorser).Return(time.Second * 5)

peer, err := NewPeer(peer1URL, config)
if err != nil {
Expand Down Expand Up @@ -212,6 +221,7 @@ func TestPlaceholders(t *testing.T) {
defer mockCtrl.Finish()
config := mock_apiconfig.NewMockConfig(mockCtrl)
config.EXPECT().IsTLSEnabled().Return(false)
config.EXPECT().TimeoutOrDefault(apiconfig.Endorser).Return(time.Second * 5)

peer, err := NewPeer(peer1URL, config)
if err != nil {
Expand Down Expand Up @@ -239,13 +249,15 @@ func TestPeersToTxnProcessors(t *testing.T) {
defer mockCtrl.Finish()
config := mock_apiconfig.NewMockConfig(mockCtrl)
config.EXPECT().IsTLSEnabled().Return(false)
config.EXPECT().TimeoutOrDefault(apiconfig.Endorser).Return(time.Second * 5)

peer1, err := NewPeer(peer1URL, config)
if err != nil {
t.Fatalf("Failed to create NewPeer error(%v)", err)
}

config.EXPECT().IsTLSEnabled().Return(false)
config.EXPECT().TimeoutOrDefault(apiconfig.Endorser).Return(time.Second * 5)
peer2, err := NewPeer(peer2URL, config)
if err != nil {
t.Fatalf("Failed to create NewPeer error(%v)", err)
Expand Down
9 changes: 5 additions & 4 deletions pkg/fabric-client/peer/peerendorser.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ package peer
import (
"context"
"fmt"
"time"

"github.com/hyperledger/fabric-sdk-go/api/apiconfig"
"github.com/hyperledger/fabric-sdk-go/api/apitxn"
Expand All @@ -31,15 +30,17 @@ type TransactionProposalError struct {
Err error
}

func newPeerEndorser(target string, certificate string, serverHostOverride string, dialTimeout time.Duration, dialBlocking bool, config apiconfig.Config) (peerEndorser, error) {
func newPeerEndorser(target string, certificate string, serverHostOverride string,
dialBlocking bool, config apiconfig.Config) (
peerEndorser, error) {
if len(target) == 0 {
return peerEndorser{}, fmt.Errorf("Target is required")
}

// Construct dialer options for the connection
var opts []grpc.DialOption
opts = append(opts, grpc.WithTimeout(dialTimeout)) // TODO: should be configurable
if dialBlocking { // TODO: configurable?
opts = append(opts, grpc.WithTimeout(config.TimeoutOrDefault(apiconfig.Endorser)))
if dialBlocking { // TODO: configurable?
opts = append(opts, grpc.WithBlock())
}

Expand Down
Loading

0 comments on commit 3da99de

Please sign in to comment.