go.uber.org/cadence@v1.2.9/internal/compatibility/thrift/error.go (about)

     1  // Copyright (c) 2021 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  package thrift
    22  
    23  import (
    24  	"errors"
    25  
    26  	apiv1 "github.com/uber/cadence-idl/go/proto/api/v1"
    27  	"go.uber.org/yarpc/encoding/protobuf"
    28  	"go.uber.org/yarpc/yarpcerrors"
    29  
    30  	"go.uber.org/cadence/.gen/go/shared"
    31  	"go.uber.org/cadence/internal/common"
    32  )
    33  
    34  func Error(err error) error {
    35  	status := yarpcerrors.FromError(err)
    36  	if status == nil || status.Code() == yarpcerrors.CodeOK {
    37  		return nil
    38  	}
    39  
    40  	switch status.Code() {
    41  	case yarpcerrors.CodePermissionDenied:
    42  		return &shared.AccessDeniedError{
    43  			Message: status.Message(),
    44  		}
    45  	case yarpcerrors.CodeInternal:
    46  		return &shared.InternalServiceError{
    47  			Message: status.Message(),
    48  		}
    49  	case yarpcerrors.CodeNotFound:
    50  		switch details := getErrorDetails(err).(type) {
    51  		case *apiv1.EntityNotExistsError:
    52  			return &shared.EntityNotExistsError{
    53  				Message:        status.Message(),
    54  				CurrentCluster: &details.CurrentCluster,
    55  				ActiveCluster:  &details.ActiveCluster,
    56  			}
    57  		case *apiv1.WorkflowExecutionAlreadyCompletedError:
    58  			return &shared.WorkflowExecutionAlreadyCompletedError{
    59  				Message: status.Message(),
    60  			}
    61  		}
    62  	case yarpcerrors.CodeInvalidArgument:
    63  		switch getErrorDetails(err).(type) {
    64  		case nil:
    65  			return &shared.BadRequestError{
    66  				Message: status.Message(),
    67  			}
    68  		case *apiv1.QueryFailedError:
    69  			return &shared.QueryFailedError{
    70  				Message: status.Message(),
    71  			}
    72  		}
    73  	case yarpcerrors.CodeAlreadyExists:
    74  		switch details := getErrorDetails(err).(type) {
    75  		case *apiv1.CancellationAlreadyRequestedError:
    76  			return &shared.CancellationAlreadyRequestedError{
    77  				Message: status.Message(),
    78  			}
    79  		case *apiv1.DomainAlreadyExistsError:
    80  			return &shared.DomainAlreadyExistsError{
    81  				Message: status.Message(),
    82  			}
    83  		case *apiv1.WorkflowExecutionAlreadyStartedError:
    84  			return &shared.WorkflowExecutionAlreadyStartedError{
    85  				Message:        common.StringPtr(status.Message()),
    86  				StartRequestId: &details.StartRequestId,
    87  				RunId:          &details.RunId,
    88  			}
    89  		}
    90  	case yarpcerrors.CodeDataLoss:
    91  		return &shared.InternalDataInconsistencyError{
    92  			Message: status.Message(),
    93  		}
    94  	case yarpcerrors.CodeFailedPrecondition:
    95  		switch details := getErrorDetails(err).(type) {
    96  		case *apiv1.ClientVersionNotSupportedError:
    97  			return &shared.ClientVersionNotSupportedError{
    98  				FeatureVersion:    details.FeatureVersion,
    99  				ClientImpl:        details.ClientImpl,
   100  				SupportedVersions: details.SupportedVersions,
   101  			}
   102  		case *apiv1.FeatureNotEnabledError:
   103  			return &shared.FeatureNotEnabledError{
   104  				FeatureFlag: details.FeatureFlag,
   105  			}
   106  		case *apiv1.DomainNotActiveError:
   107  			return &shared.DomainNotActiveError{
   108  				Message:        status.Message(),
   109  				DomainName:     details.Domain,
   110  				CurrentCluster: details.CurrentCluster,
   111  				ActiveCluster:  details.ActiveCluster,
   112  			}
   113  		}
   114  	case yarpcerrors.CodeResourceExhausted:
   115  		switch getErrorDetails(err).(type) {
   116  		case *apiv1.LimitExceededError:
   117  			return &shared.LimitExceededError{
   118  				Message: status.Message(),
   119  			}
   120  		case *apiv1.ServiceBusyError:
   121  			return &shared.ServiceBusyError{
   122  				Message: status.Message(),
   123  			}
   124  		}
   125  	case yarpcerrors.CodeUnknown:
   126  		return errors.New(status.Message())
   127  	}
   128  
   129  	// If error does not match anything, return raw yarpc status error
   130  	// There are some code that casts error to yarpc status to check for deadline exceeded status
   131  	return status
   132  }
   133  
   134  func getErrorDetails(err error) interface{} {
   135  	details := protobuf.GetErrorDetails(err)
   136  	if len(details) > 0 {
   137  		return details[0]
   138  	}
   139  	return nil
   140  }