open-rmf / rmf-web

Apache License 2.0
87 stars 42 forks source link

data backend service #109

Closed koonpeng closed 4 years ago

koonpeng commented 4 years ago

Replaces the numerous clients (soss, trajectory, negotiation, others) with a canonical server, which handles marshaling between each data sources.

Current: image

New: image

Current problem: Because the dashboard connects directly to each service, they must support web standards (http, websockets etc). ROS2 is an example protocol which does not support web standards, so we have to use soss to bridge it. There may be other protocols which may not support web standards which we may need in the future, hl7 for example. With the current pattern, we would need a bridge for each of these unsupported protocols, and each bridge would also brings in another client to implement in the dashboard.

The new proposal will unify all data sources into a canonical system (graphql for example). The server will convert the various data sources into a format suitable to be consumed by the dashboard.

Advantages:

Disadvantages:


I looked at some RPC libraries available, here are some comparisons on the feature set that we would need.

chart

See https://docs.google.com/spreadsheets/d/1IPN_rKSwGaXleJ3KcT6TCHM1V1uuOye76gk3mJxREqs/edit?usp=sharing for more detailed notes.

Some rpc implementations have a type system (graphql, grpc etc). This usually means a language agnostic message definition files, this could be a double edged sword, the advantage of it is that it allows the framework to generate language specific constructs to provide strongly typed bindings. The disadvantage is that as long as we are only supporting js/ts, we can just write those definitions directly. It also brings in another layer of complexity as ros2 already has its own type system which romi-js uses to generate typescript definitions, moving to these rpc frameworks would mean converting ros2's definitions to the rpc's format and then generating typescript code based on that.

ChawinTan commented 4 years ago

No more dependency on soss (soss is not actively developed and is a low priority component of rmf).

Does this mean we will write something entirely new in the server to replace soss entirely or will it be more like a layer to hide the bridge but the bridge is still needed somewhere?

My current understanding is that no dependency on soss === soss does not connect directly to the dashboard but to the canonical server instead.

koonpeng commented 4 years ago

sry, I meant for it to connect to ros2 directly, bypassing soss. It can use either rclnodejs, rclpy or rclcpp, or other rcl bindings depending what language we use for the server. I will update the pictures.

matiasbavera commented 4 years ago

+1 to this idea. Outdated after update of the issue description. Thinking a little further in time, we could have a possible bottleneck with the proposed architecture; maybe we can solve that on deploy time, like for example, having one deployed server per service or having a load balancer.

Does this mean we will write something entirely new in the server to replace soss entirely or will it be more like a layer to hide the bridge but the bridge is still needed somewhere?

My current understanding is that no dependency on soss === soss does not connect directly to the dashboard but to the canonical server instead.

Lol, the same thing cross my mind.

sry, I meant for it to connect to ros2 directly, bypassing soss. It can use either rclnodejs, rclpy or rclcpp, or other rcl bindings depending what language we use for the server. I will update the pictures.

Cool, thanks for the clarification.

The new proposal will unify all data sources into a canonical system (graphql for example). The server will convert the various data sources into a format suitable to be consumed by the dashboard.

Not against Graphql, and just to be on the same page, we will be just using the Schema Stitching for Combining Schemas benefit of it (maybe the no API versioning too). I'm saying this (and maybe I'm wrong) because I'm not seeing a case where we will have an overfetching or an underfetching because what we want to get are the messages that already have all the information in a request.

We can use apollo as our Graphql client. https://www.apollographql.com/docs/react/. It has a lot of cool functionalities:

src: "https://www.apollographql.com/docs/react/"

We can use all of this cool features except for the Local State (happily =) )

HTH,

koonpeng commented 4 years ago

updated the opening comment with a comparison of some rpc frameworks, at the moment it doesn't look like there is anything suitable, what does everyone think?

At the moment, I feel that the best approach now seems to be either writing a js client for msgpack-rpc, or using a custom variant of json-rpc that uses msgpack/bson as the payload.

matiasbavera commented 4 years ago

At the moment, I feel that the best approach now seems to be either writing a js client for msgpack-rpc, or using a custom variant of json-rpc that uses msgpack/bson as the payload.

Yeah, you're right it doesn't look like there is anything suitable for our needs. I found a client for messagepack-rpc (I think it can be useful if we want to go through that path). https://stackoverflow.com/questions/9457657/how-to-invoke-a-messagepack-rpc-service-from-javascript https://github.com/nori0428/msgpack.rpc.js

Since this doesn't have native browser support we may want to check the performance of this under heavy load circumstances.

custom variant of json-rpc that uses msgpack/bson as the payload.

I don't have anything against this either, but wouldn't we have to double convert messages to use the content in this case?

