lettuce icon indicating copy to clipboard operation
lettuce copied to clipboard

Add support for CLIENT TRACKINGINFO

Open tishun opened this issue 1 year ago • 6 comments

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.

tishun avatar May 24 '24 15:05 tishun

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?

tishun avatar May 29 '24 11:05 tishun

@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.

mp911de avatar Jun 04 '24 07:06 mp911de

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.

tishun avatar Jun 05 '24 16:06 tishun

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.

mp911de avatar Jun 06 '24 07:06 mp911de

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.

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.

tishun avatar Jun 06 '24 12:06 tishun

We should return Map<String, String> to make the response usable even without a parser.

@uglide what is your take on this solution?

tishun avatar Jun 07 '24 13:06 tishun

ping @uglide :)

tishun avatar Jul 11 '24 13:07 tishun

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 :)

tishun avatar Aug 07 '24 14:08 tishun

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.

mp911de avatar Aug 07 '24 14:08 mp911de

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.

atakavci avatar Aug 07 '24 14:08 atakavci

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.

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.

tishun avatar Aug 08 '24 09:08 tishun

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 :)

tishun avatar Aug 08 '24 10:08 tishun