Add support for CLIENT TRACKINGINFO
Closes #2761
Make sure that:
- [x] You have read the contribution guidelines.
- [x] You have created a feature request first to discuss your contribution intent. Please reference the feature request ticket number in the pull request.
- [x] You use the code formatters provided here and have them applied to your changes. Don’t submit any formatting related changes.
- [x] You submit test cases (unit or integration tests) that back your changes.
This is what I initially went with, but the existing CommandOutput abstractions could not handle a Map result with nested Array. Both the MapOutput and the GenericMapOutput could not handle this.
The only place we had a similar parsing done is with the CLUSTER SLOTS and I replicated this approach.
@mp911de do we have a way to handle this or should I create a new CommandOutput?
@mp911de do we have a way to handle this or should I create a new CommandOutput?
Have you tried ObjectOutput? An alternative could be ArrayOutput. If both do not work, then a custom CommandOutput would be the last alternative.
Sooo folks I'd love to hear from you what you think about the latest solution.
I already had a discussion with @uglide on that, but would love to hear any comments.
Obviously it has some downsides, but I personally find it a good compromise between what we have as a solution right now and having an actual mapping to a domain object. The latter would also incur some more heavy duty maintenance on our part.
The new output is pretty complex and its result seems pretty complex to understand as well. A Object or List<Object> return is typically much easier to consume as it would contain Redis primitives (Lists, numbers, strings) that are more common than the approach used here.
The new output is pretty complex and its result seems pretty complex to understand as well. A
ObjectorList<Object>return is typically much easier to consume as it would contain Redis primitives (Lists, numbers, strings) that are more common than the approach used here.
I agree. It is a tradeoff.
The proposed solution is supposed to be used (mainly) in conjunction with the parser logic. Further down the line the parser could be extended to generate stubs based on some schema definition. For a strongly typed language such as Java this is the only working way to consume an API of a service, that has complex types and could be changed down the line.
Jedis has a model object for complex return types, but this makes the design tightly coupled with the current API. Any change to the API would break the existing model.
I was aiming for a middle ground where we have a utility to help the user consume the logic in a simple way (see the integration test), but also allow them to parse the information themselves if the model changes.
A good example for this is if another value is added to the Map. The consumers of the driver could start polling the new value without having to wait until we release a new version of the parser.
So we gat a bit of more stability for the price of having to deal with this interim object that is a bit complex to use.
We should return Map<String, String> to make the response usable even without a parser.
@uglide what is your take on this solution?
ping @uglide :)
Everyone,
after a 30min discussion with @atakavci I realized we are definitely over-engineering this and only making it complex to the users of the driver as a result. The final version simply parses the data behind the scenes and returns a nice domain object to the user. The existing infrastructure is now facilitating the parsing of future complex objects, buty without exposing any of the complexity to the API.
Why did we decide to not expose the parsing to the users of the driver:
- first and most important of all - making the assumption that the server would return a different data structure (and thus - obviously - has introduced breaking changes) and the users of the driver would still opt to use the old version of the driver (not adapted to the server's breaking changes) is a bold assumption
- additionally the users of the Lettuce driver already have a way to send custom commands in case the existing coverage is not sufficient, so they do not need yet another facility that would give them alternatives of parsing the data
- last but not least I agree with @mp911de that the data needs to be easy to use by the user
Any thoughts are welcome, but I feel confident right now that this is the best solution. Feel free to prove me wrong :)
Hiding the inner Output is a good thing and it will allow for future revision without breaking calling code. I would strongly advise to investigate on a generic output that is driven by the Redis response structure allowing for capturing the response. A Output wrapper could then apply the parsing.
first of, i am all good with typed object as return value. but let me share my 2 cents here as well and may be contradict with myself 😬 while doing that;
-
i think using a new version of client api with an old version of server is not a bold assumption,, there are reasonable amount of organizations where these two things are in responsibility of separate people/department with different timelines.
-
imho, what we have as conclusion is only one step away from 'ideal'. simplicity is a key quality of a successful api/driver i believe, and i am choosing this for simplicity. maintenance and compatibility should stay as a burden on our side.
-
referring to the 'ideal' word above, solution with DynamicAggregateData would not be over-engineered when the time comes and we had this first round with a request/issue from users trying to access some part of the server response which is not exposed with the current return type.
And thanks for the discussion, i am happy we had it.
Hiding the inner
Outputis a good thing and it will allow for future revision without breaking calling code. I would strongly advise to investigate on a generic output that is driven by the Redis response structure allowing for capturing the response. AOutputwrapper could then apply the parsing.
Hey Mark, apologies, not sure If I get this right, let me rephrase it and see if we are on the same page. Your recommendation is to have a multipurpose generic output class that is able to handle all possible permutations of the command results and then use wrapper outputs to apply any parsing / mapping to Java types.
Is that correct? If so - this makes sense. I can create another issue to track this work.
Just for the sake of argument (I mostly agree with your comments):
- i think using a new version of client api with an old version of server is not a bold assumption,, there are reasonable amount of organizations where these two things are in responsibility of separate people/department with different timelines.
I agree that it is not impossible for the situation to arise where two teams / companies working on the same solution end up with different version of the client and server. However I would be surprised if - instead of upgrading the driver - they decide to parse the result themselves. First of all they would have to now maintain this new code and change it again in the future when it breaks (or remove it when they upgrade the driver). Second of all - in terms of effort and stability - it is the harder thing to do.
Even then they are still given the opportunity to use the custom commands functionality to manually process the result.
- imho, what we have as conclusion is only one step away from 'ideal'. simplicity is a key quality of a successful api/driver i believe, and i am choosing this for simplicity. maintenance and compatibility should stay as a burden on our side.
Here is where I disagree, but we could agree to disagree :) To me this is the ideal solution. I realize it incurs maintenance and compatibility but IMHO this is the responsibility of the driver. Somebody has to pay the price and the driver makes most sense - otherwise all the users of the driver would have to pay that price themselves, which is less than ideal.
- referring to the 'ideal' word above, solution with DynamicAggregateData would not be over-engineered when the time comes and we had this first round with a request/issue from users trying to access some part of the server response which is not exposed with the current return type.
You may be right, depending on what such a solution would bring to the users of the driver, compared to the custom commands. If it is yet another way or them to parse things manually it does not add any value. If it helps them more than that then it might be meaningful.
And thanks for the discussion, i am happy we had it.
Absolutely. I have the feeling we will have more of these :)