使用Bazel构建并运行Python gRPC服务器时遭遇Protobuf版本冲突的问题咨询
Bazel构建并运行Python gRPC服务器时遭遇Protobuf版本冲突的问题咨询
我正在尝试搭建一个更大型的Bazel基础设施,主要想实现两个目标:
- 用
rules_proto_grpc_python从.proto文件生成适配gRPC的.py文件 - 通过
py_binary运行实现了上述接口的服务器代码
但我遇到了下面这个错误:
google.protobuf.runtime_version.VersionError: Detected incompatible Protobuf Gencode/Runtime versions when loading helloworld/hello.proto: gencode 5.29.1 runtime 5.27.2. Runtime version cannot be older than the linked gencode version. See Protobuf version guarantees at https://protobuf.dev/support/cross-version-runtime-guarantee.
这个错误说明rules_proto_grpc_python用来生成.py文件的Protobuf版本,和运行时依赖的Protobuf版本不匹配。我尝试给py_binary指定protobuf>=5.29.1的依赖,但因为项目里其他包的版本冲突,这个方案走不通。在这个最小复现示例里虽然确实能这么做,但会弹出一堆关于冲突符号链接的警告,这看起来也很有隐患。
所以我想请教有没有办法做到以下两点之一:
- 给
rules_proto_grpc_python指定要使用的Protobuf版本 - 换一种方式从.proto文件生成对应的.py文件?
编辑于2025-02-27
我在大型仓库里反复调整依赖配置后,终于让它正常运行了——只需要指定Protobuf的最低版本就解决了问题。
以下是最小复现示例的相关文件:
顶层MODULE.bazel文件
# MODULE.bazel bazel_dep(name = "aspect_bazel_lib", version = "2.7.8") bazel_dep(name = "aspect_rules_py", version = "1.3.2") bazel_dep(name = "rules_python", version = "1.1.0") bazel_dep(name = "rules_proto", version = "7.1.0") bazel_dep(name = "rules_proto_grpc_python", version = "5.0.0") # deps for python projects. _PY_MINOR_VER = 10 _PY_VERSION = "3.%s" % _PY_MINOR_VER _PY_VER_ = "python_3_%s" % _PY_MINOR_VER python = use_extension("@rules_python//python/extensions:python.bzl", "python") python.toolchain( python_version = _PY_VERSION, is_default = True, ) # You can use this repo mapping to ensure that your BUILD.bazel files don't need # to be updated when the python version changes to a different `3.12` version. use_repo( python, "python_3_%s" % _PY_MINOR_VER, ) pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip") pip.parse( hub_name = "pypi", # We need to use the same version here as in the `python.toolchain` call. python_version = _PY_VERSION, requirements_lock = "//:requirements_lock.txt", ) use_repo(pip, "pypi")
/proto_library/proto/hello.proto文件
# proto_library/proto/hello.proto syntax = "proto3"; package helloworld; // The greeting service definition. service Greeter { // Sends a greeting rpc SayHello (HelloRequest) returns (HelloReply) {} } // The request message containing the user's name. message HelloRequest { string name = 1; } // The response message containing the greetings message HelloReply { string message = 1; }
proto文件同目录下的BUILD.bazel文件
# proto_library/proto/BUILD.bazel load("@rules_proto//proto:defs.bzl", "proto_library") load("@rules_proto_grpc_python//:defs.bzl", "py_proto_library", "py_grpc_library") proto_library( name = "hello_proto", srcs = ["hello.proto"], # Add these to control Python package structure strip_import_prefix = "/proto_library/proto", import_prefix = "helloworld", visibility = ["//visibility:public"], ) py_proto_library( name = "hello_py_proto", protos = [":hello_proto"], visibility = ["//visibility:public"], ) py_grpc_library( name = "hello_py_grpc", protos = [":hello_proto"], visibility = ["//visibility:public"], deps = [":hello_py_proto"], )
实现服务器逻辑的Python代码
# proto_library/src/hello_server.py import logging import sys from concurrent import futures import grpc from helloworld import hello_pb2, hello_pb2_grpc class Greeter(hello_pb2_grpc.GreeterServicer): def SayHello(self, request, context): return hello_pb2.HelloReply(message="Hello, %s!" % request.name) def serve(): port = "50051" server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) hello_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server) server.add_insecure_port("[::]:" + port) server.start() print("Server started, listening on " + port) server.wait_for_termination() if __name__ == "__main__": logging.basicConfig() serve()
proto_library目录下的BUILD文件
# proto_library/BUILD.bazel load("@aspect_rules_py//py:defs.bzl", "py_binary", "py_library") load("@pypi//:requirements.bzl", "requirement") py_binary( name = "hello_test", srcs = ["src/hello_server.py"], deps = [ "//proto_library/proto:hello_py_proto", "//proto_library/proto:hello_py_grpc", requirement("grpcio"), requirement("protobuf"), ], # Add these to handle Python packaging imports = [".."], # Make parent directories importable visibility = ["//visibility:public"], package_collisions = "warning", # Create proper Python package structure main = "hello_server.py", )
备注:内容来源于stack exchange,提问作者kgully
相关产品推荐
相关产品推荐

