Я хотел бы использовать вызовы RPC в своем приложении Volttron, но я не могу заставить работать любой вызов. Все вызовы завершаются с ошибкой «нет маршрута к хосту»
<stderr> ERROR: Unreachable: VIP error (113): No route to host: rpcserver.agent_1
По сути, есть два агента: агент "сервер", который экспортирует процедуру RPC, и агент "клиент", который вызывает процедуру.
В агенте «сервер» я экспортировал метод класса агента следующим образом:
@RPC.export('setConfig')
def setConfig(self, config):
self.config = config
self.initialize_device()
Агент "client" вызывает экспортированный метод следующим образом:
self.vip.rpc.call(sender, 'setConfig', self.config[sender]).get()
Где «отправитель» - это VIP-идентификатор агента «сервера» (который оказывается «rpcserver.agent_1» и соответствует значению аргумента «отправитель» при получении сообщения pubsub от rpcserver.agent. I определили идентификатор как rpcserver.agent_ {n} в файле IDENTITY).
Мои вопросы:
1. Я делаю что-то явно неправильно или пропускаю какой-то шаг для правильной настройки подсистемы RPC?
2. Предполагается ли, что «равноправный» аргумент в self.vip.rpc.call(peer, method, ...)
будет идентификатором агента? Это не ясно из документации (я пробовал другие варианты, такие как имя агента или uuid, но ни одна из них не работала)
Я использую volttron 5.1.0 в виртуальной машине Ubuntu.
Любая помощь в этом была бы очень признательна.
С наилучшими пожеланиями
ОПИСАНИЕ:
Это для управляющего приложения, которое соединяет несколько устройств. Агенты загружаются динамически в зависимости от доступных устройств в сети. Я хотел бы попробовать RPC вместо использования только pubsub. Я уже довольно тщательно искал код и документацию Volttron для получения подробных сведений об API RPC, но пока безрезультатно.
Минимальный класс "сервер":
class rpcServerAgent(Agent):
def __init__(self, config, **kwargs):
super(rpcServerAgent, self).__init__(**kwargs)
self.config = config
@Core.receiver('onstart')
def onstart(self, sender, **kwargs):
self.vip.rpc.export(self.setConfig, name='setConfig') # Also tried online exporting
# Ask the client to call the exported procedure
myutils.publish(self, topic='rpc/test', message={}) # myutils.publish publishes the message on pubsub
@RPC.export('setConfig')
def setConfig(self, config):
self.config = config
self.initialize_device()
myutils.publish(self, topic='rpc/clientready')
def initialize_device(self):
pass
Минимальный "клиентский" класс:
class rpcClientAgent(Agent):
def __init__(self, config, **kwargs):
super(rpcClientAgent, self).__init__(**kwargs)
self.config = {'rpcclient.agent_1': {'a': 0, 'b': 1}} # dummy config for rpcclient.agent
@Core.receiver('onstart')
def onstart(self, sender, **kwargs):
self.vip.pubsub.subscribe(peer='pubsub',
prefix='rpc',
callback=self.__handle_request__).get(timeout=5)
def call_RPC(self, sender):
sender = sender.strip() # volttron adds a newline at the end
self.vip.rpc.call(sender, 'setConfig', self.config[sender]).get() # assume that self.config[sender] is well-defined
@PubSub.subscribe('pubsub', 'rpc')
def __handle_request__(self, peer, sender, bus, topic, headers, message):
try:
msg = json.loads(message)
except:
raise ValueError("failed to decode message")
topics = topic.split('/')
if len(topics) > 1:
if topics[0] == 'rpc':
if topics[1] == 'test':
self.call_RPC(sender)
Ожидаемое поведение: вызывается экспортированная функция и публикуется сообщение pubsub с темой «rpc / clientready».
Фактическое поведение: сбой вызова RPc с ошибкой «Недоступен: ошибка VIP (113): нет маршрута к хосту: rpcclient.agent_1»
Редактировать
В конце концов я обнаружил, что проблема заключалась в том, что имя агента внутри вольтрона заканчивалось символом '\ n'. Это произошло из-за того, что gedit автоматически добавил его, и, очевидно, строка не была очищена вольттроном.