-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Question: Do responses need to be correlated with requests? #31
Comments
Note that in my strawman proposal action requests are already assigned a unique identifier (currently a URL) in an How would this work for properties? Would a Consumer generate an identifier (e.g. |
Hello, I believe the inclusion of a unique message ID and correlation ID in the response message is just beneficial, especially in a request/reply pattern. While not every client implementation is required to use these IDs, having them available adds flexibility and helps ensure that more complex use cases are supported. For clients that don't need to correlate responses, they can simply process the incoming messages without paying attention to the correlation ID. However, for clients that do need to track responses against specific requests, the presence of these IDs makes it easier and more reliable. WebSockets, by design, enable asynchronous communication, which means that responses may not arrive in the same order as requests were sent. This is where message IDs and correlation IDs become crucial. Message IDs allow you to uniquely identify each message, while correlation IDs ensure that even if responses are received out-of-order, each reply can be properly matched with its corresponding request. This is particularly important when dealing with scenarios where multiple requests are being sent simultaneously, and responses might be processed by the server in parallel. For example, consider a scenario where a client is controlling a light by issuing a series of commands—turning the light off, turning it on, and changing its color. If the device handling these requests is multi-threaded or experiences any form of processing delay, it’s possible for the responses to be sent back in a different order than the requests were made. In such cases, having a correlation ID in the response would allow the client to correctly match the response (e.g., turning the light on) to the corresponding request, even if the response for "turning the light off" arrives afterward. This ensures that the client can maintain the proper sequence of operations and understand the state of the system correctly. Ultimately, incorporating message IDs and correlation IDs provides a layer of robustness that allows for better handling of out-of-order or delayed responses, improving the overall reliability and consistency of the system. Also in error handling use cases it's important to understand which request message has actually failed. Correlation IDs help to ensure that retry logic is tied to the correct message. If a request fails and needs to be retried, the correlation ID ensures that the retry is linked to the original request, avoiding confusion or duplicate processing. |
Adding a few use-cases in favor of request/correlation-id:
|
When I first read the strawman proposal a few months back, I wanted to comment on this specific need. I think its absolutely necessary to have a message ID. Apart from asyncio, also threaded clients, clients shared in multiprocess scenarios will always need a message ID to correlate the responses. These patterns are common in python and also in SCADA systems, control & real time systems based on web of things. Besides, it will help solve many more problems apart from correlation, including writing nicer logic, logs etc.. Besides its a few more bytes. With a decent serializer and a faster responding eventloop, the overhead will be literally in nanoseconds if I am not wrong. I have already given the strawman proposal a shot over ZMQ , but I could not conclude it because my use case was significantly ahead of what the proposal could satisfy. However, it could be very useful to also share the message contract over multiple transport layers apart from websocket. So, some day I hope that may message contract will converge to what you guys have and I absolutely need a message ID. The following is my current messaging contract which looks somewhat similar to the strawman proposal , except laid out as a list instead of a dict/JSON: You can also see the message types I support: If I use your sub protocol, this will go to I had some issue with encoding a raw byte payload with a different content type than JSON (like raw byte array or an octet stream) within the JSON, so I didn't cast the contract yet into something looking like the proposal of this project. In following you can see its usage to run a certain WoT operation here: Its not exactly following the standard, but you can see the similarity I hope. |
I'm not completely convinced by all of the use cases suggested here:
However, I can see that correlating responses with requests could result in a more robust system and reduce the risk of race conditions and ambiguous responses. It's definitely true that error responses are more useful if they can be correlated with a request! I think we should probably add a That ID could also be used in a Open questions:
|
Maybe you already have a solution for this? I don't see a way to accomplish this though, so I'm asking what is wrong with using the requestID to differentiate consumers? I've implemented the current proposal but can't get it to work properly without adding this dependency on the requestID to identify the consumer to send a response to.
I welcome this.
Yes 👍 open questions:
Currently I'm using shortid (golang) and nanoid JS. According to the author of nanoid: So yes, some version of UUID would work nicely. As long as the collision probability is low.
Hmm yes, good question. It is a bit of an edge case though. Two options come to mind:
My preference is 2 as this is a problem introduced by the consumer by making overlapping subscriptions. |
While transport protocols like TCP (and WebSockets by extension) guarantee message order, this doesn't necessarily ensure order at the application level. For example, if you rapidly turn a lamp on and off, the Thing's implementation might process these actions on different threads. Without proper handling, responses could be returned out of order via the WebSocket connection. To resolve this, a correlationId is essential, allowing the client to reliably match responses to their corresponding requests.
In my Client and Server ThingServient implementation, I generate a unique UUID for each WebSocket connection to keep track of multiple consumers. But additionally, I use messageIds (or requestIds) to manage a map of pending requests and responses. This is implemented using a map of messageIds and CompletableDeferred in Kotlin (Promises in JS), allowing efficient tracking of pending requests. The use of messageIds ensures that both the client and server can handle multiple requests concurrently, correlate responses to their originating requests, and gracefully handle timeouts for requests that take too long to complete. Without this messageId/correlationId pair, it would be definitely more difficult to implement.
Totally agree. If an action results in a property being updated, I currently don't see the need to put the requestId of the invokeAction message into a propertyReading message.
I think we should specify/use UUIDv4 and not allow to use any ID format.
I would favor to model subscribeEvent/observeProperty as idempotent operations, where the most recent request takes precedence. If a subscription already exists for an event or property, it should simply be overwritten by the latest one, without exceptions. |
@RobWin stated in #34 (comment) that he thinks Do other people think I'm going to file a separate issue regarding * In the strawman proposal I used the capitalisation "thingId" but I think I actually prefer "thingID" as some others have being using. Sorry if this causes problems for anyone who already started implementing the strawman proposal! |
@RobWin wrote:
I think this makes the most sense. Just to note we also need to consider the scenario of overlapping subscriptions between E.g.
Based on the discussion in this and other issues I am starting to agree that |
That's indeed a good question. I haven't implemented |
Answer: Yes, but correlation IDs are optional. I've filed a separate issue for the question about overlapping subscriptions: #41 |
@RobWin and @hspaay have suggested that for the more request/response style messages in the protocol it would be useful to be able to correlate responses with specific requests. E.g. so that a Consumer knows that a given
propertyReading
message corresponds to a particularreadProperty
message.Is it important for a Consumer to know exactly which request a given response corresponds to, or is it OK for a Consumer which sends a
readProperty
message to just make use of the nextpropertyReading
message it receives for the given property?Which other operations might need this feature?
How would it work?
What additional members are needed?
The text was updated successfully, but these errors were encountered: