mirror of
https://github.com/OPM/ResInsight.git
synced 2026-10-26 15:10:22 -05:00
Surface gRPC failure context to Python script authors instead of silently returning sentinel values or raising bare gRPC errors. - RipsError now carries code/details/location and a from_rpc_error() helper. Existing single-arg construction stays valid. - Stop swallowing grpc.RpcError in case.__grid_count for non-NOT_FOUND failures and in instance._check_connection_and_version, so the underlying status is propagated. - pdmobject add_method decorator and _call_pdm_method_* attach code/details to the raised RipsError; existing message text is preserved so pytest match=... assertions keep working. - Instance.start_heartbeat / stop_heartbeat / check_alive provide an opt-in background ping that flips a sticky lost-connection flag and raises a readable RipsError from check_alive() if the server dies. - Server side: GetPdmObject in RiaGrpcAppService, RiaGrpcCaseService and RiaGrpcProjectService no longer return Status::OK with an empty reply when the underlying object is missing; they return NOT_FOUND / INTERNAL with a descriptive message. Other RiaGrpc*Service files audited and already return non-OK with text on error paths.
51 lines
1.8 KiB
Python
51 lines
1.8 KiB
Python
import grpc
|
|
|
|
|
|
class RetryOnRpcErrorClientInterceptor(
|
|
grpc.UnaryUnaryClientInterceptor, grpc.StreamUnaryClientInterceptor
|
|
):
|
|
def __init__(
|
|
self,
|
|
*,
|
|
retry_policy,
|
|
status_for_retry,
|
|
should_abort=None,
|
|
):
|
|
self.retry_policy = retry_policy
|
|
self.status_for_retry = status_for_retry
|
|
self.should_abort = should_abort
|
|
|
|
def _intercept_call(self, continuation, client_call_details, request_or_iterator):
|
|
for retry_num in range(self.retry_policy.num_retries()):
|
|
response = continuation(client_call_details, request_or_iterator)
|
|
|
|
if isinstance(response, grpc.RpcError):
|
|
# Return if it was last attempt
|
|
if retry_num == (self.retry_policy.num_retries() - 1):
|
|
return response
|
|
|
|
# If status code is not in retryable status codes
|
|
if (
|
|
self.status_for_retry
|
|
and response.code() not in self.status_for_retry
|
|
):
|
|
return response
|
|
|
|
# Bail out immediately if an external signal (e.g. the
|
|
# heartbeat) says the server is gone — otherwise we'd
|
|
# spend the full retry budget on a defunct process.
|
|
if self.should_abort is not None and self.should_abort():
|
|
return response
|
|
|
|
self.retry_policy.sleep(retry_num)
|
|
else:
|
|
return response
|
|
|
|
def intercept_unary_unary(self, continuation, client_call_details, request):
|
|
return self._intercept_call(continuation, client_call_details, request)
|
|
|
|
def intercept_stream_unary(
|
|
self, continuation, client_call_details, request_iterator
|
|
):
|
|
return self._intercept_call(continuation, client_call_details, request_iterator)
|