Skip to content

Commit

Permalink
Merge pull request #2143 from Aaronontheweb/2138-fix-reachability
Browse files Browse the repository at this point in the history
added missing copyright headers; added spec to verify joining when a seed node is offline
  • Loading branch information
Aaronontheweb authored Jul 6, 2016
2 parents c2dd30e + 04e4dc5 commit 010ef67
Show file tree
Hide file tree
Showing 36 changed files with 442 additions and 49 deletions.
2 changes: 1 addition & 1 deletion RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#### 1.0.9 April 26 2016 ####
#### 1.0.10 April 26 2016 ####
Placeholder for next release

#### 1.0.8 April 26 2016 ####
Expand Down
10 changes: 9 additions & 1 deletion src/SharedAssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
// <auto-generated/>
//-----------------------------------------------------------------------
// <copyright file="SharedAssemblyInfo.cs" company="Akka.NET Project">
// Copyright (C) 2009-2016 Lightbend Inc. <http://www.typesafe.com>
// Copyright (C) 2013-2016 Akka.NET project <https://github.com/akkadotnet/akka.net>
// </copyright>
//-----------------------------------------------------------------------

// <auto-generated/>
using System.Reflection;

[assembly: AssemblyCompanyAttribute("Akka.NET Team")]
[assembly: AssemblyCopyrightAttribute("Copyright © 2013-2016 Akka.NET Team")]
[assembly: AssemblyTrademarkAttribute("")]
[assembly: AssemblyVersionAttribute("1.0.9.0")]
[assembly: AssemblyFileVersionAttribute("1.0.9.0")]

Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
using System.Reflection;
//-----------------------------------------------------------------------
// <copyright file="AssemblyInfo.cs" company="Akka.NET Project">
// Copyright (C) 2009-2016 Lightbend Inc. <http://www.typesafe.com>
// Copyright (C) 2013-2016 Akka.NET project <https://github.com/akkadotnet/akka.net>
// </copyright>
//-----------------------------------------------------------------------

using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

Expand Down Expand Up @@ -34,3 +41,4 @@
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
using System;
//-----------------------------------------------------------------------
// <copyright file="QueryExecutor.cs" company="Akka.NET Project">
// Copyright (C) 2009-2016 Lightbend Inc. <http://www.typesafe.com>
// Copyright (C) 2013-2016 Akka.NET project <https://github.com/akkadotnet/akka.net>
// </copyright>
//-----------------------------------------------------------------------

using System;
using System.Data;
using System.Data.Common;
using System.Threading;
Expand Down Expand Up @@ -316,4 +323,5 @@ protected object GetSnapshot(DbDataReader reader)
return obj;
}
}
}
}

Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
using System;
//-----------------------------------------------------------------------
// <copyright file="DefaultConfigSpec.cs" company="Akka.NET Project">
// Copyright (C) 2009-2016 Lightbend Inc. <http://www.typesafe.com>
// Copyright (C) 2013-2016 Akka.NET project <https://github.com/akkadotnet/akka.net>
// </copyright>
//-----------------------------------------------------------------------

using System;
using Akka.Configuration;
using Akka.Persistence.Query;
using Akka.Persistence.Query.Sql;
Expand Down Expand Up @@ -26,4 +33,5 @@ public void SqlReadJournal_applies_default_config()
config.GetInt("max-buffer-size").Should().Be(100);
}
}
}
}

Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
using System.Reflection;
//-----------------------------------------------------------------------
// <copyright file="AssemblyInfo.cs" company="Akka.NET Project">
// Copyright (C) 2009-2016 Lightbend Inc. <http://www.typesafe.com>
// Copyright (C) 2013-2016 Akka.NET project <https://github.com/akkadotnet/akka.net>
// </copyright>
//-----------------------------------------------------------------------

using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

