Fix concurrency on the client (#183)

* reworked peer connection establishment logic eliminating race conditions and deadlocks while running many peers
This commit is contained in:
Mikhail Bragin
2022-01-10 18:43:13 +01:00
committed by GitHub
parent 828410b34c
commit 319632ffe8
25 changed files with 1216 additions and 898 deletions

View File

@@ -45,6 +45,10 @@ type Client struct {
status Status
}
func (c *Client) StreamConnected() bool {
return c.status == StreamConnected
}
func (c *Client) GetStatus() Status {
return c.status
}
@@ -117,7 +121,7 @@ func (c *Client) Receive(msgHandler func(msg *proto.Message) error) error {
c.notifyStreamDisconnected()
log.Debugf("signal connection state %v", c.signalConn.GetState())
if !c.ready() {
if !c.Ready() {
return fmt.Errorf("no connection to signal")
}
@@ -204,9 +208,9 @@ func (c *Client) connect(key string) (proto.SignalExchange_ConnectStreamClient,
return stream, nil
}
// ready indicates whether the client is okay and ready to be used
// Ready indicates whether the client is okay and Ready to be used
// for now it just checks whether gRPC connection to the service is in state Ready
func (c *Client) ready() bool {
func (c *Client) Ready() bool {
return c.signalConn.GetState() == connectivity.Ready || c.signalConn.GetState() == connectivity.Idle
}
@@ -228,7 +232,7 @@ func (c *Client) WaitStreamConnected() {
// The Client.Receive method must be called before sending messages to establish initial connection to the Signal Exchange
// Client.connWg can be used to wait
func (c *Client) SendToStream(msg *proto.EncryptedMessage) error {
if !c.ready() {
if !c.Ready() {
return fmt.Errorf("no connection to signal")
}
if c.stream == nil {
@@ -287,7 +291,7 @@ func (c *Client) encryptMessage(msg *proto.Message) (*proto.EncryptedMessage, er
// Send sends a message to the remote Peer through the Signal Exchange.
func (c *Client) Send(msg *proto.Message) error {
if !c.ready() {
if !c.Ready() {
return fmt.Errorf("no connection to signal")
}
@@ -295,9 +299,11 @@ func (c *Client) Send(msg *proto.Message) error {
if err != nil {
return err
}
_, err = c.realClient.Send(context.TODO(), encryptedMessage)
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
_, err = c.realClient.Send(ctx, encryptedMessage)
if err != nil {
//log.Errorf("error while sending message to peer [%s] [error: %v]", msg.RemoteKey, err)
return err
}

View File

@@ -74,10 +74,6 @@ var (
log.Fatalf("failed to listen: %v", err)
}
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
proto.RegisterSignalExchangeServer(grpcServer, server.NewServer())
log.Printf("started server: localhost:%v", signalPort)
if err := grpcServer.Serve(lis); err != nil {

View File

@@ -29,7 +29,7 @@ func NewServer() *Server {
func (s *Server) Send(ctx context.Context, msg *proto.EncryptedMessage) (*proto.EncryptedMessage, error) {
if !s.registry.IsPeerRegistered(msg.Key) {
return nil, fmt.Errorf("unknown peer %s", msg.Key)
return nil, fmt.Errorf("peer %s is not registered", msg.Key)
}
if dstPeer, found := s.registry.Get(msg.RemoteKey); found {