62 lines
1.8 KiB
Go
62 lines
1.8 KiB
Go
|
package shared
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"time"
|
||
|
|
||
|
"github.com/hashicorp/nomad/plugins/base"
|
||
|
"google.golang.org/grpc/codes"
|
||
|
"google.golang.org/grpc/status"
|
||
|
)
|
||
|
|
||
|
// HandleStreamErr is used to handle a non io.EOF error in a stream. It handles
|
||
|
// detecting if the plugin has shutdown via the passeed pluginCtx. The
|
||
|
// parameters are:
|
||
|
// - err: the error returned from the streaming RPC
|
||
|
// - reqCtx: the context passed to the streaming request
|
||
|
// - pluginCtx: the plugins done ctx used to detect the plugin dying
|
||
|
//
|
||
|
// The return values are:
|
||
|
// - base.ErrPluginShutdown if the error is because the plugin shutdown
|
||
|
// - context.Canceled if the reqCtx is canceled
|
||
|
// - The original error
|
||
|
func HandleStreamErr(err error, reqCtx, pluginCtx context.Context) error {
|
||
|
if err == nil {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// Determine if the error is because the plugin shutdown
|
||
|
if errStatus, ok := status.FromError(err); ok && errStatus.Code() == codes.Unavailable {
|
||
|
// Potentially wait a little before returning an error so we can detect
|
||
|
// the exit
|
||
|
select {
|
||
|
case <-pluginCtx.Done():
|
||
|
err = base.ErrPluginShutdown
|
||
|
case <-reqCtx.Done():
|
||
|
err = reqCtx.Err()
|
||
|
|
||
|
// There is no guarantee that the select will choose the
|
||
|
// doneCtx first so we have to double check
|
||
|
select {
|
||
|
case <-pluginCtx.Done():
|
||
|
err = base.ErrPluginShutdown
|
||
|
default:
|
||
|
}
|
||
|
case <-time.After(3 * time.Second):
|
||
|
// Its okay to wait a while since the connection isn't available and
|
||
|
// on local host it is likely shutting down. It is not expected for
|
||
|
// this to ever reach even close to 3 seconds.
|
||
|
}
|
||
|
|
||
|
// It is an error we don't know how to handle, so return it
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
// Context was cancelled
|
||
|
if errStatus := status.FromContextError(reqCtx.Err()); errStatus.Code() == codes.Canceled {
|
||
|
return context.Canceled
|
||
|
}
|
||
|
|
||
|
return err
|
||
|
}
|