Expand Down Expand Up @@ -34,3 +41,4 @@
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ namespace Akka.Cluster
public sealed class ClusterShuttingDown : Akka.Cluster.ClusterEvent.IClusterDomainEvent
{
public static readonly Akka.Cluster.ClusterEvent.IClusterDomainEvent Instance;
public override string ToString() { }
}
public sealed class CurrentClusterState
{
Expand All @@ -68,6 +69,7 @@ namespace Akka.Cluster
public Akka.Actor.Address Leader { get; }
public override bool Equals(object obj) { }
public override int GetHashCode() { }
public override string ToString() { }
}
public sealed class MemberExited : Akka.Cluster.ClusterEvent.MemberStatusChange
{
Expand Down Expand Up @@ -95,6 +97,7 @@ namespace Akka.Cluster
public Akka.Cluster.Member Member { get; }
public override bool Equals(object obj) { }
public override int GetHashCode() { }
public override string ToString() { }
}
public sealed class MemberUp : Akka.Cluster.ClusterEvent.MemberStatusChange
{
Expand All @@ -106,6 +109,7 @@ namespace Akka.Cluster
public Akka.Cluster.Member Member { get; }
public override bool Equals(object obj) { }
public override int GetHashCode() { }
public override string ToString() { }
}
public sealed class ReachableMember : Akka.Cluster.ClusterEvent.ReachabilityEvent
{
Expand All @@ -118,6 +122,7 @@ namespace Akka.Cluster
public string Role { get; }
public override bool Equals(object obj) { }
public override int GetHashCode() { }
public override string ToString() { }
}
public enum SubscriptionInitialStateMode
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@
<Compile Include="SunnyWeatherSpec.cs" />
<Compile Include="TransitionSpec.cs" />
<Compile Include="UnreachableNodeJoinsAgainSpec.cs" />
<Compile Include="JoinWithOfflineSeedNodeSpec.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\contrib\testkits\Akka.TestKit.Xunit2\Akka.TestKit.Xunit2.csproj">
Expand Down
196 changes: 196 additions & 0 deletions src/core/Akka.Cluster.Tests.MultiNode/JoinWithOfflineSeedNodeSpec.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
//-----------------------------------------------------------------------
// <copyright file="JoinWithOfflineSeedNodeSpec.cs" company="Akka.NET Project">
// Copyright (C) 2009-2016 Lightbend Inc. <http://www.typesafe.com>
// Copyright (C) 2013-2016 Akka.NET project <https://github.com/akkadotnet/akka.net>
// </copyright>
//-----------------------------------------------------------------------

using System;
using System.Collections.Immutable;
using Akka.Actor;
using Akka.Actor.Dsl;
using Akka.Cluster.TestKit;
using Akka.Event;
using Akka.Remote.TestKit;
using FluentAssertions;

