Skip to content
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

Allow to set TTL (and other QoS-related settings) on a per-message (and/or per-send) basis #26840

Open
mauromol opened this issue Apr 21, 2021 · 8 comments
Assignees
Labels
in: messaging Issues in messaging modules (jms, messaging) type: enhancement A general enhancement
Milestone

Comments

@mauromol
Copy link

I know there are at least two other issues on this topic:

With this I'm asking if you could reconsider to improve JmsTemplate so that it's possible to do this, especially in light of the existence now of Spring Boot, which configures a JmsTemplate for you (so the workaround to create a new JmsTemplate instance on each message send makes things much more complex than they could be).

Use case: I'm using JmsTemplate to send notifications; these notifications should have different expiration times depending on their context, which has itself an expiration after which all related notifications become stale and useless.

To workaround this, apart from the option to create new JmsTemplates on each send operation, there's the possibility to use one of the execute(...) overloadings that takes a ProducerCallback parameter, however in this case you're completely left alone with regards to the message creation and actual sending process, which is not trivial (see org.springframework.jms.core.JmsTemplate.doSend(Session, Destination, MessageCreator) implementation).

@mauromol mauromol changed the title Allow to set TTL (and other QoS-related settings) on a per-message (and/or per-send) base with JmsTemplate Allow to set TTL (and other QoS-related settings) on a per-message (and/or per-send) basis with JmsTemplate Apr 21, 2021
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Apr 21, 2021
@snicoll
Copy link
Member

snicoll commented Apr 22, 2021

@mauromol I don't understand why you think that what you're asking is any different from #24144 and how Spring Boot is related. What you call a workaround is what the JMS spec mandates, as described in this comment.

there's the possibility to use one of the execute(...) overloadings that takes a ProducerCallback parameter, however in this case you're completely left alone with regards to the message creation and actual sending process, which is not trivial (see org.springframework.jms.core.JmsTemplate.doSend(Session, Destination, MessageCreator) implementation).

I don't really understand what is the problem. doSend is framework code that accomodates with various use cases depending on what was configured on the template. If you write code for your dedicated use case, you shouldn't have to worry about that.

Can you clarify what improvements you would like us to consider?

@snicoll snicoll added the status: waiting-for-feedback We need additional information before we can continue label Apr 22, 2021
@mauromol
Copy link
Author

@mauromol I don't understand why you think that what you're asking is any different from #24144 and how Spring Boot is related. What you call a workaround is what the JMS spec mandates, as described in this comment.

#24144 was requesting to let the JmsTemplate consumer to use (for instance) Message.setJMSExpiration(long expiration) within the MessageCreator implementation to set a message expiration and then pass that value to the producer in order to properly set message expiration. However, this is a misuse of the JMS API that states that such method is "for use by JMS providers only to set this field when a message is sent".
My request, instead, is to provide a proper API on JmsTemplate to do this in a proper way. Something like, for instance:

jmsTemplate.send(myMessageCreator, messageExpiration);

I don't really understand what is the problem. doSend is framework code that accomodates with various use cases depending on what was configured on the template. If you write code for your dedicated use case, you shouldn't have to worry about that.

Can you clarify what improvements you would like us to consider?

With Spring Boot you can easily get a JmsTemplate instance injected in your code once you add a proper starter and configure JMS properties:
https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-using-jms-sending
So, let's suppose I've added org.springframework.boot:spring-boot-starter-activemq to my dependencies and that I've set all my spring.jms.* and spring.activemq.*. Then, I have that auto-configured JmsTemplate injected where I need it, how can I send a message with a custom per-message expiration?

