Requests are queued by the completion queue thread and processed from the main
thread. A long running request, or an open progress dialog in the GUI, therefore
left every request unanswered for as long as that operation lasted, including
the liveness checks a client uses to decide whether ResInsight is still there.
Let a callback declare that it touches no application state, and serve those
directly on the completion queue thread instead of queueing them. GetVersion is
the only such callback, since it reads compile-time constants only. Everything
that touches the project or the data model is still processed on the main
thread, so no request can observe or modify the data model while another one is
running.
The allocated callback list is now used from both threads and is guarded by a
mutex. Shutdown takes a lock before flagging that it is in progress, so that it
waits for any dispatch already running on the completion queue thread and no new
request handler can be registered on a queue that is about to be shut down.
During a blocking call of 3.25 s, 65 pings were answered with a maximum latency
of 6.2 ms. Before this change none of them were answered until the call
completed.
ResInsight serves gRPC requests from its main thread, so a long running call
leaves the heartbeat pings unanswered for as long as that call runs. The
heartbeat counted those timeouts as connection failures and closed the channel,
which aborted the very call the user was waiting for. The client reported
"RipsError: Channel closed!" while the ResInsight process was alive and well.
Classify a ping that fails with DEADLINE_EXCEEDED or RESOURCE_EXHAUSTED as a
busy server and never count it towards the failure threshold. Only failures
that indicate a broken connection declare the connection lost. A new
busy_warning_sec argument controls when a warning is logged for a server that
has been unresponsive for a while, so long operations are visible without being
killed.
Keep the process handle from Instance.launch so the heartbeat can check whether
ResInsight actually exited. A dead process is now detected immediately and
reported with its exit code instead of a bare channel error, and check_alive()
repeats that diagnosis.
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.