Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 12 additions & 7 deletions src/Adaptive.Cluster.Tests/Client/AeronClusterAsyncConnectTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ public void ShouldCloseIngressPublicationsOnMembers()
A.CallTo(() => _aeron.AsyncAddSubscription(_context.EgressChannel(), _context.EgressStreamId()))
.Returns(subscriptionId);
var subscription = A.Fake<Subscription>();
A.CallTo(() => subscription.TryResolveChannelEndpointPort()).Returns("something");
A.CallTo(() => _aeron.GetSubscription(subscriptionId)).Returns(subscription);

const int ingressStreamId = 878;
Expand Down Expand Up @@ -206,24 +207,28 @@ public void ShouldCloseIngressPublicationsOnMembers()
for (int i = 0; i < iterations; i++)
{
Assert.IsNull(asyncConnect.Poll());
Assert.AreEqual(AsyncConnectState.CREATE_INGRESS_PUBLICATIONS, asyncConnect.State());
Assert.AreEqual(AsyncConnectState.AWAIT_PUBLICATION_CONNECTED, asyncConnect.State());
}

A.CallTo(() => _aeron.AsyncAddExclusivePublication("aeron:udp?endpoint=localhost:20000", ingressStreamId))
.MustHaveHappenedANumberOfTimesMatching(n => n <= 1);
A.CallTo(() => _aeron.AsyncAddExclusivePublication("aeron:udp?endpoint=localhost:20001", ingressStreamId))
.MustHaveHappened(iterations, Times.Exactly);
.MustHaveHappened(iterations - 1, Times.Exactly);
A.CallTo(() => _aeron.AsyncAddExclusivePublication("aeron:udp?endpoint=localhost:20002", ingressStreamId))
.MustHaveHappenedANumberOfTimesMatching(n => n <= 1);
A.CallTo(() => _aeron.GetExclusivePublication(publicationId1)).MustHaveHappened(2, Times.Exactly);
A.CallTo(() => _aeron.GetExclusivePublication(publicationId2)).MustHaveHappened(iterations, Times.Exactly);
A.CallTo(() => _aeron.GetExclusivePublication(publicationId3)).MustHaveHappened(iterations, Times.Exactly);
A.CallTo(() => _aeron.GetExclusivePublication(publicationId2))
.MustHaveHappened(iterations - 1, Times.Exactly);
A.CallTo(() => _aeron.GetExclusivePublication(publicationId3))
.MustHaveHappened(iterations - 1, Times.Exactly);

asyncConnect.Dispose();

A.CallTo(() => subscription.Dispose()).MustHaveHappened();
A.CallTo(subscription).MustHaveHappenedOnceExactly();
A.CallTo(() => publication1.Dispose()).MustHaveHappened();
A.CallTo(() => subscription.TryResolveChannelEndpointPort())
.MustHaveHappened(iterations - 1, Times.Exactly);
A.CallTo(() => subscription.Dispose()).MustHaveHappenedOnceExactly();
A.CallTo(() => publication1.IsConnected).MustHaveHappened(iterations - 2, Times.Exactly);
A.CallTo(() => publication1.Dispose()).MustHaveHappenedOnceExactly();
A.CallTo(() => _context.Dispose()).MustHaveHappenedOnceExactly();
A.CallTo(() => _aeron.AsyncRemovePublication(publicationId3))
.MustHaveHappenedANumberOfTimesMatching(n => n <= 1);
Expand Down
32 changes: 32 additions & 0 deletions src/Adaptive.Cluster.Tests/Client/AeronClusterTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
using System;
using System.Collections.Generic;
using Adaptive.Aeron;
using Adaptive.Aeron.Exceptions;
using Adaptive.Aeron.LogBuffer;
using Adaptive.Aeron.Protocol;
using Adaptive.Agrona;
Expand Down Expand Up @@ -214,6 +215,37 @@ public void ShouldStayConnectedAfterSuccessfulFailover(bool withIngressDisconnec
Assert.IsFalse(_aeronCluster.Closed);
}

