-
Notifications
You must be signed in to change notification settings - Fork 648
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Make sure transport operations do not share mutable state between mul…
…tiple routing strategies (#6905) (#6910) * Add routing to dispatch connector tests to reproduce the shared state problem * Fix the state sharing problem in ToTransportOperation * Cross check headers and properties * Test for the header modifications in the routing strategy * add acceptance test * better naming and comments * block scoped namespace * Remove left overs * Move test * Primary ctor * Behavior --------- Co-authored-by: Tim Bussmann <[email protected]>
- Loading branch information
1 parent
db82ac8
commit 9dab85f
Showing
6 changed files
with
301 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
168 changes: 168 additions & 0 deletions
168
src/NServiceBus.AcceptanceTests/Outbox/When_publishing_with_outbox.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
namespace NServiceBus.AcceptanceTests.Outbox | ||
{ | ||
using System; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using AcceptanceTesting; | ||
using AcceptanceTesting.Customization; | ||
using EndpointTemplates; | ||
using Features; | ||
using NServiceBus.Pipeline; | ||
using NUnit.Framework; | ||
|
||
public class When_publishing_with_outbox : NServiceBusAcceptanceTest | ||
{ | ||
[Test] | ||
public async Task Should_be_delivered_to_all_subscribers() | ||
{ | ||
Requires.OutboxPersistence(); | ||
|
||
Context context = await Scenario.Define<Context>() | ||
.WithEndpoint<Publisher>(b => | ||
b.When(c => c.Subscriber1Subscribed && c.Subscriber2Subscribed, (session, c) => | ||
{ | ||
// Send a trigger message that will invoke the handler method that publishes the event | ||
c.AddTrace("Both subscribers are subscribed, going to send TriggerMessage"); | ||
return session.SendLocal(new TriggerMessage()); | ||
}) | ||
) | ||
.WithEndpoint<Subscriber1>(b => b.When(async (session, ctx) => | ||
{ | ||
await session.Subscribe<MyEvent>(); | ||
if (ctx.HasNativePubSubSupport) | ||
{ | ||
ctx.Subscriber1Subscribed = true; | ||
ctx.AddTrace("Subscriber1 is now subscribed (at least we have asked the broker to be subscribed)"); | ||
} | ||
else | ||
{ | ||
ctx.AddTrace("Subscriber1 has now asked to be subscribed to MyEvent"); | ||
} | ||
})) | ||
.WithEndpoint<Subscriber2>(b => b.When(async (session, ctx) => | ||
{ | ||
await session.Subscribe<MyEvent>(); | ||
if (ctx.HasNativePubSubSupport) | ||
{ | ||
ctx.Subscriber2Subscribed = true; | ||
ctx.AddTrace("Subscriber2 is now subscribed (at least we have asked the broker to be subscribed)"); | ||
} | ||
else | ||
{ | ||
ctx.AddTrace("Subscriber2 has now asked to be subscribed to MyEvent"); | ||
} | ||
})) | ||
.Done(c => c.Subscriber1GotTheEvent && c.Subscriber2GotTheEvent) | ||
.Run(TimeSpan.FromSeconds(10)); | ||
|
||
Assert.True(context.Subscriber1GotTheEvent); | ||
Assert.True(context.Subscriber2GotTheEvent); | ||
} | ||
|
||
public class Context : ScenarioContext | ||
{ | ||
public bool Subscriber1GotTheEvent { get; set; } | ||
public bool Subscriber2GotTheEvent { get; set; } | ||
public bool Subscriber1Subscribed { get; set; } | ||
public bool Subscriber2Subscribed { get; set; } | ||
} | ||
|
||
public class Publisher : EndpointConfigurationBuilder | ||
{ | ||
public Publisher() => | ||
EndpointSetup<DefaultPublisher>(b => | ||
{ | ||
b.ConfigureTransport().TransportTransactionMode = TransportTransactionMode.ReceiveOnly; | ||
b.EnableOutbox(); | ||
// Test the outbox behavior in situations where messages are deserialized and dispatched from the outbox storage by injecting an exception into the dispatch pipeline | ||
b.Pipeline.Register(new BlowUpAfterDispatchBehavior(), "ensure outbox dispatch fails"); | ||
b.Recoverability().Immediate(i => i.NumberOfRetries(1)); | ||
b.OnEndpointSubscribed<Context>((s, context) => | ||
{ | ||
var subscriber1 = Conventions.EndpointNamingConvention(typeof(Subscriber1)); | ||
if (s.SubscriberEndpoint.Contains(subscriber1)) | ||
{ | ||
context.Subscriber1Subscribed = true; | ||
context.AddTrace($"{subscriber1} is now subscribed"); | ||
} | ||
var subscriber2 = Conventions.EndpointNamingConvention(typeof(Subscriber2)); | ||
if (s.SubscriberEndpoint.Contains(subscriber2)) | ||
{ | ||
context.AddTrace($"{subscriber2} is now subscribed"); | ||
context.Subscriber2Subscribed = true; | ||
} | ||
}); | ||
b.DisableFeature<AutoSubscribe>(); | ||
}); | ||
|
||
public class TriggerHandler : IHandleMessages<TriggerMessage> | ||
{ | ||
public Task Handle(TriggerMessage message, IMessageHandlerContext context) | ||
=> context.Publish(new MyEvent()); | ||
} | ||
|
||
class BlowUpAfterDispatchBehavior : IBehavior<IBatchDispatchContext, IBatchDispatchContext> | ||
{ | ||
public async Task Invoke(IBatchDispatchContext context, Func<IBatchDispatchContext, Task> next) | ||
{ | ||
if (Interlocked.Increment(ref invocationCounter) == 1) | ||
{ | ||
throw new SimulatedException(); | ||
} | ||
|
||
await next(context).ConfigureAwait(false); | ||
} | ||
|
||
int invocationCounter; | ||
} | ||
} | ||
|
||
public class Subscriber1 : EndpointConfigurationBuilder | ||
{ | ||
public Subscriber1() => | ||
EndpointSetup<DefaultServer>(c => c.DisableFeature<AutoSubscribe>(), | ||
metadata => metadata.RegisterPublisherFor<MyEvent>(typeof(Publisher))); | ||
|
||
public class MyHandler : IHandleMessages<MyEvent> | ||
{ | ||
public MyHandler(Context testContext) => this.testContext = testContext; | ||
|
||
public Task Handle(MyEvent message, IMessageHandlerContext context) | ||
{ | ||
testContext.Subscriber1GotTheEvent = true; | ||
return Task.CompletedTask; | ||
} | ||
|
||
readonly Context testContext; | ||
} | ||
} | ||
|
||
public class Subscriber2 : EndpointConfigurationBuilder | ||
{ | ||
public Subscriber2() => | ||
EndpointSetup<DefaultServer>(c => c.DisableFeature<AutoSubscribe>(), | ||
metadata => metadata.RegisterPublisherFor<MyEvent>(typeof(Publisher))); | ||
|
||
public class MyHandler : IHandleMessages<MyEvent> | ||
{ | ||
public MyHandler(Context testContext) => this.testContext = testContext; | ||
|
||
public Task Handle(MyEvent messageThatIsEnlisted, IMessageHandlerContext context) | ||
{ | ||
testContext.Subscriber2GotTheEvent = true; | ||
return Task.CompletedTask; | ||
} | ||
|
||
readonly Context testContext; | ||
} | ||
} | ||
|
||
public class MyEvent : IEvent | ||
{ | ||
} | ||
|
||
public class TriggerMessage : ICommand | ||
{ | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
16 changes: 8 additions & 8 deletions
16
src/NServiceBus.Core/Pipeline/Outgoing/RoutingContextExtensions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters