We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
gRPC: Received message larger than max (11059277 vs. 4194304)
We are using mlserver (gRPC) for serving custom PyTorch ML Model and are sending images of size 640x640x3 . But because of the size we are getting the below error:

> status = StatusCode.RESOURCE_EXHAUSTED
> 	details = "Received message larger than max (11059277 vs. 4194304)"
> 	debug_error_string = "{"created":"@1630074151.799330000","description":"Error received from peer ipv4:0.0.0.0:28081","file":"src/core/lib/surface/call.cc","file_line":1070,"grpc_message":"Received message larger than max (11059277 vs. 4194304)","grpc_status":8}"

Setting the following on client side did not work:
```
maxMsgLength = 20 * 1024 * 1024
ch_options = [('grpc.max_message_length', maxMsgLength),
              ('grpc.max_send_message_length', maxMsgLength),
              ('grpc.max_receive_message_length', maxMsgLength)]
channel = grpc.insecure_channel(f'{host}:{port}', options=ch_options)

```
However setting it on server side worked:
```
def _create_server(self):
        self._inference_servicer = InferenceServicer(self._data_plane)
        self._model_repository_servicer = ModelRepositoryServicer(
            self._model_repository_handlers
        )
        channel_opt = [('grpc.max_send_message_length', 20 * 1024 * 1024), ('grpc.max_receive_message_length', 20 * 1024 * 1024)]
        self._server = aio.server(
            ThreadPoolExecutor(max_workers=self._settings.grpc_workers), options = channel_opt
        )

        add_GRPCInferenceServiceServicer_to_server(
            self._inference_servicer, self._server
        )

```
But this is not a proper solution, since our mlserver runs in a docker and does a pip install.
This should be part of the server config in MLServer.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `mlserver/grpc/server.py`
Content:
```
1 from grpc import aio
2 from concurrent.futures import ThreadPoolExecutor
3 
4 from ..handlers import DataPlane, ModelRepositoryHandlers
5 from ..settings import Settings
6 
7 from .servicers import InferenceServicer, ModelRepositoryServicer
8 from .dataplane_pb2_grpc import add_GRPCInferenceServiceServicer_to_server
9 from .model_repository_pb2_grpc import add_ModelRepositoryServiceServicer_to_server
10 
11 
12 class GRPCServer:
13     def __init__(
14         self,
15         settings: Settings,
16         data_plane: DataPlane,
17         model_repository_handlers: ModelRepositoryHandlers,
18     ):
19         self._settings = settings
20         self._data_plane = data_plane
21         self._model_repository_handlers = model_repository_handlers
22 
23     def _create_server(self):
24         self._inference_servicer = InferenceServicer(self._data_plane)
25         self._model_repository_servicer = ModelRepositoryServicer(
26             self._model_repository_handlers
27         )
28         self._server = aio.server(
29             ThreadPoolExecutor(max_workers=self._settings.grpc_workers)
30         )
31 
32         add_GRPCInferenceServiceServicer_to_server(
33             self._inference_servicer, self._server
34         )
35         add_ModelRepositoryServiceServicer_to_server(
36             self._model_repository_servicer, self._server
37         )
38 
39         self._server.add_insecure_port(
40             f"{self._settings.host}:{self._settings.grpc_port}"
41         )
42 
43         return self._server
44 
45     async def start(self):
46         self._create_server()
47 
48         await self._server.start()
49         await self._server.wait_for_termination()
50 
51     async def stop(self):
52         # TODO: Read from config
53         await self._server.stop(grace=5)
54
```

