提问人:Kholdarbekov 提问时间:7/23/2022 更新时间:7/23/2022 访问量:421
Flask gRPC betterproto socket.gaierror:[Errno 8] nodename 或 servname 提供,或未知
Flask gRPC betterproto socket.gaierror: [Errno 8] nodename nor servname provided, or not known
问:
我正在使用 gRPC 创建微服务。为了从 .proto 文件生成代码,我使用 betterproto 而不是 grpcio-tools。当我使用 Flask 作为客户端应用程序来调用服务器的函数时,它出现错误:
_, protocol = await self._loop.create_connection(
File "/opt/homebrew/Cellar/[email protected]/3.9.12_1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/asyncio/base_events.py", line 1026, in create_connection
infos = await self._ensure_resolved(
File "/opt/homebrew/Cellar/[email protected]/3.9.12_1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/asyncio/base_events.py", line 1405, in _ensure_resolved
return await loop.getaddrinfo(host, port, family=family, type=type,
File "/opt/homebrew/Cellar/[email protected]/3.9.12_1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/asyncio/base_events.py", line 861, in getaddrinfo
return await self.run_in_executor(
File "/opt/homebrew/Cellar/[email protected]/3.9.12_1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/concurrent/futures/thread.py", line 58, in run
result = self.fn(*self.args, **self.kwargs)
File "/opt/homebrew/Cellar/[email protected]/3.9.12_1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/socket.py", line 954, in getaddrinfo
for res in _socket.getaddrinfo(host, port, family, type, proto, flags):
socket.gaierror: [Errno 8] nodename nor servname provided, or not known
我使用的是 MacOS、Python 3.9.12、protobuf 预发布版本。如何解决此错误?
db.proto
syntax = "proto3";
package db;
import "google/protobuf/timestamp.proto";
message Box {
string name = 1;
int32 id = 2;
int32 price = 3;
string description = 4;
string category = 5;
int32 quantity = 6;
google.protobuf.Timestamp created_at = 7;
}
enum RequestStatus
{
OK = 0;
ERROR = 1;
}
message GetAllBoxesRequest {
}
message GetBoxesResponse {
repeated Box box = 1;
RequestStatus status = 2;
}
service DatabaseService {
rpc GetBoxes(GetAllBoxesRequest) returns (GetBoxesResponse) {}
}
这是从betterproto生成的文件
数据库/初始化.py
# Generated by the protocol buffer compiler. DO NOT EDIT!
# sources: db.proto
# plugin: python-betterproto
from dataclasses import dataclass
from datetime import datetime
from typing import Dict, List
import betterproto
from betterproto.grpc.grpclib_server import ServiceBase
import grpclib
class RequestStatus(betterproto.Enum):
OK = 0
ERROR = 1
@dataclass(eq=False, repr=False)
class Box(betterproto.Message):
name: str = betterproto.string_field(1)
id: int = betterproto.int32_field(2)
price: int = betterproto.int32_field(3)
description: str = betterproto.string_field(4)
category: str = betterproto.string_field(5)
quantity: int = betterproto.int32_field(6)
created_at: datetime = betterproto.message_field(7)
@dataclass(eq=False, repr=False)
class GetAllBoxesRequest(betterproto.Message):
pass
@dataclass(eq=False, repr=False)
class GetBoxesResponse(betterproto.Message):
box: List["Box"] = betterproto.message_field(1)
status: "RequestStatus" = betterproto.enum_field(2)
class DatabaseServiceStub(betterproto.ServiceStub):
async def get_boxes(self) -> "GetBoxesResponse":
request = GetAllBoxesRequest()
return await self._unary_unary(
"/db.DatabaseService/GetBoxes", request, GetBoxesResponse
)
class DatabaseServiceBase(ServiceBase):
async def get_boxes(self) -> "GetBoxesResponse":
raise grpclib.GRPCError(grpclib.const.Status.UNIMPLEMENTED)
async def __rpc_get_boxes(self, stream: grpclib.server.Stream) -> None:
request = await stream.recv_message()
request_kwargs = {}
response = await self.get_boxes(**request_kwargs)
await stream.send_message(response)
def __mapping__(self) -> Dict[str, grpclib.const.Handler]:
return {
"/db.DatabaseService/GetBoxes": grpclib.const.Handler(
self.__rpc_get_boxes,
grpclib.const.Cardinality.UNARY_UNARY,
GetAllBoxesRequest,
GetBoxesResponse,
),
}
server.py
import asyncio
import logging
from db import (
DatabaseServiceBase,
Box,
RequestStatus,
GetBoxesResponse,
)
from grpclib.server import Server
from pymongo import MongoClient
log = logging.getLogger(__name__)
def get_database():
CONNECTION_STRING = f"mongodb://{DB_USERNAME}:{DB_USER_PASSWORD}@{DB_HOST}:{DB_PORT}"
# Create a connection using MongoClient
client = MongoClient(CONNECTION_STRING)
# Create the database and return it
return client.boxes
boxes_db = get_database()
def dict_to_box(data):
if "_id" in data:
data["id"] = data.pop("_id")
return Box(**data)
class DatabaseService(DatabaseServiceBase):
async def get_boxes(self) -> "GetBoxesResponse":
boxes = boxes_db.boxes.find()
list_of_boxes = [dict_to_box(box) for box in boxes]
return GetBoxesResponse(box=list_of_boxes, status=RequestStatus.OK)
async def main():
server = Server([DatabaseService()])
await server.start("127.0.0.1", 50051)
await server.wait_closed()
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
由于 betterproto 生成异步函数,因此我额外安装了 Flask async: 。您可以在下面的 app.py 中看到我正在使用异步函数。pip install "flask[async]"
app.py(烧瓶)
import os
import asyncio
from flask import Flask, render_template
from grpclib.client import Channel
import db
app = Flask(__name__)
SERVICE_HOST = os.getenv("SERVICE_HOST", "127.0.0.1")
SERVICE_PORT = os.getenv("SERVICE_PORT", 50051)
@app.route("/")
async def render_homepage():
service_channel = Channel(f"{SERVICE_HOST}:{SERVICE_PORT}")
service = db.DatabaseServiceStub(service_channel)
get_boxes_response = await service.get_boxes() # <-- Error is throwing here
service_channel.close()
return render_template(
"index.html",
boxes=get_boxes_response.box,
)
if __name__ == '__main__':
app.run(debug=True)
答:
0赞
Kholdarbekov
7/23/2022
#1
回答我自己的问题!
我发现我以错误的方式将参数发送到频道,因为它不应该app.py
Channel(host=SERVICE_HOST, port=SERVICE_PORT)
Channel(f"{SERVICE_HOST}:{SERVICE_PORT}")
评论