From 32f97bd862e1548f610c9e43b768c3db4ba837a5 Mon Sep 17 00:00:00 2001 From: Kristian Bendiksen Date: Mon, 7 Sep 2026 12:04:45 +0200 Subject: [PATCH] #14683 Raise the gRPC message size limit for large payloads A schedule generated from a full production history, or a large raw text block imported into the event timeline, easily exceeds the gRPC default limit of 4 MB. Such a call failed with "Received message larger than max (5119402 vs 4194304)" even though both sides were healthy. Raise the limit to 128 MB on the server and use a matching limit for the client channels. A schedule of 19.5 MB is now returned without error. --- GrpcInterface/Python/rips/instance.py | 21 +++++++++++++++------ GrpcInterface/RiaGrpcServer.cpp | 8 ++++++++ 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/GrpcInterface/Python/rips/instance.py b/GrpcInterface/Python/rips/instance.py index 5f3f158dd0..5bbbe7400d 100644 --- a/GrpcInterface/Python/rips/instance.py +++ b/GrpcInterface/Python/rips/instance.py @@ -57,6 +57,19 @@ def _is_server_busy_error(rpc_error: grpc.RpcError) -> bool: return code in _BUSY_STATUS_CODES +# A single PDM method call may return a large payload, e.g. the schedule text +# generated from a full production history. The gRPC default of 4 MB is easily +# exceeded by such results, so raise it well above any realistic deck size +# while still keeping a bound against runaway allocations. +_MAX_MESSAGE_LENGTH = 128 * 1024 * 1024 + +_CHANNEL_OPTIONS = [ + ("grpc.enable_http_proxy", False), + ("grpc.max_receive_message_length", _MAX_MESSAGE_LENGTH), + ("grpc.max_send_message_length", _MAX_MESSAGE_LENGTH), +] + + class Instance: """The ResInsight Instance class. Use to launch or find existing ResInsight instances @@ -83,9 +96,7 @@ class Instance: @staticmethod def __is_valid_port(port: int) -> bool: location = "localhost:" + str(port) - channel = grpc.insecure_channel( - location, options=[("grpc.enable_http_proxy", False)] - ) + channel = grpc.insecure_channel(location, options=_CHANNEL_OPTIONS) app = App_pb2_grpc.AppStub(channel) try: app.GetVersion(Empty(), timeout=1) @@ -307,9 +318,7 @@ class Instance: self._heartbeat_stop = None self._process = process - self.channel = grpc.insecure_channel( - self.location, options=[("grpc.enable_http_proxy", False)] - ) + self.channel = grpc.insecure_channel(self.location, options=_CHANNEL_OPTIONS) self.launched = launched self.commands = Commands_pb2_grpc.CommandsStub(self.channel) diff --git a/GrpcInterface/RiaGrpcServer.cpp b/GrpcInterface/RiaGrpcServer.cpp index 9b822f7962..1340bbb6ef 100644 --- a/GrpcInterface/RiaGrpcServer.cpp +++ b/GrpcInterface/RiaGrpcServer.cpp @@ -151,6 +151,14 @@ void RiaGrpcServerImpl::initialize() QString requestedServerAddress = QString( "localhost:%1" ).arg( m_portNumber ); builder.AddListeningPort( requestedServerAddress.toStdString(), grpc::InsecureServerCredentials(), &m_portNumber ); + // A single request or reply can be large, e.g. the schedule text generated from a full + // production history or a raw text block imported into the event timeline. The gRPC default + // limit of 4 MB is easily exceeded by such payloads, so raise it well above any realistic deck + // size. The client uses a matching limit (see rips/instance.py). + const int maxMessageSize = 128 * 1024 * 1024; + builder.SetMaxReceiveMessageSize( maxMessageSize ); + builder.SetMaxSendMessageSize( maxMessageSize ); + for ( auto key : RiaGrpcServiceFactory::instance()->allKeys() ) { std::shared_ptr service( RiaGrpcServiceFactory::instance()->create( key ) );