These are the solutions (what I call "workarounds") I see:

  • throw away the auto-configured JmsTemplate and manually set up and use my custom JmsTemplate extension that exposes such a functionality (doSend is protected)
  • throw away the auto-configured JmsTemplate and manually set up a factory of JmsTemplate instances, producing a different JmsTemplate instance for each message I need to send
  • keep the auto-configured JmsTemplate and call org.springframework.jms.core.JmsTemplate.execute(ProducerCallback<T>) by passing a ProducerCallback implementation that does the following:
    1. create the message (easy)
    2. mimic org.springframework.jms.core.JmsTemplate.doSend(MessageProducer, Message) to set the delivery delay on the producer and send the message with it by passing in the needed QoS parameters (including the message expiration/TTL) (relatively easy, but verbose)
    3. handle the transaction as done by org.springframework.jms.core.JmsTemplate.doSend(Session, Destination, MessageCreator) (not trivial)

Of course, copy 'n' paste is always a "solution", but quite inelegant and not future-proof, in case JmsTemplate should evolve and perform other things in its doSend(...) methods.

IMHO this requirement is enough reasonable and common (at least when I look at the past issues here on GitHub and at some questions on StackOverflow) to deserve support by JmsTemplate out-of-the-box. This is why I opened this issue.

I hope I've clarified now.

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Apr 22, 2021
@jhoeller
Copy link
Contributor

jhoeller commented Apr 22, 2021

In terms of our envisioned scenarios there, it's indeed appropriate to create a per-operation JmsTemplate instance with the corresponding settings applied before invoking the actual operation on it. This is within the design there and not out of the ordinary at all. JmsTemplate instances can be seen as a lightweight holder for a ConnectionFactory plus various settings, allowing operations to be triggered on it.

We could make it more obvious/convenient to build such derived JmsTemplate instances with the same ConnectionFactory but different settings, but as you noted, you can easily set up such a factory yourself. All the settings on the JmsTemplate are publicly accessible, so there are no design constraints as far as I can see (towards your second proposal that you call a "workaround").

With respect to the autoconfigured JmsTemplate instance in Boot, that's just a convenient JmsOperations delegate pointing to a ConnectionFactory with default QoS settings. "Throwing it away" is the wrong way of seeing it IMO; choosing to use different QoS settings through a custom ConnectionFactory+settings holder (a custom JmsTemplate instance) is a perfectly fine choice in terms of our design.

@mauromol
Copy link
Author

mauromol commented Apr 22, 2021

In terms of our envisioned scenarios there, it's indeed appropriate to create a per-operation JmsTemplate instance with the corresponding settings applied before invoking the actual operation on it. This is within the design there and not out of the ordinary at all. JmsTemplate instances can be seen as a lightweight holder for a ConnectionFactory plus various settings, allowing operations to be triggered on it.

Still, parameters like the delivery mode, the priority and TTL are strictly bound to a message, not to the connection factory IMHO. We're not talking about a connection/socket timeout here, which are properties of the connection. In other messaging systems, these are just message properties (or "headers"), so while providing default values at template level is fine, having to create multiple templates just to be able to specify per-message properties sounds like a waste to me.
We could argue on why the JMS API didn't allow to specify such parameters along with the message itself (and indeed reports like #24144 show that people can get confused), instead of requiring to set them on the producer on send, but this is how things have been done on that side.

We could make it more obvious/convenient to build such derived JmsTemplate instances with the same ConnectionFactory but different settings, but as you noted, you can easily set up such a factory yourself. All the settings on the JmsTemplate are publicly accessible, so there are no design constraints as far as I can see (towards your second proposal that you call a "workaround").

Well, perhaps having a method on JmsTemplate like withQos(...) which returns a new equivalent JmsTemplate with just different QoS settings will be acceptable for me. In this way I could still use the autoconfigured JmsTemplate and derive new ones whenever I need different QoS settings. It would still sound a bit odd to me, but at least it would be practical and straight.

With respect to the autoconfigured JmsTemplate instance in Boot, that's just a convenient JmsOperations delegate pointing to a ConnectionFactory with default QoS settings. "Throwing it away" is the wrong way of seeing it IMO; choosing to use different QoS settings through a custom ConnectionFactory+settings holder (a custom JmsTemplate instance) is a perfectly fine choice in terms of our design.

