-
Notifications
You must be signed in to change notification settings - Fork 18
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
Refactor IMessageDispatcher
into Middleware
#932
Refactor IMessageDispatcher
into Middleware
#932
Conversation
Codecov Report
@@ Coverage Diff @@
## main #932 +/- ##
==========================================
- Coverage 84.39% 84.37% -0.03%
==========================================
Files 120 131 +11
Lines 3120 3199 +79
==========================================
+ Hits 2633 2699 +66
- Misses 487 500 +13
Flags with carried forward coverage won't be shown. Click here to find out more.
Continue to review full report at Codecov.
|
IMessageDispatcher
into Middleware
{ | ||
if (builder == null) throw new ArgumentNullException(nameof(builder)); | ||
|
||
IMessageMonitor monitor = builder.ServiceResolver.ResolveService<IMessageMonitor>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can't just resolve the ErrorHandlerMiddleware
from the resolver, because if the IMessageMonitor
was added via the ServicesBuilder, then resolving the middleware from the resolver will bypass the SB and resolve from the container, which is a no-op by default.
The downside is that middlewares that do this are instance-per-queue instead of shared.
…reate deafults and use them.
- Adjusted the handler builder model to make applying user overrides to defaults more straightforward. The previous method of providing a Configure func worked until I tried to apply defaults beforehand that could be adjusted, and it became impossible to ensure they were ordered correctly. With the new way, defaults are applied unless users provide a middleware configuration override, in which case they must call UseDefaults: ``` .ConfigureJustSaying((builder) => builder.WithLoopbackTopic<SimpleMessage>(UniqueName, c => c.WithMiddlewareConfiguration(m => { m.UseExactlyOnce<SimpleMessage>("lock-simple-message"); m.UseDefaults<SimpleMessage>(handler.GetType()); }))) ``` - Removed the concept of clearing the middleware chain, as everything is now opt-in - Made sure all approval test results were prefixed by their classname to make them easier to find :-)
- Fix up some stray approval tests - found an easier way to work around the lambda function name in approval test filename problem.
- Minor cleanup - Add new AwaitableMiddleware that can be used to wait for an entire middleware chain to complete instead of just the inner handler. Useful for testing middleware after effects.
- BackoffMiddleware can be singleton as the exception is now stored on the handle context
- DefaultServiceResolver can be a bit smarter - Added some docs, applied some code conventions - Add try/finally around backoff middleware - better safe than sorry if it's used elsewhere.
- Made Client private in ISqsQueue to hide it to make testing easier. It's an implementation detail. Added methods we use to ISqsQueue - Refactoring tests that use FakeAmazonSqs to use FakeSqsQueue instead. Data driven tests! - Remove DummySqsQueue as it does the same job as FakeSqsQueue
var messages = PopMessagesFromSourceQueue(sourceQueue); | ||
var receiptHandles = messages.ToDictionary(m => m.MessageId, m => m.ReceiptHandle); | ||
|
||
var sendResponse = destinationQueue.Client.SendMessageBatch(new SendMessageBatchRequest |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This Client property is private now as we no longer expose the IAmazonSqs, so I've removed this command as I don't think its used very much. We have other ways of handling retries.
- As long as one completion task throws OCE, we're good
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good.
I wonder if with the extra CancellationToken usages if anywhere needs changing to more gracefully needs to handle if it fires and causes a cancellation mid operation? (Say between two API calls related to a single message batch, like a receive and then a delete)
Co-authored-by: Martin Costello <martin@martincostello.com>
Co-authored-by: Martin Costello <martin@martincostello.com>
Co-authored-by: Martin Costello <martin@martincostello.com>
Co-authored-by: Martin Costello <martin@martincostello.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few comments here and there. Most of it us just me being nit-picky about /// docs and null checks on the public members.
src/JustSaying/Fluent/ServiceResolver/CompoundServiceResolver.cs
Outdated
Show resolved
Hide resolved
src/JustSaying/Fluent/ServiceResolver/CompoundServiceResolver.cs
Outdated
Show resolved
Hide resolved
src/JustSaying/Messaging/Middleware/PostProcessing/SqsPostProcessorMiddleware.cs
Show resolved
Hide resolved
...stSaying.UnitTests/AwsTools/MessageHandling/MessageDispatcherTests/WhenDispatchingMessage.cs
Show resolved
Hide resolved
tests/JustSaying.UnitTests/Messaging/Channels/Fakes/FakeMessageDeleter.cs
Show resolved
Hide resolved
tests/JustSaying.UnitTests/Messaging/Channels/Fakes/InMemoryServiceResolver.cs
Show resolved
Hide resolved
- Rename HandleException to HandledException
src/JustSaying/Messaging/Middleware/Backoff/BackoffMiddleware.cs
Outdated
Show resolved
Hide resolved
src/JustSaying/Messaging/Middleware/Backoff/BackoffMiddleware.cs
Outdated
Show resolved
Hide resolved
…bility mechanism here is adding new middlewares, and not extending existing ones.
…e UseBackoff middleware
Remove IMessageBackoffStrategy from DI
src/JustSaying/Messaging/Middleware/Backoff/BackoffMiddlewareBuilderExtensions.cs
Show resolved
Hide resolved
- Add null check for IMBS
This PR partially resolves #875 by moving much of the post-processing code from the
MessageDispatcher
to separate middlewares.The default middleware chain for all handlers is now:
It is also now possible to modify the middleware configuration from the subscription builders directly, where before you had to go via the SqsReadConfiguration.
Before:
After:
The resulting middleware chain:
The
UseDefaults
method will add all of the above middlewares as a shortcut for having to add them all manually. Previously it wasn't possible to have a no-op pipeline as theHandlerInvocationMiddleware
was always added, but now you can by not calling this.A bit of debt
The need to include the handler type is to maintain the
IMessageMonitor.HandlerExecutionTime(_handlerType, context.MessageType, watch.Elapsed)
contract. Possibly this call could be moved to the handler invocation middleware where we have the handler type (so that we don't need to resolve the handler in each middleware).DI Wireup
There has also been a change to how we resolve services from configuration (using
ServicesBuilder
) vs the providedIServiceResolver
. Previously both theIServiceResolver
and theServicesBuilder
were checked to see if the user has overridden various services such asIMessageMonitor
via config instead of adding it to the container.IMessageMonitor
is used all over the place, so this check had to be done in each location (it wasn't, which was causing bugs).There is now an
IServiceResolver
over theServicesBuilder
(ServiceBuilderServiceResolver
) that enables resolution from anywhere without needing to care where the component was registered. ACompoundServiceResolver
provides a single service resolver for both the service builder resolver, and the user provided resolver (or theDefaultServiceResolver
if none supplied).This is particularly useful for middlewares, as previously we had to know about the ServicesBuilder in order to find the correct
IMessageMonitor
, for example. We can now wholly rely on a singleIServicesResolver
.I'm keen for feedback on this design - it's a little ugly, but IMO superior to infecting the rest of the codebase with knowledge of the services builder.
TODO: