Flask gRPC betterproto socket.gaierror:[Errno 8] nodename 或 servname 提供,或未知

Flask gRPC betterproto socket.gaierror: [Errno 8] nodename nor servname provided, or not known

提问人:Kholdarbekov 提问时间:7/23/2022 更新时间:7/23/2022 访问量:421

问:

我正在使用 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)
python 套接字 烧瓶 异步 gRPC

评论


答:

0赞 Kholdarbekov 7/23/2022 #1

回答我自己的问题!

我发现我以错误的方式将参数发送到频道,因为它不应该app.pyChannel(host=SERVICE_HOST, port=SERVICE_PORT)Channel(f"{SERVICE_HOST}:{SERVICE_PORT}")