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

Fix: no DeadLetters when publishing to a Topic with no subscribers #5561

Merged
merged 5 commits into from
Feb 3, 2022
Merged

Fix: no DeadLetters when publishing to a Topic with no subscribers #5561

merged 5 commits into from
Feb 3, 2022

Conversation

eaba
Copy link
Contributor

@eaba eaba commented Feb 2, 2022

The summary of the PubSub design is this, as it relates to #5352, if there are no subscribers, wait on the Deadline and if no new subscriber within that window terminate the Topic actor.

It is the waiting on the Deadline that is the actual issue.

@eaba
Copy link
Contributor Author

eaba commented Feb 2, 2022

This relies on the Topic ActorRef termination and if we want it to publish to deadletters when there are zero subscribers, we will need to change the current design:

private void IgnoreOrSendToDeadLetters(object message)
{
if (_settings.SendToDeadLettersWhenNoSubscribers)
Context.System.DeadLetters.Tell(new DeadLetter(message, Sender, Context.Self));
}
private void PublishMessage(string path, object message, bool allButSelf = false)
{
IEnumerable<IActorRef> Refs()
{
foreach (var entry in _registry)
{
var address = entry.Key;
var bucket = entry.Value;
if (!(allButSelf && address == _cluster.SelfAddress) && bucket.Content.TryGetValue(path, out var valueHolder))
{
if (valueHolder != null && !valueHolder.Ref.IsNobody())
yield return valueHolder.Ref;
}
}
}
var counter = 0;
foreach (var r in Refs())
{
if (r == null) continue;
r.Forward(message);
counter++;
}
if (counter == 0) IgnoreOrSendToDeadLetters(message);
}

Copy link
Member

@Aaronontheweb Aaronontheweb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left some comments on the structure of the test

Copy link
Contributor Author

@eaba eaba left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Aaronontheweb improved the test with the latest commit

@eaba eaba changed the title Reproduce Pub Sub Issue - not to be merged. Reproduce Pub Sub Issue Feb 3, 2022
@eaba eaba marked this pull request as ready for review February 3, 2022 11:19
Copy link
Member

@Aaronontheweb Aaronontheweb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left some comments on the changes included in here

_ = ExpectMsg<UnsubscribeAck>();

// assert
await EventFilter.DeadLetter<object>().ExpectAsync(1,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reproduction - as @eaba pointed out this spec would fail before because the TTL value kept the topic actor alive for 120s. The real bug was that the topic actor never published any DeadLetter instances if it was alive but had no subscribers.

@@ -643,7 +643,7 @@ private long NextVersion()

private IActorRef NewTopicActor(string encodedTopic)
{
var t = Context.ActorOf(Actor.Props.Create(() => new Topic(_settings.RemovedTimeToLive, _settings.RoutingLogic)), encodedTopic);
var t = Context.ActorOf(Actor.Props.Create(() => new Topic(_settings.RemovedTimeToLive, _settings.RoutingLogic, _settings.SendToDeadLettersWhenNoSubscribers)), encodedTopic);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Propagate akka.cluster.pub-sub.send-to-dead-letters-when-no-subscribers to the topic actors, who are the ones who actually need to implement this.

/// A <see cref="DeadLetter"/> published when there are no subscribers
/// for a topic that has received a <see cref="Publish"/> event.
/// </summary>
internal readonly struct NoSubscribersDeadLetter
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Created an envelope NoSubscribersDeadLetter in order to help make it clear inside the user's logging system why this DeadLetter was published. Created it as a readonly struct because it will immediately be captured inside a DeadLetter and therefore we can save on an allocation here in the event of a large number of deadletters being published all at once.

/// <param name="emptyTimeToLive">The TTL for how often this actor will be removed.</param>
/// <param name="sendToDeadLettersWhenNone">When set to <c>true</c>, this actor will
/// publish a <see cref="DeadLetter"/> for each message if the total number of subscribers == 0.</param>
protected TopicLike(TimeSpan emptyTimeToLive, bool sendToDeadLettersWhenNone)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated constructor to receive new value. These are all internal classes so no breaking changes here.

@@ -116,22 +151,23 @@ protected bool DefaultReceive(object message)
default:
foreach (var subscriber in Subscribers)
subscriber.Forward(message);

// no subscribers
if (Subscribers.Count == 0 && SendToDeadLettersWhenNoSubscribers)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The bugfix: @eaba pointed out that this actor never was programmed to publish to deadletters when the subscriber count is zero, so we do this after the foreach loop (arbitrary) if we're configured for it. This causes the reproduction spec to now pass.

@Aaronontheweb Aaronontheweb changed the title Reproduce Pub Sub Issue Fix: no DeadLetters when publishing to a Topic with no subscribers Feb 3, 2022
@Aaronontheweb Aaronontheweb merged commit 8c3fe57 into akkadotnet:dev Feb 3, 2022
@eaba eaba deleted the reproduce_pub_sub_issue branch February 3, 2022 15:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants