Update pkg/ttrpcutil with improved pipe dial logic

Signed-off-by: Kevin Parsons <kevpar@microsoft.com>
This commit is contained in:
Kevin Parsons 2019-07-30 18:37:58 -07:00
parent daf12cd194
commit b16e7c5de1

View File

@ -19,6 +19,7 @@
package ttrpcutil package ttrpcutil
import ( import (
"context"
"net" "net"
"os" "os"
"time" "time"
@ -28,33 +29,31 @@ import (
) )
func ttrpcDial(address string, timeout time.Duration) (net.Conn, error) { func ttrpcDial(address string, timeout time.Duration) (net.Conn, error) {
var c net.Conn ctx, cancel := context.WithTimeout(context.Background(), timeout)
var lastError error defer cancel()
timedOutError := errors.Errorf("timed out waiting for npipe %s", address)
start := time.Now() // If there is nobody serving the pipe we limit the timeout for this case to
// 5 seconds because any shim that would serve this endpoint should serve it
// within 5 seconds.
serveTimer := time.NewTimer(5 * time.Second)
defer serveTimer.Stop()
for { for {
remaining := timeout - time.Since(start) c, err := winio.DialPipeContext(ctx, address)
if remaining <= 0 { if err != nil {
lastError = timedOutError if os.IsNotExist(err) {
break select {
} case <-serveTimer.C:
c, lastError = winio.DialPipe(address, &remaining) return nil, errors.Wrap(os.ErrNotExist, "pipe not found before timeout")
if lastError == nil { default:
break // Wait 10ms for the shim to serve and try again.
}
if !os.IsNotExist(lastError) {
break
}
// There is nobody serving the pipe. We limit the timeout for this case
// to 5 seconds because any shim that would serve this endpoint should
// serve it within 5 seconds. We use the passed in timeout for the
// `DialPipe` timeout if the pipe exists however to give the pipe time
// to `Accept` the connection.
if time.Since(start) >= 5*time.Second {
lastError = timedOutError
break
}
time.Sleep(10 * time.Millisecond) time.Sleep(10 * time.Millisecond)
continue
}
} else if err == context.DeadlineExceeded {
return nil, errors.Wrapf(err, "timed out waiting for npipe %s", address)
}
return nil, err
}
return c, nil
} }
return c, lastError
} }