Path: `mlserver/settings.py`
Content:
```
1 from typing import List, Optional
2 from pydantic import BaseSettings, PyObject
3 
4 from .version import __version__
5 from .types import MetadataTensor
6 
7 ENV_PREFIX_SETTINGS = "MLSERVER_"
8 ENV_PREFIX_MODEL_SETTINGS = "MLSERVER_MODEL_"
9 
10 
11 class Settings(BaseSettings):
12     class Config:
13         env_prefix = ENV_PREFIX_SETTINGS
14 
15     debug: bool = True
16 
17     # Model repository folder
18     model_repository_root: str = "."
19     load_models_at_startup: bool = True
20 
21     # Server metadata
22     server_name: str = "mlserver"
23     server_version: str = __version__
24     extensions: List[str] = []
25 
26     # Server settings
27     host: str = "0.0.0.0"
28     http_port: int = 8080
29     grpc_port: int = 8081
30     grpc_workers: int = 10
31 
32 
33 class ModelParameters(BaseSettings):
34     """
35     Parameters that apply only to a particular instance of a model.
36     This can include things like model weights.
37     The main difference with respect to ModelSettings is that parameters can
38     change on each instance (e.g. each version) of the model.
39     """
40 
41     class Config:
42         env_prefix = ENV_PREFIX_MODEL_SETTINGS
43 
44     uri: Optional[str] = None
45     version: Optional[str] = None
46     format: Optional[str] = None
47     extra: Optional[dict] = {}
48 
49 
50 class ModelSettings(BaseSettings):
51     class Config:
52         env_prefix = ENV_PREFIX_MODEL_SETTINGS
53 
54     name: str = ""
55 
56     # Model metadata
57     platform: str = ""
58     versions: Optional[List[str]] = []
59     inputs: Optional[List[MetadataTensor]] = []
60     outputs: Optional[List[MetadataTensor]] = []
61 
62     # Parallel settings
63     parallel_workers: Optional[int] = 4
64 
65     # Custom model class implementation
66     implementation: PyObject = "mlserver.model.MLModel"  # type: ignore
67 
68     # Model parameters are meant to be set directly by the MLServer runtime.
69     # However, it's also possible to override them manually.
70     parameters: Optional[ModelParameters] = None
71
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/mlserver/grpc/server.py b/mlserver/grpc/server.py
--- a/mlserver/grpc/server.py
+++ b/mlserver/grpc/server.py
@@ -1,5 +1,6 @@
 from grpc import aio
 from concurrent.futures import ThreadPoolExecutor
+from typing import Any, List, Tuple
 
 from ..handlers import DataPlane, ModelRepositoryHandlers
 from ..settings import Settings
@@ -25,8 +26,10 @@
         self._model_repository_servicer = ModelRepositoryServicer(
             self._model_repository_handlers
         )
+
         self._server = aio.server(
-            ThreadPoolExecutor(max_workers=self._settings.grpc_workers)
+            ThreadPoolExecutor(max_workers=self._settings.grpc_workers),
+            options=self._get_options(),
         )
 
         add_GRPCInferenceServiceServicer_to_server(
@@ -42,6 +45,19 @@
 
         return self._server
 
+    def _get_options(self) -> List[Tuple[str, Any]]:
+        options = []
+
+        max_message_length = self._settings.grpc_max_message_length
+        if max_message_length is not None:
+            options += [
+                ("grpc.max_message_length", max_message_length),
+                ("grpc.max_send_message_length", max_message_length),
+                ("grpc.max_receive_message_length", max_message_length),
+            ]
+
+        return options
+
     async def start(self):
         self._create_server()
 
diff --git a/mlserver/settings.py b/mlserver/settings.py
--- a/mlserver/settings.py
+++ b/mlserver/settings.py
@@ -28,6 +28,7 @@
     http_port: int = 8080
     grpc_port: int = 8081
     grpc_workers: int = 10
+    grpc_max_message_length: Optional[int] = None
 
 
 class ModelParameters(BaseSettings):

{"golden_diff": "diff --git a/mlserver/grpc/server.py b/mlserver/grpc/server.py\n--- a/mlserver/grpc/server.py\n+++ b/mlserver/grpc/server.py\n@@ -1,5 +1,6 @@\n from grpc import aio\n from concurrent.futures import ThreadPoolExecutor\n+from typing import Any, List, Tuple\n \n from ..handlers import DataPlane, ModelRepositoryHandlers\n from ..settings import Settings\n@@ -25,8 +26,10 @@\n         self._model_repository_servicer = ModelRepositoryServicer(\n             self._model_repository_handlers\n         )\n+\n         self._server = aio.server(\n-            ThreadPoolExecutor(max_workers=self._settings.grpc_workers)\n+            ThreadPoolExecutor(max_workers=self._settings.grpc_workers),\n+            options=self._get_options(),\n         )\n \n         add_GRPCInferenceServiceServicer_to_server(\n@@ -42,6 +45,19 @@\n \n         return self._server\n \n+    def _get_options(self) -> List[Tuple[str, Any]]:\n+        options = []\n+\n+        max_message_length = self._settings.grpc_max_message_length\n+        if max_message_length is not None:\n+            options += [\n+                (\"grpc.max_message_length\", max_message_length),\n+                (\"grpc.max_send_message_length\", max_message_length),\n+                (\"grpc.max_receive_message_length\", max_message_length),\n+            ]\n+\n+        return options\n+\n     async def start(self):\n         self._create_server()\n \ndiff --git a/mlserver/settings.py b/mlserver/settings.py\n--- a/mlserver/settings.py\n+++ b/mlserver/settings.py\n@@ -28,6 +28,7 @@\n     http_port: int = 8080\n     grpc_port: int = 8081\n     grpc_workers: int = 10\n+    grpc_max_message_length: Optional[int] = None\n \n \n class ModelParameters(BaseSettings):\n", "issue": "gRPC: Received message larger than max (11059277 vs. 4194304)\nWe are using mlserver (gRPC) for serving custom PyTorch ML Model and are sending images of size 640x640x3 . But because of the size we are getting the below error:\r\n\r\n> status = StatusCode.RESOURCE_EXHAUSTED\r\n> \tdetails = \"Received message larger than max (11059277 vs. 4194304)\"\r\n> \tdebug_error_string = \"{\"created\":\"@1630074151.799330000\",\"description\":\"Error received from peer ipv4:0.0.0.0:28081\",\"file\":\"src/core/lib/surface/call.cc\",\"file_line\":1070,\"grpc_message\":\"Received message larger than max (11059277 vs. 4194304)\",\"grpc_status\":8}\"\r\n\r\nSetting the following on client side did not work:\r\n```\r\nmaxMsgLength = 20 * 1024 * 1024\r\nch_options = [('grpc.max_message_length', maxMsgLength),\r\n              ('grpc.max_send_message_length', maxMsgLength),\r\n              ('grpc.max_receive_message_length', maxMsgLength)]\r\nchannel = grpc.insecure_channel(f'{host}:{port}', options=ch_options)\r\n\r\n```\r\nHowever setting it on server side worked:\r\n```\r\ndef _create_server(self):\r\n        self._inference_servicer = InferenceServicer(self._data_plane)\r\n        self._model_repository_servicer = ModelRepositoryServicer(\r\n            self._model_repository_handlers\r\n        )\r\n        channel_opt = [('grpc.max_send_message_length', 20 * 1024 * 1024), ('grpc.max_receive_message_length', 20 * 1024 * 1024)]\r\n        self._server = aio.server(\r\n            ThreadPoolExecutor(max_workers=self._settings.grpc_workers), options = channel_opt\r\n        )\r\n\r\n        add_GRPCInferenceServiceServicer_to_server(\r\n            self._inference_servicer, self._server\r\n        )\r\n\r\n```\r\nBut this is not a proper solution, since our mlserver runs in a docker and does a pip install.\r\nThis should be part of the server config in MLServer.\n", "before_files": [{"content": "from grpc import aio\nfrom concurrent.futures import ThreadPoolExecutor\n\nfrom ..handlers import DataPlane, ModelRepositoryHandlers\nfrom ..settings import Settings\n\nfrom .servicers import InferenceServicer, ModelRepositoryServicer\nfrom .dataplane_pb2_grpc import add_GRPCInferenceServiceServicer_to_server\nfrom .model_repository_pb2_grpc import add_ModelRepositoryServiceServicer_to_server\n\n\nclass GRPCServer:\n    def __init__(\n        self,\n        settings: Settings,\n        data_plane: DataPlane,\n        model_repository_handlers: ModelRepositoryHandlers,\n    ):\n        self._settings = settings\n        self._data_plane = data_plane\n        self._model_repository_handlers = model_repository_handlers\n\n    def _create_server(self):\n        self._inference_servicer = InferenceServicer(self._data_plane)\n        self._model_repository_servicer = ModelRepositoryServicer(\n            self._model_repository_handlers\n        )\n        self._server = aio.server(\n            ThreadPoolExecutor(max_workers=self._settings.grpc_workers)\n        )\n\n        add_GRPCInferenceServiceServicer_to_server(\n            self._inference_servicer, self._server\n        )\n        add_ModelRepositoryServiceServicer_to_server(\n            self._model_repository_servicer, self._server\n        )\n\n        self._server.add_insecure_port(\n            f\"{self._settings.host}:{self._settings.grpc_port}\"\n        )\n\n        return self._server\n\n    async def start(self):\n        self._create_server()\n\n        await self._server.start()\n        await self._server.wait_for_termination()\n\n    async def stop(self):\n        # TODO: Read from config\n        await self._server.stop(grace=5)\n", "path": "mlserver/grpc/server.py"}, {"content": "from typing import List, Optional\nfrom pydantic import BaseSettings, PyObject\n\nfrom .version import __version__\nfrom .types import MetadataTensor\n\nENV_PREFIX_SETTINGS = \"MLSERVER_\"\nENV_PREFIX_MODEL_SETTINGS = \"MLSERVER_MODEL_\"\n\n\nclass Settings(BaseSettings):\n    class Config:\n        env_prefix = ENV_PREFIX_SETTINGS\n\n    debug: bool = True\n\n    # Model repository folder\n    model_repository_root: str = \".\"\n    load_models_at_startup: bool = True\n\n    # Server metadata\n    server_name: str = \"mlserver\"\n    server_version: str = __version__\n    extensions: List[str] = []\n\n    # Server settings\n    host: str = \"0.0.0.0\"\n    http_port: int = 8080\n    grpc_port: int = 8081\n    grpc_workers: int = 10\n\n\nclass ModelParameters(BaseSettings):\n    \"\"\"\n    Parameters that apply only to a particular instance of a model.\n    This can include things like model weights.\n    The main difference with respect to ModelSettings is that parameters can\n    change on each instance (e.g. each version) of the model.\n    \"\"\"\n\n    class Config:\n        env_prefix = ENV_PREFIX_MODEL_SETTINGS\n\n    uri: Optional[str] = None\n    version: Optional[str] = None\n    format: Optional[str] = None\n    extra: Optional[dict] = {}\n\n\nclass ModelSettings(BaseSettings):\n    class Config:\n        env_prefix = ENV_PREFIX_MODEL_SETTINGS\n\n    name: str = \"\"\n\n    # Model metadata\n    platform: str = \"\"\n    versions: Optional[List[str]] = []\n    inputs: Optional[List[MetadataTensor]] = []\n    outputs: Optional[List[MetadataTensor]] = []\n\n    # Parallel settings\n    parallel_workers: Optional[int] = 4\n\n    # Custom model class implementation\n    implementation: PyObject = \"mlserver.model.MLModel\"  # type: ignore\n\n    # Model parameters are meant to be set directly by the MLServer runtime.\n    # However, it's also possible to override them manually.\n    parameters: Optional[ModelParameters] = None\n", "path": "mlserver/settings.py"}], "after_files": [{"content": "from grpc import aio\nfrom concurrent.futures import ThreadPoolExecutor\nfrom typing import Any, List, Tuple\n\nfrom ..handlers import DataPlane, ModelRepositoryHandlers\nfrom ..settings import Settings\n\nfrom .servicers import InferenceServicer, ModelRepositoryServicer\nfrom .dataplane_pb2_grpc import add_GRPCInferenceServiceServicer_to_server\nfrom .model_repository_pb2_grpc import add_ModelRepositoryServiceServicer_to_server\n\n\nclass GRPCServer:\n    def __init__(\n        self,\n        settings: Settings,\n        data_plane: DataPlane,\n        model_repository_handlers: ModelRepositoryHandlers,\n    ):\n        self._settings = settings\n        self._data_plane = data_plane\n        self._model_repository_handlers = model_repository_handlers\n\n    def _create_server(self):\n        self._inference_servicer = InferenceServicer(self._data_plane)\n        self._model_repository_servicer = ModelRepositoryServicer(\n            self._model_repository_handlers\n        )\n\n        self._server = aio.server(\n            ThreadPoolExecutor(max_workers=self._settings.grpc_workers),\n            options=self._get_options(),\n        )\n\n        add_GRPCInferenceServiceServicer_to_server(\n            self._inference_servicer, self._server\n        )\n        add_ModelRepositoryServiceServicer_to_server(\n            self._model_repository_servicer, self._server\n        )\n\n        self._server.add_insecure_port(\n            f\"{self._settings.host}:{self._settings.grpc_port}\"\n        )\n\n        return self._server\n\n    def _get_options(self) -> List[Tuple[str, Any]]:\n        options = []\n\n        max_message_length = self._settings.grpc_max_message_length\n        if max_message_length is not None:\n            options += [\n                (\"grpc.max_message_length\", max_message_length),\n                (\"grpc.max_send_message_length\", max_message_length),\n                (\"grpc.max_receive_message_length\", max_message_length),\n            ]\n\n        return options\n\n    async def start(self):\n        self._create_server()\n\n        await self._server.start()\n        await self._server.wait_for_termination()\n\n    async def stop(self):\n        # TODO: Read from config\n        await self._server.stop(grace=5)\n", "path": "mlserver/grpc/server.py"}, {"content": "from typing import List, Optional\nfrom pydantic import BaseSettings, PyObject\n\nfrom .version import __version__\nfrom .types import MetadataTensor\n\nENV_PREFIX_SETTINGS = \"MLSERVER_\"\nENV_PREFIX_MODEL_SETTINGS = \"MLSERVER_MODEL_\"\n\n\nclass Settings(BaseSettings):\n    class Config:\n        env_prefix = ENV_PREFIX_SETTINGS\n\n    debug: bool = True\n\n    # Model repository folder\n    model_repository_root: str = \".\"\n    load_models_at_startup: bool = True\n\n    # Server metadata\n    server_name: str = \"mlserver\"\n    server_version: str = __version__\n    extensions: List[str] = []\n\n    # Server settings\n    host: str = \"0.0.0.0\"\n    http_port: int = 8080\n    grpc_port: int = 8081\n    grpc_workers: int = 10\n    grpc_max_message_length: Optional[int] = None\n\n\nclass ModelParameters(BaseSettings):\n    \"\"\"\n    Parameters that apply only to a particular instance of a model.\n    This can include things like model weights.\n    The main difference with respect to ModelSettings is that parameters can\n    change on each instance (e.g. each version) of the model.\n    \"\"\"\n\n    class Config:\n        env_prefix = ENV_PREFIX_MODEL_SETTINGS\n\n    uri: Optional[str] = None\n    version: Optional[str] = None\n    format: Optional[str] = None\n    extra: Optional[dict] = {}\n\n\nclass ModelSettings(BaseSettings):\n    class Config:\n        env_prefix = ENV_PREFIX_MODEL_SETTINGS\n\n    name: str = \"\"\n\n    # Model metadata\n    platform: str = \"\"\n    versions: Optional[List[str]] = []\n    inputs: Optional[List[MetadataTensor]] = []\n    outputs: Optional[List[MetadataTensor]] = []\n\n    # Parallel settings\n    parallel_workers: Optional[int] = 4\n\n    # Custom model class implementation\n    implementation: PyObject = \"mlserver.model.MLModel\"  # type: ignore\n\n    # Model parameters are meant to be set directly by the MLServer runtime.\n    # However, it's also possible to override them manually.\n    parameters: Optional[ModelParameters] = None\n", "path": "mlserver/settings.py"}]}