Class: Gruf::Error

Inherits:
Object
  • Object
show all
Includes:
Loggable
Defined in:
lib/gruf/error.rb

Overview

Represents a error that can be transformed into a gRPC error and have metadata attached to the trailing headers. This layer acts as an middle layer that can have metadata injection, tracing support, and other functionality not present in the gRPC core.

Constant Summary collapse

TYPES =

Returns A hash mapping of gRPC BadStatus codes to error symbols.

Returns:

  • (Hash<GRPC::BadStatus>)

    A hash mapping of gRPC BadStatus codes to error symbols

{
  ok: GRPC::Ok,
  cancelled: GRPC::Cancelled,
  unknown: GRPC::Unknown,
  invalid_argument: GRPC::InvalidArgument,
  bad_request: GRPC::InvalidArgument,
  deadline_exceeded: GRPC::DeadlineExceeded,
  not_found: GRPC::NotFound,
  already_exists: GRPC::AlreadyExists,
  unauthorized: GRPC::PermissionDenied,
  permission_denied: GRPC::PermissionDenied,
  unauthenticated: GRPC::Unauthenticated,
  resource_exhausted: GRPC::ResourceExhausted,
  failed_precondition: GRPC::FailedPrecondition,
  aborted: GRPC::Aborted,
  out_of_range: GRPC::OutOfRange,
  unimplemented: GRPC::Unimplemented,
  internal: GRPC::Internal,
  unavailable: GRPC::Unavailable,
  data_loss: GRPC::DataLoss
}.freeze
MAX_METADATA_SIZE =

Default limit on trailing metadata is 8KB. We need to be careful not to overflow this limit, or the response message will never be sent. Instead, resource_exhausted will be thrown.

7.5 * 1_024
METADATA_SIZE_EXCEEDED_CODE =
'metadata_size_exceeded'
METADATA_SIZE_EXCEEDED_MSG =
'Metadata too long, risks exceeding http2 trailing metadata limit.'

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Loggable

#logger

Constructor Details

#initialize(args = {}) ⇒ Error

Initialize the error, setting default values

Parameters:

  • args (Hash) (defaults to: {})

    (Optional) An optional hash of arguments that will set fields on the error object



87
88
89
90
91
92
93
# File 'lib/gruf/error.rb', line 87

def initialize(args = {})
  @field_errors = []
  @metadata = {}
  args.each do |k, v|
    send("#{k}=", v) if respond_to?(k)
  end
end

Instance Attribute Details

#app_codeSymbol

Returns An arbitrary application code that can be used for logical processing of the error by the client.

Returns:

  • (Symbol)

    An arbitrary application code that can be used for logical processing of the error by the client



64
65
66
# File 'lib/gruf/error.rb', line 64

def app_code
  @app_code
end

#codeSymbol

Returns The given internal gRPC code for the error.

Returns:

  • (Symbol)

    The given internal gRPC code for the error



60
61
62
# File 'lib/gruf/error.rb', line 60

def code
  @code
end

#debug_infoErrors::DebugInfo

Returns A object containing debugging information, such as a stack trace and exception name, that can be used to debug an given error response. This is sent by the server over the trailing metadata.

Returns:

  • (Errors::DebugInfo)

    A object containing debugging information, such as a stack trace and exception name, that can be used to debug an given error response. This is sent by the server over the trailing metadata.



74
75
76
# File 'lib/gruf/error.rb', line 74

def debug_info
  @debug_info
end

#field_errorsArray

Returns An array of field errors that can be returned by the server.

Returns:

  • (Array)

    An array of field errors that can be returned by the server



70
71
72
# File 'lib/gruf/error.rb', line 70

def field_errors
  @field_errors
end

#grpc_errorGRPC::BadStatus

Return the appropriately mapped GRPC::BadStatus error object for this error

Returns:

  • (GRPC::BadStatus)


205
206
207
208
# File 'lib/gruf/error.rb', line 205

def grpc_error
  md = @metadata || {}
  @grpc_error = grpc_class.new(message, **md)
