-
Notifications
You must be signed in to change notification settings - Fork 1k
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
Fixed: IWrappedMessage
+ IDeadLetterSuppression
handling
#7414
Changes from all commits
7f2d57d
04e3186
c9e14fe
1e8cb3a
0495506
5a1f914
e9115f5
0f9904a
09599c1
736476f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
// ----------------------------------------------------------------------- | ||
// <copyright file="WrappedMessagesSpec.cs" company="Akka.NET Project"> | ||
// Copyright (C) 2009-2024 Lightbend Inc. <http://www.lightbend.com> | ||
// Copyright (C) 2013-2024 .NET Foundation <https://github.com/akkadotnet/akka.net> | ||
// </copyright> | ||
// ----------------------------------------------------------------------- | ||
|
||
using Akka.Actor; | ||
using Akka.Event; | ||
using Akka.TestKit; | ||
using Xunit; | ||
|
||
namespace Akka.Tests; | ||
|
||
public class WrappedMessagesSpec | ||
{ | ||
private sealed record WrappedClass(object Message) : IWrappedMessage; | ||
|
||
private sealed record WrappedSuppressedClass(object Message) : IWrappedMessage, IDeadLetterSuppression; | ||
|
||
private sealed class SuppressedMessage : IDeadLetterSuppression | ||
{ | ||
|
||
} | ||
|
||
|
||
[Fact] | ||
public void ShouldUnwrapWrappedMessage() | ||
{ | ||
var message = new WrappedClass("chocolate-beans"); | ||
var unwrapped = WrappedMessage.Unwrap(message); | ||
unwrapped.ShouldBe("chocolate-beans"); | ||
} | ||
|
||
public static readonly TheoryData<object, bool> SuppressedMessages = new() | ||
{ | ||
{new SuppressedMessage(), true}, | ||
{new WrappedClass(new SuppressedMessage()), true}, | ||
{new WrappedClass(new WrappedClass(new SuppressedMessage())), true}, | ||
{new WrappedClass(new WrappedClass("chocolate-beans")), false}, | ||
{new WrappedSuppressedClass("foo"), true}, | ||
{new WrappedClass(new WrappedSuppressedClass("chocolate-beans")), true}, | ||
{new WrappedClass("chocolate-beans"), false}, | ||
{"chocolate-beans", false} | ||
}; | ||
|
||
[Theory] | ||
[MemberData(nameof(SuppressedMessages))] | ||
public void ShouldDetectIfWrappedMessageIsSuppressed(object message, bool shouldBeSuppressed) | ||
{ | ||
var isSuppressed = WrappedMessage.IsDeadLetterSuppressedAnywhere(message); | ||
isSuppressed.ShouldBe(shouldBeSuppressed); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -197,6 +197,18 @@ public static object Unwrap(object message) | |
} | ||
return message; | ||
} | ||
|
||
internal static bool IsDeadLetterSuppressedAnywhere(object message) | ||
{ | ||
var isSuppressed = message is IDeadLetterSuppression; | ||
while(!isSuppressed && message is IWrappedMessage wm) | ||
{ | ||
message = wm.Message; | ||
isSuppressed = message is IDeadLetterSuppression; | ||
} | ||
|
||
return isSuppressed; | ||
} | ||
} | ||
|
||
/// <summary> | ||
|
@@ -226,19 +238,20 @@ public DeadLetterActorRef(IActorRefProvider provider, ActorPath path, EventStrea | |
/// <exception cref="InvalidMessageException">This exception is thrown if the given <paramref name="message"/> is undefined.</exception> | ||
protected override void TellInternal(object message, IActorRef sender) | ||
{ | ||
if (message == null) throw new InvalidMessageException("Message is null"); | ||
var i = message as Identify; | ||
if (i != null) | ||
switch (message) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Refomatting - nothing of significance here |
||
{ | ||
sender.Tell(new ActorIdentity(i.MessageId, ActorRefs.Nobody)); | ||
return; | ||
} | ||
var d = message as DeadLetter; | ||
if (d != null) | ||
{ | ||
if (!SpecialHandle(d.Message, d.Sender)) { _eventStream.Publish(d); } | ||
return; | ||
case null: | ||
throw new InvalidMessageException("Message is null"); | ||
case Identify i: | ||
sender.Tell(new ActorIdentity(i.MessageId, ActorRefs.Nobody)); | ||
return; | ||
case DeadLetter d: | ||
{ | ||
if (!SpecialHandle(d.Message, d.Sender)) { _eventStream.Publish(d); } | ||
return; | ||
} | ||
} | ||
|
||
if (!SpecialHandle(message, sender)) { _eventStream.Publish(new DeadLetter(message, sender.IsNobody() ? Provider.DeadLetters : sender, this)); } | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -46,9 +46,13 @@ public DeadLetterMessageQueue(IActorRef deadLetters) | |
/// <param name="envelope">TBD</param> | ||
public void Enqueue(IActorRef receiver, Envelope envelope) | ||
{ | ||
if (envelope.Message is DeadLetter) | ||
if (envelope.Message is AllDeadLetters) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Important fix - now that we can produce |
||
{ | ||
// actor subscribing to DeadLetter. Drop it. | ||
/* We're receiving a DeadLetter sent to us by someone else (which is not normal - usually only happens | ||
* if we were explicitly subscribed to DeadLetters on the EventStream). | ||
* | ||
* Have to terminate here in order to prevent a stack overflow. | ||
*/ | ||
return; | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -104,7 +104,7 @@ public sealed class SuppressedDeadLetter : AllDeadLetters | |
/// <exception cref="ArgumentNullException"> | ||
/// This exception is thrown when either the sender or the recipient is undefined. | ||
/// </exception> | ||
public SuppressedDeadLetter(IDeadLetterSuppression message, IActorRef sender, IActorRef recipient) : base(message, sender, recipient) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Breaking API change here, kind of - needed to relax this type constraint otherwise we'd lose data in the |
||
public SuppressedDeadLetter(object message, IActorRef sender, IActorRef recipient) : base(message, sender, recipient) | ||
{ | ||
if (sender == null) throw new ArgumentNullException(nameof(sender), "SuppressedDeadLetter sender may not be null"); | ||
if (recipient == null) throw new ArgumentNullException(nameof(recipient), "SuppressedDeadLetter recipient may not be null"); | ||
|
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.
Function to check, up and down the stack, if a message was marked as
IDeadLetterSuppression
anywhere within