Also, I think we can use the API-gateway architecture to have one point to access multiple services. https://www.redhat.com/en/topics/api/what-does-an-api-gateway-do#:~:text=An%20API%20gateway%20is%20an,and%20return%20the%20appropriate%20result.

I'll keep digging in case I find something else.

koonpeng commented 4 years ago

Also, I think we can use the API-gateway architecture to have one point to access multiple services. https://www.redhat.com/en/topics/api/what-does-an-api-gateway-do#:~:text=An%20API%20gateway%20is%20an,and%20return%20the%20appropriate%20result.

You are right, what we are looking for is more of an api gateway instead of just a simple rpc mechanism. These are some of the offerings available (https://alternativeto.net/browse/search?q=api-gateway). One of our main data sources is ros2, I doubt that is supported by any of the popular offerings, but they should all support plugins to add custom backends. I wonder if we should use one of these gateways or make something much less complex ourselves?

Edit: looks like there really isnt any good way to add a ros2 plugin, the most promising is Tyk but I have my doubts.

matiasbavera commented 4 years ago

You are right, what we are looking for is more of an api gateway instead of just a simple rpc mechanism. These are some of the offerings available (https://alternativeto.net/browse/search?q=api-gateway). One of our main data sources is ros2, I doubt that is supported by any of the popular offerings, but they should all support plugins to add custom backends. I wonder if we should use one of these gateways or make something much less complex ourselves?

Edit: looks like there really isnt any good way to add a ros2 plugin, the most promising is Tyk but I have my doubts.

  • krakend: plugin must be in go, there is no stable rcl bindings for go
  • kong: go or lua, neither of which has rcl bindings
  • tyk: python, javascript, lua, .net, java. python has 1st class ros2 support, js, java, .net has third-party support. However the python example uses synchronous programming, and the doc says the python interpreter is embedded in Tyk so I'm not sure if we can run rclpy on it.

Cool! thanks for the summary! Yeah, you're right, if we can't run rclpy we'll run out of options, as you said, maybe we should start to handle the possibility of doing something less complex ourselves.

matiasbavera commented 4 years ago

Hi @matiasinsaurralde, just in case you can give us a hand,

We need to use an API gateway and we're considering Tyk because it looks great. The examples we saw use synchronous programming, and the doc says that the Python interpreter is embedded in Tyk. What is holding us back (@koonpeng just correct me if I'm wrong) is that we have to install a library called rclpy (ROS Client Library for Python) and use asynchronous programming.

So my question is this, would there be some simple way to add that library to the embedded python interpreter and use that library in a plugin? Could asynchronous programming be used?

matiasinsaurralde commented 4 years ago

Hi, the way we embed Python into Tyk is by loading the CPython on runtime, using libdl/dlopen, this would make use of your default Python installation. You should be able to use any Python module with it as long as you've previously installed it using pip or similar. I haven't tried async Python code in this context and I'm not sure if CPython has any limitations in that scenario, I would say that we embed it in a quite standard way.

matiasinsaurralde commented 4 years ago

I would be happy to try it out, if you can provide a simple rclpy sample that I could run.

matiasbavera commented 4 years ago

Hi, the way we embed Python into Tyk is by loading the CPython on runtime, using libdl/dlopen, this would make use of your default Python installation. You should be able to use any Python module with it as long as you've previously installed it using pip or similar. I haven't tried async Python code in this context and I'm not sure if CPython has any limitations in that scenario, I would say that we embed it in a quite standard way.

Awesome! I really appreciate your help tocayo! =)

I would be happy to try it out, if you can provide a simple rclpy sample that I could run.

I'll check with @koonpeng if it has something at hand.

koonpeng commented 4 years ago

Hi @matiasinsaurralde, thanks for taking the time to look at this.

For abit of background, we are currently receiving data from multiple sources, they are mainly websockets and ros2 now but there is a possibility in the future that we will need to receive data from other obscure protocols like hl7. These non-web protocols would need a bridge, the current idea is to convert them to msgpack and serve it as binary through http (preferably http2) or websockets.

We are looking at Tyk to help us manage all these endpoints, the challenge would be to get these non-web protocols to work, with regards to ros2 the considerations we have are:

For reference, here is an example rclpy code to perform a ros2 subscription

https://github.com/ros2/examples/blob/master/rclpy/topics/minimal_subscriber/examples_rclpy_minimal_subscriber/subscriber_lambda.py

rclpy.spin starts its own event loop and a callback is invoked when a message comes in. So the Tyk plugin cannot return a response synchronously, and would also need to "stream" the response in chunks as the messages arrive.

koonpeng commented 4 years ago

121 merged