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

Support deferred messages or delayed processing #411

Open
fgheysels opened this issue Jul 19, 2023 · 13 comments
Open

Support deferred messages or delayed processing #411

fgheysels opened this issue Jul 19, 2023 · 13 comments
Labels
area:message-processing All issues related to how we process the messages enhancement New feature or request integration:service-bus All issues concerning integration with Azure Service Bus
Projects
Milestone

Comments

@fgheysels
Copy link
Member

We might have processes where we receive a message from servicebus that cannot be processed yet. (For instance because we're waiting on another message coming from another party first).
In such situations, it would be good if we could defer the message or resubmit the same message.
It would be nice if we could do this in the implementation of the message-handler. I can see that the AzureServiceBusMessageHandler now already has functionality to Complete or Abandon messages via protected methdos. Some 'defer' or 'resubmit' logic there would be appropriate I think.

I think there are 2 approaches:

Re-submitting:

I'm thinking of having the possibility of re-submitting the exact same message to Service Bus again, but with a specific / specified
ScheduledEnqueueTimeUtc property. Docs on this here. (That would probably mean completing the initial message and then resubmitting a copy of it , with all the same properties etc... but with a specified ScheduledEnqueueTimeUtc ?
(Or can this be implemented by abandoning the message and passing in the necessary 'propertiesToModify' ? [ pass in ScheduledEnqueueTimeUtc as propertyToModify ? )

Deferring

This might be another possible approach, but I think it's more complex?
Some documentation on the defer-functionality that is provided by Azure ServiceBus can be found here.
The drawback of deferring -as I see it-, is that you need another mechanism to retrieve deferred messages again, and that you need to specify which deferred message you want to retrieve again (so you need to keep state / administration for this).

@stijnmoreels
Copy link
Member

That would be a cool feature, indeed. I see some similarity with #25 and #36 .

@stijnmoreels stijnmoreels added this to the v1.5.0 milestone Jul 20, 2023
@stijnmoreels stijnmoreels added this to To do in Roadmap via automation Jul 20, 2023
@stijnmoreels stijnmoreels added enhancement New feature or request integration:service-bus All issues concerning integration with Azure Service Bus area:message-processing All issues related to how we process the messages labels Jul 20, 2023
@fgheysels
Copy link
Member Author

That would be a cool feature, indeed. I see some similarity with #25 and #36 .

I see some similarity with #25 indeed. However, @tomkerkhove mentions there that the pump should orchestrate this, but I don't know how the pump could do that. The pump has no knowledge of the 'business logic' that must be executed (what must be executed first).
Therefore, my assumption would be that the message-handler would be responsible for 'resubmitting' the message if it cannot be processed yet.

@fgheysels
Copy link
Member Author

fgheysels commented Jul 20, 2023

I've tried implementing this by calling the AbandonAsync method and specify a scheduledEnqueueTimeUtc property while abandoning, but this doesn't give us the desired results.

This issue is related to what we want to achieve here: Azure/azure-service-bus#454

One of the workarounds that is proposed in the above issue is to 'Defer' the message and keep track of the deferred message by sending another message to the queue which contains the sequence-number of the deferred message so that it can be retrieved later.
I think this might be a good approach for a work around.

I was thinking of having something like:

  • a (protected) method in AzureServiceBusMessageHandler that you can call to 'Defer' or re-submit a message using a method that has a signature like this: DeferMessageAsync( DateTimeOffset resubmitDateTime);.
    When this method is called it should:

    • Defer the incoming message using the ProcessMessageEventArgs.DeferMessageAsync method.
    • Post a new message on ServiceBus with the necesary meta-data (amongst others the SequenceNumber of the received message that was deferred. The scheduledEnqueueTimeUtc property of this new message must be set to the resubmitDateTime value that was passed as a parameter.
  • When the pump / messagerouter receives the message that has been posted because of the deferral, the messagerouter should be able to retrieve the original deffered message via the ReceiveDeferredMessageAsync method and the sequenceNumber that was stored in that message. Once the deferred message is retrieved, it should be routed to the correct MessageHandler, just as we're doing now with 'normal' messages.
    (I believe for this to work, we would need to be able to register a message-handler that can handle those messages that have been posted because of a deferral ? Maybe this can be done by wrapping the necessary information in a DeferredMessageMetadata type or something ? When such a type is received, the messagehandler that is linked to this type can be executed. The implementation of this message-handler retrieves the deferred message, and makes sure that the messaage is routed ? Just thinking out loud).

Of course, this is still -imho- a workaround for the problem at hand. Ideally, MSFT solves this by adding this functionality in ServiceBus as this work-around brings a few other problems to the table:

  • we must be able to send messages from a message-handler to ServiceBus. This means that the process that is processing messages would also need to have 'send' rights to Service Bus.
  • What if the Message is successfully deferred, but sending the scheduled message fails ?
  • What about topics and subscriptions ? See this side-effect of this workaround (and this possible resolution to it).

@stijnmoreels
Copy link
Member

Sounds like a plan! 🎉 Thx a lot for documenting/investigating this so thoroughly. Will see if I can work on something while you're gone. 👍

@stijnmoreels
Copy link
Member

The feature is done being designed and almost picked up for development: Azure/azure-service-bus#454 (comment)
Maybe we can wait a bit for it.

@fgheysels
Copy link
Member Author

Well, I think this is something we're going to need very soon in a project. Also, other teams might find it very useful.
I don't know how soon MSFT will start development, and how soon it will be released / available. I guess we can close that gap for now using our 'work around implementation', and then, once MSFT has provided a cleaner solution, modify our implementation to make use of the feature that MSFT has developed ?

@stijnmoreels
Copy link
Member

Yes, think that is a good approach. Unless of course this is very critical for other projects, otherwise I would be in favor to wait a bit for Microsoft to catch up.

@fgheysels
Copy link
Member Author

I think it is a crucial feature, something that should have been implemented by MSFT from the start imho.
I'm afraid it can take up to 6 months or more before MSFT will deploy this.

Another thing regarding the possible implementation. I've discussed this with @gverstraete yesterday as well, and his first idea on how to implement this, could also be an option:

When 'deferring' a message, we could create a clone of the message, (with the same body and properties) and send this message to service bus with a `ScheduledEnqueuetimeUtc', and next to that we must then also make sure to 'accept' the original message so that it is no longer available in the queue.

@stijnmoreels
Copy link
Member

stijnmoreels commented Aug 17, 2023

Ah yes, but I'm wondering what Impact this could have on the performance/scaling/cost of Service Bus as for every message, there will be two in the queue.

Otherwise, this is indeed a rather elegant solution.
If we're thinking about implementing this, we should also probably note somewhere that the authorization of the Service Bus resource will require Write (new messages) too, instead of Read only.

@fgheysels
Copy link
Member Author

Ah yes, but I'm wondering what Impact this could have on the performance/scaling/cost of Service Bus as for every message, there will be two in the queue.

Service Bus bills you per operation, not by the amount of messages. Service Bus Pricing.
Of course, in a situation where you need to retrieve a deferred message, that 's an additional operation, but I would say that additional costs for this would be marginal ?

Otherwise, this is indeed a rather elegant solution. If we're thinking about implementing this, we should also probably note somewhere that the authorization of the Service Bus resource will require Write (new messages) too, instead of Read only.

That's a good point, and indeed a drawback.

@fgheysels
Copy link
Member Author

The thing is that we'll need to decide on how to continue with this:

  • implement using deferring the message and enqueue a message that says 'retrieve the deferred message'
  • implement via the approach that 'clones' the original message and sends it with a scheduled date, abandon the original message
  • wait for MSFT

I would be in favor to not to wait for MSFT as we don't know how soon the feature will be delivered. We can close the gap for now with an alternative approach. Once MSFT comes up with their solution, we can rework our workaround to use the 'official implementation'.

What's your take @gverstraete ?
This is a feature we'll certainly require at a project I'm working on with @jcools85 right now, so he might have some ideas as well ?

@gverstraete
Copy link

The thing is that we'll need to decide on how to continue with this:

  • implement using deferring the message and enqueue a message that says 'retrieve the deferred message'
  • implement via the approach that 'clones' the original message and sends it with a scheduled date, abandon the original message
  • wait for MSFT

I would be in favor to not to wait for MSFT as we don't know how soon the feature will be delivered. We can close the gap for now with an alternative approach. Once MSFT comes up with their solution, we can rework our workaround to use the 'official implementation'.

What's your take @gverstraete ? This is a feature we'll certainly require at a project I'm working on with @jcools85 right now, so he might have some ideas as well ?

Agree, I think cloning makes most sense

@fgheysels
Copy link
Member Author

For implementation, I would go with 'cloning' the message. That looks to be the most simple solution.

Next to that, we must take into consideration that a processor not only needs to have listen permissions to the queue (or topic), but also needs to have send permission.
In my opinion, that is something that we can add in the documentation. When a message is being deferred (send back to the queue), and the connection that we're using doesn't have send rights, we'll just throw an exception.

When MSFT has finished it's implementation, we can refactor our internal workings to make use of the functionality MSFT provides. If no 'send' rights are required for MSFT's implementation, we can modify our documentation and make a note of this in our release-notes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area:message-processing All issues related to how we process the messages enhancement New feature or request integration:service-bus All issues concerning integration with Azure Service Bus
Projects
Roadmap
  
To do
Development

No branches or pull requests

3 participants