end

#messageString

Returns The error message returned by the server.

Returns:

  • (String)

    The error message returned by the server



67
68
69
# File 'lib/gruf/error.rb', line 67

def message
  @message
end

#metadataObject

Returns the value of attribute metadata.



80
81
82
# File 'lib/gruf/error.rb', line 80

def 
  @metadata
end

Instance Method Details

#add_field_error(field_name, error_code, message = '') ⇒ Object

Add a field error to this error package

Parameters:

  • field_name (Symbol)

    The field name for the error

  • error_code (Symbol)

    The application error code for the error; e.g. :job_not_found

  • message (String) (defaults to: '')

    The application error message for the error; e.g. "Job not found with ID 123"



102
103
104
# File 'lib/gruf/error.rb', line 102

def add_field_error(field_name, error_code, message = '')
  @field_errors << Errors::Field.new(field_name, error_code, message)
end

#attach_to_call(active_call) ⇒ Error

Update the trailing metadata on the given gRPC call, including the error payload if configured to do so.

Parameters:

  • active_call (GRPC::ActiveCall)

    The marshalled gRPC call

Returns:

  • (Error)

    Return the error itself after updating metadata on the given gRPC call. In the case of a metadata overflow error, we replace the current error with a new one that won't cause a low-level http2 error.



155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# File 'lib/gruf/error.rb', line 155

def attach_to_call(active_call)
  [Gruf..to_sym] = serialize if Gruf.
  return self if .empty? || !active_call || !active_call.respond_to?(:output_metadata)

  # Check if we've overflown the maximum size of output metadata. If so,
  # log a warning and replace the metadata with something smaller to avoid
  # resource exhausted errors.
  if .inspect.size > MAX_METADATA_SIZE
    code = METADATA_SIZE_EXCEEDED_CODE
    msg = METADATA_SIZE_EXCEEDED_MSG
    logger.warn "#{code}: #{msg} Original error: #{to_h.inspect}"
    err = Gruf::Error.new(code: :internal, app_code: code, message: msg)
    return err.attach_to_call(active_call)
  end

  active_call..update()
  self
end

#fail!(active_call) ⇒ GRPC::BadStatus

Fail the current gRPC call with the given error, properly attaching it to the call and raising the appropriate gRPC BadStatus code.

Parameters:

  • active_call (GRPC::ActiveCall)

    The marshalled gRPC call

Returns:

  • (GRPC::BadStatus)

    The gRPC BadStatus code this error is mapped to



181
182
183
# File 'lib/gruf/error.rb', line 181

def fail!(active_call)
  raise attach_to_call(active_call).grpc_error
end

#has_field_errors?Boolean

Return true if there are any present field errors

Returns:

  • (Boolean)

    True if the service has any field errors



111
112
113
# File 'lib/gruf/error.rb', line 111

def has_field_errors?
  @field_errors.any?
end

#serializeString

Serialize the error for transport

Returns:

  • (String)

    The serialized error message



141
142
143
144
# File 'lib/gruf/error.rb', line 141

def serialize
  serializer = serializer_class.new(self)
  serializer.serialize.to_s
end

#set_debug_info(detail, stack_trace = []) ⇒ Object

Set the debugging information for the error message

service

Parameters:

  • detail (String)

    The detailed message generated by the exception

  • stack_trace (Array<String>) (defaults to: [])

    An array of strings that represents the exception backtrace generated by the



122
123
124
# File 'lib/gruf/error.rb', line 122

def set_debug_info(detail, stack_trace = [])
  @debug_info = Errors::DebugInfo.new(detail, stack_trace)
end

#to_hHash

Return the error represented in Hash form

Returns:

  • (Hash)

    The error as a hash



190
191
192
193
194
195
196
197
198
# File 'lib/gruf/error.rb', line 190

def to_h
  {
    code: code,
    app_code: app_code,
    message: message,
    field_errors: field_errors.map(&:to_h),
    debug_info: debug_info.to_h
  }
end