Skip to content

Commit

Permalink
[FAB-8143] Clear error between retry attempts
Browse files Browse the repository at this point in the history
Change-Id: I563522b62357b7499be5b673df634ecbcc2f1fad
Signed-off-by: Divyank Katira <Divyank.Katira@securekey.com>
  • Loading branch information
d1vyank committed Feb 8, 2018
1 parent dbcc63a commit d477b43
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 8 deletions.
8 changes: 7 additions & 1 deletion pkg/fabric-client/mocks/mockpeer.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@ package mocks
// TODO: Move protos to this library
import (
"encoding/pem"
"sync"

"github.com/hyperledger/fabric-sdk-go/api/apifabclient"
pb "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/protos/peer"
)

// MockPeer is a mock fabricsdk.Peer.
type MockPeer struct {
RWLock *sync.RWMutex
Error error
MockName string
MockURL string
Expand All @@ -30,7 +32,7 @@ type MockPeer struct {

// NewMockPeer creates basic mock peer
func NewMockPeer(name string, url string) *MockPeer {
mp := &MockPeer{MockName: name, MockURL: url, Status: 200}
mp := &MockPeer{MockName: name, MockURL: url, Status: 200, RWLock: &sync.RWMutex{}}
return mp
}

Expand Down Expand Up @@ -81,6 +83,10 @@ func (p *MockPeer) URL() string {

// ProcessTransactionProposal does not send anything anywhere but returns an empty mock ProposalResponse
func (p *MockPeer) ProcessTransactionProposal(tp apifabclient.TransactionProposal) (apifabclient.TransactionProposalResult, error) {
if p.RWLock != nil {
p.RWLock.Lock()
defer p.RWLock.Unlock()
}
p.ProcessProposalCalls++
return apifabclient.TransactionProposalResult{
Endorser: p.MockURL,
Expand Down
10 changes: 9 additions & 1 deletion pkg/fabric-txn/chclient/chclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,12 @@ import (
"github.com/hyperledger/fabric-sdk-go/pkg/fabric-txn/discovery"
"github.com/hyperledger/fabric-sdk-go/pkg/fabric-txn/discovery/greylist"
txnHandlerImpl "github.com/hyperledger/fabric-sdk-go/pkg/fabric-txn/txnhandler"
"github.com/hyperledger/fabric-sdk-go/pkg/logging"
"github.com/pkg/errors"
)

var logger = logging.NewLogger("fabric_sdk_go")

const (
defaultHandlerTimeout = time.Second * 10
)
Expand Down Expand Up @@ -110,9 +113,14 @@ func (cc *ChannelClient) resolveRetry(req *chclient.RequestContext, opts chclien
if !req.RetryHandler.Required(req.Error) {
return false
}
logger.Infof("Retrying on error %s", req.Error)

cc.greylist.Greylist(req.Error)
// Reset processors
// Reset context parameters
req.Opts.ProposalProcessors = opts.ProposalProcessors
req.Error = nil
req.Response = chclient.Response{}

return true
}

Expand Down
24 changes: 18 additions & 6 deletions pkg/fabric-txn/chclient/chclient_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -369,20 +369,32 @@ func TestTransactionValidationError(t *testing.T) {

func TestExecuteTxWithRetries(t *testing.T) {
testStatus := status.New(status.EndorserClientStatus, status.ConnectionFailed.ToInt32(), "test", nil)
testResp := []byte("test")
retryInterval := 2 * time.Second

testPeer1 := fcmocks.NewMockPeer("Peer1", "http://peer1.com")
testPeer1.Error = testStatus
chClient := setupChannelClient([]apifabclient.Peer{testPeer1}, t)
retryOpts := retry.DefaultOpts
retryOpts.InitialBackoff = 1 * time.Microsecond
retryOpts.Attempts = 1
retryOpts.BackoffFactor = 1
retryOpts.InitialBackoff = retryInterval
retryOpts.RetryableCodes = retry.ChannelClientRetryableCodes

_, err := chClient.Query(chclient.Request{ChaincodeID: "testCC", Fcn: "invoke", Args: [][]byte{[]byte("query"), []byte("b")}},
go func() {
// Remove peer error condition after retry attempt interval
time.Sleep(retryInterval / 2)
testPeer1.RWLock.Lock()
testPeer1.Error = nil
testPeer1.Payload = testResp
testPeer1.RWLock.Unlock()
}()

resp, err := chClient.Query(chclient.Request{ChaincodeID: "testCC", Fcn: "invoke", Args: [][]byte{[]byte("query"), []byte("b")}},
chclient.WithRetry(retryOpts))
if err == nil {
t.Fatalf("Should have failed for not success status")
}
assert.Equal(t, retry.DefaultOpts.Attempts, testPeer1.ProcessProposalCalls-1, "Expected peer to be called (retry attempts + 1) times")
assert.Nil(t, err, "expected error to be nil")
assert.Equal(t, 2, testPeer1.ProcessProposalCalls, "Expected peer to be called twice")
assert.Equal(t, testResp, resp.Payload, "expected correct response")
}

func TestDiscoveryGreylist(t *testing.T) {
Expand Down

0 comments on commit d477b43

Please sign in to comment.