[Test]
public void ShouldRetryNewLeaderIngressPublicationWhenSendChannelEndpointIsClosing()
{
long registrationId = _ingressPublication.RegistrationId;
A.CallTo(() => _aeron.GetExclusivePublication(registrationId))
.Throws(
new RegistrationException(
registrationId,
(int)ErrorCode.RESOURCE_TEMPORARILY_UNAVAILABLE,
ErrorCode.RESOURCE_TEMPORARILY_UNAVAILABLE,
"send_channel_endpoint found in CLOSING state, please retry"
)
)
.Once()
.Then.Returns(_ingressPublication);

MakeEgressSubscriptionDeliverNewLeaderEvent();

Assert.AreEqual(1, _aeronCluster.PollEgress());
A.CallTo(() =>
_egressListener.OnNewLeader(
ClusterSessionId,
_leadershipTermId,
_leaderMemberId,
IngressEndpoints
)
)
.MustHaveHappened();
Assert.IsFalse(_aeronCluster.Closed);
}

[TestCase(false)]
[TestCase(true)]
public void ShouldCloseItselfWhenUnableToSendMessageForLongerThanNewLeaderConnectionTimeout(
Expand Down
64 changes: 36 additions & 28 deletions src/Adaptive.Cluster/Client/AeronCluster.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1087,11 +1087,28 @@ private Publication AddNewLeaderIngressPublication(Context ctx, string channel,
long deadlineNs = _nanoClock.NanoTime() + ctx.MessageTimeoutNs();
do
{
Publication publication = GetIngressPublication(ctx, registrationId);
if (null != publication)
if (NULL_VALUE == registrationId)
{
return publication;
registrationId = AsyncAddIngressPublication(ctx, channel, streamId);
}

try
{
Publication publication = GetIngressPublication(ctx, registrationId);
if (null != publication)
{
return publication;
}
}
catch (RegistrationException ex)
{
registrationId = NULL_VALUE;
if (ErrorCode.RESOURCE_TEMPORARILY_UNAVAILABLE != ex.ErrorCode())
{
throw;
}
}

_idleStrategy.Idle(ctx.RunAgentInvokers());
} while (_nanoClock.NanoTime() < deadlineNs);

Expand Down Expand Up @@ -2447,10 +2464,13 @@ private void CreateIngressPublications()
{
_ingressPublication = GetIngressPublication(_ctx, _ingressRegistrationId);
}
catch (RegistrationException)
catch (RegistrationException ex)
{
_ingressRegistrationId = NULL_VALUE;
throw;
if (ErrorCode.RESOURCE_TEMPORARILY_UNAVAILABLE != ex.ErrorCode())
{
throw;
}
}
}
else
Expand All @@ -2461,27 +2481,7 @@ private void CreateIngressPublications()
}
else
{
int count = 0;
foreach (MemberIngress member in _memberByIdMap.Values)
{
if (null != member._publication || null != member._publicationException)
{
count++;
}
else
{
if (NULL_VALUE == member._registrationId)
{
member.AsyncAddPublication();
}
member.AsyncGetPublication();
}
}

if (_memberByIdMap.Count == count)
{
State(AWAIT_PUBLICATION_CONNECTED);
}
State(AWAIT_PUBLICATION_CONNECTED);
}
}

Expand All @@ -2494,8 +2494,12 @@ private void AwaitPublicationConnected()
{
foreach (MemberIngress member in _memberByIdMap.Values)
{
if (null == member._publication && NULL_VALUE != member._registrationId)
if (null == member._publication && null == member._publicationException)
{
if (NULL_VALUE == member._registrationId)
{
member.AsyncAddPublication();
}
member.AsyncGetPublication();
}

Expand Down Expand Up @@ -2728,7 +2732,11 @@ internal void AsyncGetPublication()
}
catch (RegistrationException ex)
{
_publicationException = ex;
if (ErrorCode.RESOURCE_TEMPORARILY_UNAVAILABLE != ex.ErrorCode())
{
_publicationException = ex;
}

_registrationId = NULL_VALUE;
}
}
Expand Down
Loading