-
Notifications
You must be signed in to change notification settings - Fork 78
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
[Host] IConsumerErrorHandler usage limited when using per message scopes #347
Comments
|
Are you planning a PR improve this? |
To be honest, there's not a lot that I can do to improve it without introducing breaking changes. The basic flow at the moment is:
Due to this implementation being wrapped by a single Possible solutions:
None of these options are ideal unfortunately. Do you have any other ideas/suggestions? ** it would be nice to optionally have an "abandon" state too, where a message can be sent directly to the DLQ instead of being served up by the service bus again (for non-transient exceptions). |
When the interceptors where introduced they were running intentionally on the same scope as the message handling scope (I wanted the interceptors to have access to the ongoing/current message scope). Later, when Error Handler interceptors were introduced I had the same thought if not to create a whole new scope and debated this some at the time, and came to the conclusion these consumer error handlers are like a try-catch wrapper with the option of simply repeating the try-catch block. So a retry would re-use the existing scope, and it felt that the created message scope dependencies could be re-used (in most cases) and its more efficient to re-use them. Therefore I had not went down the road to re-create the message scope upon retry(). Of course this could be an additional option, but first need debate about this and weigh the prons/cons and effort. Now, in your case I do understand the current design might not work (DbContext), and you really want to re-run the whole message processing (from the point of creating the scope) without letting it count towards retry count on the ASB side, correct? To solve your case (as another option):
Also, I will give this some more thought and review the code as currently I have other things in my focus. Please let me know. |
My primary application is for applying retry policies (with back-off and jitter) on Azure infrastrucure after a transient failure. With this, it's not the incremented delivery count that is an issue, but rather that messages are sent back to the queue when they fail/lock on mass and end up being processed again in unison -locking once more. I could add an interceptor to apply a delay before returning it to the queue but that just doesn't feel quite right. With regards to 5; I was intrigued, so I threw up a quick spike on implementation and to have a look at what the overhead would look like. The spike has various configurations, but the simple flow is to pass a message into a runner which steps through registered middleware with ad hoc dependency resolution. Each middleware instance passes the context on the next which allows for manipulation as/when required. This makes the implementation pretty flexible in terms of what could be supported (resillience, transactions, scopes, hybrid deserialization, message lifecycle, etc). ScopedPipeline NoScopePipeline OneThousandInterationNoopPipeline MinPipeline NoPipeline
The samples are very rudamentory, and certainly would need refinement and bus integration, but do flesh out the idea. Of course, due to the breaking nature of the change, it may very well be too much too chew. The major causalty would be |
@EtherZa could you update the spike link provided? Its currently broken. I like the middleware approach 5), as an option the middleware could decide if to redo the scope (default = false). Let me think about your requirements some more and get back to you.
|
@zarusz sorry, the repo was marked as private. The link should be good to go now. It is definitely a fundamental shift and while the additional stack does add overhead, I'll leave it to you to decide if the benefits outweigh it or not. The spike is quick and dirty and definitely could be optimised. The boxing/unboxing is just one area that would need to be made more efficient, but the principal is there. |
When per message scoping is enabled and an exception is thrown in the messaging pipeline; if a custom imeplementation of
IConsumerErrorHandler
is available, both the instnace ofIConsumerErrorHandler
and theretry
function supplied toIConsumerErrorHandler.OnHandleErorr()
are created under the original scope. This limits the functionality of the retry mechanism when transactions/scoped dependencies are in use.An use case is when using a scope registered
DbContext
that experiences a transient error while in a transaction. Any subsequent retry will reuse the existingDbContent
connection which is now in a failed state.It would be ideal to only create the message scope when
retry()
/DoHandleInternal()
is called, but theconsumerInvoker
instance that is made available to bothIConsumerErrorHandler
andIConsumerContext
is dependent on the scope.The text was updated successfully, but these errors were encountered: