-
Notifications
You must be signed in to change notification settings - Fork 65
Description
Is your refactoring request related to a problem? Please describe.
Because all the components operate on MQTT messages and topics directly, the introduction of the requirement to support custom MQTT root made it so that all these components now need to query mqtt.topic_root
config option and use it when producing and consuming topics, which leads to the following bad things:
- significant boilerplate
- it's easy to forget to handle it
- it's sometimes hard handle it correctly in places that don't have access to a
tedge_config
object
Describe the solution you'd like
The MQTT topic root should be handled in a single place which is dedicated to reading MQTT messages from the MQTT broker and then passing it to the rest of the system: the MQTT actor
The actor, when receiving MQTT messages from other actors should append the topic root, and only then send them to the MQTT broker, and when receiving messages from the broker, it should strip out the prefix and only then send the message to other actors.
But, continuing to use mqtt_channel::Message
, just with the caveat that "topic does not include MQTT topic root" will be very awkward and troublesome to use. Instead, we should create a new type, called e.g. ThinEdgeMessage
, which actors will use to communicate with the MQTT actor, and then the MQTT actor would convert between ThinEdgeMessage
and MqttMessage
, in a single place, depending on a single piece of state read from the config.
ThinEdgeMessage
would be used for communication between local thin-edge services and the mapper, but it shouldn't be used for communication between the mapper and the cloud, as there, a different topic scheme is used. As such, the mappers should be able to send both ThinEdgeMessage
s and MqttMessage
s to their MQTT actors, while local thin-edge services should only be able to send ThinEdgeMessage
s.
Describe alternatives you've considered
ThinEdgeMessage
could be used to even further abstract away MQTT use thin-edge-api directly:
struct ThinEdgeMessage {
sender: EntityTopicId,
kind: MessageKind
}
enum MessageKind {
Measurement(ThinEdgeMeasurement),
Event(ThinEdgeEvent),
Alert(ThinEdgeAlert),
Health(ThinEdgeHealth),
}
making it easier for actors to decode and act on different messages they receive. Information about an entity which sent the message could be accessible at its own field, without the need to use MqttSchema
to parse the topic, and the Channel portion of the topic could be combined with the payload to create a more direct representation of the message.
This kind of refactor would necessitate significant effort however, as all the actors would have to be rewritten to use this new message type due to significant structural changes. In contrast, a limited ThinEdgeMessage
type retaining MQTT topic/payload structure, only encoding the caveat that it doesn't include the topic root, which will be appended by the MQTT actor when sending the message over MQTT, will be easier to do.
I expect following changes will have to be made:
- Create a new
ThinEdgeMessage
type for MQTT messages without the topic root - Introduce a new variant of the MQTT actor with a channel of type
ThinEdgeMessage
- Provide
MqttSchema::entity_channel_of/topic_for
alternative which operates onThinEdgeMessage
- Replace current
MqttActor<MqttMessage>
withMqttActor<ThinEdgeMessage>
for all local thin-edge services.
At this point MQTT topic root would only be handled by the MQTT actor, but as some services still operate on MqttMessage
s natively, MqttSchema
could be used as a compatibility layer for services which are still due to be rewritten to use ThinEdgeMessage
natively.
Additional context
This is an issue made in response to #2353 (comment), but I just wanted to get this stuff out of my head. Maybe I'll write a more detailed proposal in the future, but for now, it's necessary to track where we still don't handle the MQTT topic root correctly, so here it goes.
Places where custom MQTT topic root is not handled:
- C8y Mapper MQTT Bridge
- /workspace/crates/core/c8y_api/src/utils.rs:5
- /workspace/crates/core/tedge/src/cli/connect/bridge_config_c8y.rs:101
However, as there is one bridge per mapper, and only one mapper of a given type, per thin-edge instance, there will not ever be multipletedge-mapper-c8y
ormosquitto-bridge-c8y
clients connected to the same MQTT broker and publishing under different MQTT topic roots. I think it necessitates some discussion.
- Entity store (crates/core/tedge_api/src/entity_store.rs:33)
- tedge_to_te_converter
- tedge-mapper-collectd (crates/core/tedge_mapper/src/collectd/mapper.rs:15)
The list is possibly incomplete, I've searched for regex "te(\/|")
in *.rs
files excluding tests.rs
files, but there are still test modules in other files where te/
is used.