2

我正忙于使用 Nameko 在 Python 中编写微服务后端。在寻找一个好的依赖注入包时,我遇到了 Injector。我真的很喜欢它,想和 Nameko 一起使用。然后我注意到了一个小问题:Nameko 实例化了 worker,并且不能使用开箱即用的依赖注入包。在尝试使用文档使其工作后,我偶然发现了包nameko-injector。我喜欢这个概念并试图实现它,但我得到了错误:

参数“绑定”未填充

使用 git 存储库中的示例代码(如下所示),问题发生在 NamekoInjector 类的初始化时。

微服务工作者类:

from nameko.rpc import rpc
from services.order_service import OrderService
from nameko_injector.core import NamekoInjector

INJECTOR = NamekoInjector()


@INJECTOR.decorate_service
class OrderWorker:

    # Mandatory field for service discovery
    name = "order_worker"

    def __init__(self, service: OrderService):
        self.service = service

    @rpc
    def get_orders(self):
        return self.service.orders()

OrderService 类:

from models.order.order import Order


class OrderService(object):

    def __init__(self):
        self.orders = [Order(1), Order(2)]

    def get_users(self):
        return self.orders

订单类:

class Order:
    def __init__(self, orderid):
        self.orderid = orderid

    def __str__(self):
        return str(self.orderid)

在查看 NamekoInjector 类时,我找不到绑定的确切作用和使用时间。首先,我什至不需要它,但是当我删除 NamekoInjector 类中的绑定字段和其他用法时,它仍然无法工作。有人可以帮我吗?谢谢!

4

1 回答 1

0

我意识到它已经晚了,但也许仍然相关。你非常接近解决方案。

缺失的部分:

  • configure传递给的函数NamekoInjector。它告诉库如何创建依赖项、它们的范围等。
  • 依赖项必须在入口点上指定,而不是在工作类初始化程序中。

我对您的代码进行了一些修改并将其放在一个模块中,但您可以随意组织代码。我这样做是为了简单。

下面的代码应该按原样工作。我还包括了一些帮助我运行项目的东西。

import injector
from nameko.rpc import rpc
from nameko_injector.core import NamekoInjector

class Order:
    def __init__(self, orderid):
        self.orderid = orderid

    def __str__(self):
        return str(self.orderid)

class OrderService(object):

    def __init__(self):
        self.orders = [Order(1), Order(2)]

    def get_orders(self):
        return self.orders
    
class Calculator:
    # class to demonstrate transitive dependency
    def __init__(self, randomiser):
        self.__randomiser = randomiser

    def calculate(self):
        return self.__randomiser()

# I usually keep the providers in the same place with the provided
@injector.provider
def provide_calculator() -> Calculator:
    # simple function that initialises one dependency
    return Calculator(randomiser=lambda: 42)

    
class ComplexInitService:
    """Service with own dependencies."""
    # the service to demonstrate providers.
    
    def __init__(self, calculator: Calculator):
        self.__calculator = calculator
  
    def calculate(self):
        return self.__calculator.calculate()

@injector.provider
def provide_complex_service(calculator: Calculator) -> ComplexInitService:
    return ComplexInitService(calculator)

def configure(binder):
    # function that tells the framework how to create a dependency based on the requested type
    # in the RPC/HTTP endpoint
    binder.bind(Calculator, to=provide_calculator)
    binder.bind(ComplexInitService, to=provide_calculator)
    
INJECTOR = NamekoInjector(configure)

@INJECTOR.decorate_service
class OrderWorker:

    # Mandatory field for service discovery
    name = "order_worker"

    @rpc
    def get_orders(self, service: OrderService):
        return [order.orderid for order in service.get_orders()]
    
    @rpc
    def calcualte_complex_stuff(self, service: ComplexInitService):
        return service.calculate()

我使用以下代码片段来初始化项目

rm pyproject.toml poetry.lock
poetry init \
--name nameko-injector-demo \
--no-interaction \
--dependency 'nameko-injector:1.1.2'
# poetry install

Nameko 配置示例

AMQP_URI: 'amqps://user:password@vhots.rmq.cloudamqp.com/vhost'
rpc_exchange: 'nameko-rpc'
max_workers: 10
parent_calls_tracked: 10

运行服务

poetry run nameko run --config config.yml service:OrderWorker

测试nameko shell

poetry run nameko shell --config config.yml
Nameko Python 3.8.9 (default, May 13 2021, 00:13:06)
[Clang 7.1.0 (tags/RELEASE_710/final)] shell on darwin
Broker: amqps://user:password@crow.rmq.cloudamqp.com/vhost (from --config)
>>> n.rpc.order_worker.get_orders()
[1, 2]
>>> n.rpc.order_worker.calcualte_complex_stuff()
42
于 2022-01-06T18:53:00.183 回答