It's just more work. After all, we're talking about 3 QoS settings out of ~20 total properties that can be set/configured on a JmsTemplate. I know, everything could be done, but we're talking about convenience. After all, this seems to me a so natural requirement that it sounded reasonable to request. And it seems like I'm not the first one with this need.

This said, the last decision is up to you of course.

@rstoyanchev rstoyanchev added the in: messaging Issues in messaging modules (jms, messaging) label Nov 10, 2021
@snicoll
Copy link
Member

snicoll commented Nov 12, 2023

It's just more work. After all, we're talking about 3 QoS settings out of ~20 total properties that can be set/configured on a JmsTemplate. I know, everything could be done, but we're talking about convenience. After all, this seems to me a so natural requirement that it sounded reasonable to request. And it seems like I'm not the first one with this need.

Yes, but the same argument could be made for any of the 20 properties. The pattern with template is what it is and introducing a builder-style approach could lead other to legitimately request the same to be applied to other properties. I think the building block has to stay as consistent and as simple as possible.

@snicoll snicoll closed this as not planned Won't fix, can't repro, duplicate, stale Nov 12, 2023
@snicoll snicoll added status: declined A suggestion or change that we don't feel we should currently apply and removed status: waiting-for-triage An issue we've not yet triaged or decided on status: feedback-provided Feedback has been provided labels Nov 12, 2023
@mauromol
Copy link
Author

Yes, but the same argument could be made for any of the 20 properties.

I do not think so, because I do not think all 20 properties are on the same level, but anyway... I'm just sorry about your final decision.

@loganmzz
Copy link

loganmzz commented Dec 5, 2023

Yes, but the same argument could be made for any of the 20 properties.

I do not think so, because I do not think all 20 properties are on the same level, but anyway... I'm just sorry about your final decision.

Not alone, if it can help in same way :) At least I have some happiness finding other people sharing my mind.

I think we can split JmsTemplate usage/settings over several categories:

  • Infrastructure (connection, payload processing, etc.)
  • Destination
  • Message (Request/Producer/Consumer/...)

I think most people setup their JmsTemplate for primary category (infrastructure) and other ones mostly per call. Having default is nice, but duplicating is error-prone as no facilities are provided (clone, overriding wrapper or copy constructor).
And things get worse when using the messaging wrapper (JmsMessagingTemplate).

Can you at least provide some copy facilities ?

@snicoll
Copy link
Member

snicoll commented Dec 5, 2023

Alright, It's great to get some more feedback here. Reopening to consider our options.

@snicoll snicoll reopened this Dec 5, 2023
@snicoll snicoll added type: enhancement A general enhancement and removed status: declined A suggestion or change that we don't feel we should currently apply labels Dec 5, 2023
@snicoll snicoll added this to the 6.2.x milestone Dec 5, 2023
@snicoll snicoll self-assigned this Dec 5, 2023
@jhoeller jhoeller modified the milestones: 6.2.x, 6.2.0-M2 Mar 20, 2024
@jhoeller jhoeller self-assigned this Mar 20, 2024
@jhoeller jhoeller modified the milestones: 6.2.0-M2, 6.2.x May 14, 2024
@jhoeller jhoeller modified the milestones: 6.2.x, 6.2.0-M5 Jun 12, 2024
@jhoeller jhoeller modified the milestones: 6.2.0-M5, 6.2.x Jul 4, 2024
@snicoll snicoll removed their assignment Aug 20, 2024
@jhoeller jhoeller modified the milestones: 6.2.x, General Backlog Sep 11, 2024
@jhoeller jhoeller modified the milestones: General Backlog, 7.0.x Oct 1, 2024
@jhoeller jhoeller changed the title Allow to set TTL (and other QoS-related settings) on a per-message (and/or per-send) basis with JmsTemplate Allow to set TTL (and other QoS-related settings) on a per-message (and/or per-send) basis Mar 20, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: messaging Issues in messaging modules (jms, messaging) type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

6 participants