namespace Akka.Cluster.Tests.MultiNode
{
public class JoinWithOfflineSeedNodeConfig : MultiNodeConfig
{
public RoleName Seed { get; }

public RoleName NonSeed { get; }

public JoinWithOfflineSeedNodeConfig()
{
Seed = Role("seed");
NonSeed = Role("nonseed");

CommonConfig = DebugConfig(false).WithFallback(MultiNodeClusterSpec.ClusterConfig());
}
}

public class JoinWithOfflineSeedNodeSpecNode1 : JoinWithOfflineSeedNodeSpec { }
public class JoinWithOfflineSeedNodeSpecNode2 : JoinWithOfflineSeedNodeSpec { }

/// <summary>
/// Tests to ensure that if we have 2 seed nodes defined and 1 is offline during a <see cref="Cluster.JoinSeedNodes"/>
/// command, the joining node will still be marked as <see cref="MemberStatus.Up"/> as long as there are no unreachable nodes
/// within the cluster.
/// </summary>
public abstract class JoinWithOfflineSeedNodeSpec : MultiNodeClusterSpec
{
private readonly JoinWithOfflineSeedNodeConfig _config;

private ImmutableList<Address> SeedNodes => ImmutableList.Create(SeedUniqueAddress.Address);

private Lazy<ActorSystem> _seedSystem;
private Lazy<ActorSystem> _unavailableSeedSystem;

volatile UniqueAddress _seedUniqueAddress;
public UniqueAddress SeedUniqueAddress => _seedUniqueAddress;

private Address _verifiedLeader;

protected JoinWithOfflineSeedNodeSpec() : this(new JoinWithOfflineSeedNodeConfig()) { }

protected JoinWithOfflineSeedNodeSpec(JoinWithOfflineSeedNodeConfig config) : base(config)
{
_config = config;
_seedSystem = new Lazy<ActorSystem>(() => ActorSystem.Create(Sys.Name, Sys.Settings.Config));
_unavailableSeedSystem = new Lazy<ActorSystem>(() => ActorSystem.Create(Sys.Name, Sys.Settings.Config));
}

protected override void AfterTermination()
{
RunOn(() =>
{
Shutdown(_seedSystem.Value);
}, _config.Seed);

RunOn(() =>
{
if (!_unavailableSeedSystem.Value.WhenTerminated.IsCompleted)
Shutdown(_unavailableSeedSystem.Value);
}, _config.NonSeed);

base.AfterTermination();
}

class LeaderSynchronizer : ReceiveActor
{
public LeaderSynchronizer()
{
Receive<string>(str => str.Equals("leader"), _ => Sender.Tell(Cluster.Get(Context.System).State.Leader));
}
}

/// <summary>
/// Solely for debugging purposes.
/// </summary>
class DomainEventLogger : ReceiveActor
{
private ILoggingAdapter _log = Context.GetLogger();

protected override void PreStart()
{
Akka.Cluster.Cluster.Get(Context.System).Subscribe(Self, ClusterEvent.SubscriptionInitialStateMode.InitialStateAsEvents, typeof(ClusterEvent.IClusterDomainEvent));
}

protected override void PostStop()
{
Akka.Cluster.Cluster.Get(Context.System).Unsubscribe(Self);
}

public DomainEventLogger()
{
ReceiveAny(i => _log.Debug(i.ToString()));
}
}

[MultiNodeFact]
public void JoinClusterWithOneOfflineSeedNode()
{
Within(TimeSpan.FromSeconds(30), () =>
{
RunOn(() =>
{
Sys.ActorOf(c => c.Receive<UniqueAddress>((address, ctx) =>
{
_seedUniqueAddress = address;
ctx.Sender.Tell("ok");
}), "address-receiver");
Sys.ActorOf(Props.Create(() => new DomainEventLogger()), "cluster-logger");
}, _config.NonSeed);
EnterBarrier("addr-receiver-ready");
RunOn(() =>
{
_seedUniqueAddress = Cluster.Get(_seedSystem.Value).SelfUniqueAddress;
_seedSystem.Value.ActorOf(Props.Create(() => new DomainEventLogger()), "clusterLogger");
var probe = CreateTestProbe(_seedSystem.Value);
_seedSystem.Value.ActorSelection(new RootActorPath(GetAddress(_config.NonSeed)) / "user" / "address-receiver").Tell(_seedUniqueAddress, probe.Ref);
probe.ExpectMsg("ok", TimeSpan.FromSeconds(5));
}, _config.Seed);
EnterBarrier("addr-transferred");
RunOn(() =>
{
Cluster.Get(_seedSystem.Value).JoinSeedNodes(SeedNodes);
AwaitCondition(() => Cluster.Get(_seedSystem.Value).ReadView.IsSingletonCluster);
_seedSystem.Value.ActorOf(Props.Create(() => new LeaderSynchronizer()), "leader-sync");
}, _config.Seed);
EnterBarrier("seed-self-joined");
RunOn(() =>
{
var unreachableNodeAddress = Cluster.Get(_unavailableSeedSystem.Value).SelfAddress;
// terminate the unreachableSeedNode
Shutdown(_unavailableSeedSystem.Value, RemainingOrDefault);
Cluster.JoinSeedNodes(SeedNodes.Add(unreachableNodeAddress)); // append the unreachable node address
AwaitMembersUp(2);
Sys.ActorOf(Props.Create(() => new LeaderSynchronizer()), "leader-sync");
}, _config.NonSeed);
EnterBarrier("formed-cluster");
/*
* Verify that both nodes agree on who the leader is
*/
RunOn(() =>
{
var addr2 = GetAddress(_config.NonSeed);
var probe2 = CreateTestProbe(_seedSystem.Value);
AwaitAssert(() =>
{
_seedSystem.Value.ActorSelection(new RootActorPath(addr2) / "user" / "leader-sync")
.Tell("leader", probe2.Ref);
_verifiedLeader = probe2.ExpectMsg<Address>();
_verifiedLeader.Should().Be(Cluster.Get(_seedSystem.Value).State.Leader);
});
}, _config.Seed);
RunOn(() =>
{
AwaitAssert(() =>
{
_verifiedLeader =
Sys.ActorSelection(new RootActorPath(SeedUniqueAddress.Address) / "user" / "leader-sync")
.Ask<Address>("leader")
.Result;
_verifiedLeader.Should().Be(Cluster.State.Leader);
});
}, _config.NonSeed);
EnterBarrier("verified-leader");
});
}
}
}

Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
using System;
//-----------------------------------------------------------------------
// <copyright file="LeaderDowningAllOtherNodesSpec.cs" company="Akka.NET Project">
// Copyright (C) 2009-2016 Lightbend Inc. <http://www.typesafe.com>
// Copyright (C) 2013-2016 Akka.NET project <https://github.com/akkadotnet/akka.net>
// </copyright>
//-----------------------------------------------------------------------

using System;
using System.Collections.Immutable;
using System.Linq;
using Akka.Cluster.TestKit;
Expand Down Expand Up @@ -86,4 +93,5 @@ public void A_Cluster_of_6_nodes_with_monitored_by_nr_of_members_2_must_remove_a
AwaitMembersUp(numbersOfMembers: 1, canNotBePartOfMemberRing: shutdownAddresses, timeout: 30.Seconds());
}
}
}
}

10 changes: 9 additions & 1 deletion src/core/Akka.Cluster.Tests.MultiNode/QuickRestartSpec.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
using System;
//-----------------------------------------------------------------------
// <copyright file="QuickRestartSpec.cs" company="Akka.NET Project">
// Copyright (C) 2009-2016 Lightbend Inc. <http://www.typesafe.com>
// Copyright (C) 2013-2016 Akka.NET project <https://github.com/akkadotnet/akka.net>
// </copyright>
//-----------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
Expand Down Expand Up @@ -139,3 +146,4 @@ private void JoinAndRestart()

}
}

Loading

0 comments on commit 010ef67

Please sign in to comment.