Skip to content

Instantly share code, notes, and snippets.

@ZoolWay
Last active July 12, 2016 07:46
Show Gist options
  • Save ZoolWay/8092e7c2aa3a86b009981885cd4aa271 to your computer and use it in GitHub Desktop.
Save ZoolWay/8092e7c2aa3a86b009981885cd4aa271 to your computer and use it in GitHub Desktop.
Very basic console-based Akka.NET cluster seed node and worker node
// ....
[assembly: log4net.Config.XmlConfigurator()]
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Akka" version="1.1.0" targetFramework="net461" />
<package id="Akka.Cluster" version="1.1.0" targetFramework="net461" />
<package id="Akka.Logger.log4net" version="1.0.8" targetFramework="net461" />
<package id="Akka.Remote" version="1.1.0" targetFramework="net461" />
<package id="Akka.Serialization.Wire" version="1.1.0.26-beta" targetFramework="net461" />
<package id="Google.ProtocolBuffers" version="2.4.1.555" targetFramework="net461" />
<package id="Helios" version="2.1.1" targetFramework="net461" />
<package id="log4net" version="2.0.5" targetFramework="net461" />
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net461" />
<package id="System.Collections.Immutable" version="1.2.0" targetFramework="net461" />
<package id="Wire" version="0.0.6" targetFramework="net461" />
</packages>
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="akka" type="Akka.Configuration.Hocon.AkkaConfigurationSection, Akka" />
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>
<log4net>
<appender name="ColoredConsoleAppender" type="log4net.Appender.ColoredConsoleAppender">
<mapping>
<level value="ERROR" />
<foreColor value="Red, HighIntensity" />
</mapping>
<mapping>
<level value="WARN" />
<foreColor value="Yellow" />
</mapping>
<mapping>
<level value="INFO" />
<foreColor value="White, HighIntensity" />
</mapping>
<mapping>
<level value="DEBUG" />
<foreColor value="White" />
</mapping>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%5level %date{HH:mm:ss} [%2thread] %30.30logger - %message%newline" />
</layout>
</appender>
<root>
<level value="DEBUG" />
<appender-ref ref="ColoredConsoleAppender" />
</root>
</log4net>
<akka>
<hocon>
<![CDATA[
akka {
actor {
provider = "Akka.Cluster.ClusterActorRefProvider, Akka.Cluster"
serializers {
wire = "Akka.Serialization.WireSerializer, Akka.Serialization.Wire"
}
serialization-bindings {
"System.Object" = wire
}
}
remote {
helios.tcp {
transport-class = "Akka.Remote.Transport.Helios.HeliosTcpTransport, Akka.Remote"
applied-adapters = []
transport-protocol = tcp
hostname = "127.0.0.1"
port = 0
}
}
loggers = ["Akka.Logger.log4net.Log4NetLogger,Akka.Logger.log4net"]
cluster {
seed-nodes = ["akka.tcp://sample@127.0.0.1:7001"]
roles = [node1]
}
}
]]>
</hocon>
</akka>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
</startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-9.0.0.0" newVersion="9.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.2.0.0" newVersion="1.2.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
using System;
using System.Threading;
using Akka.Actor;
namespace ClusterSeedNode
{
class Program
{
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.FullName);
private static readonly ManualResetEvent quitEvent = new ManualResetEvent(false);
private static readonly ManualResetEvent asTerminatedEvent = new ManualResetEvent(false);
static void Main(string[] args)
{
Console.CancelKeyPress += (sender, e) =>
{
quitEvent.Set();
e.Cancel = true;
};
log.Debug("Creating actor system");
ActorSystem actorSystem = ActorSystem.Create("sample");
quitEvent.WaitOne();
log.Info("Shutting down");
var cluster = Akka.Cluster.Cluster.Get(actorSystem);
cluster.RegisterOnMemberRemoved(() => MemberRemoved(actorSystem));
cluster.Leave(cluster.SelfAddress);
asTerminatedEvent.WaitOne();
log.Info("Actor system terminated, exiting");
if (System.Diagnostics.Debugger.IsAttached) Console.ReadLine();
}
private static async void MemberRemoved(ActorSystem actorSystem)
{
await actorSystem.Terminate();
asTerminatedEvent.Set();
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="akka" type="Akka.Configuration.Hocon.AkkaConfigurationSection, Akka" />
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>
<log4net>
<appender name="ColoredConsoleAppender" type="log4net.Appender.ColoredConsoleAppender">
<mapping>
<level value="ERROR" />
<foreColor value="Red, HighIntensity" />
</mapping>
<mapping>
<level value="WARN" />
<foreColor value="Yellow" />
</mapping>
<mapping>
<level value="INFO" />
<foreColor value="White, HighIntensity" />
</mapping>
<mapping>
<level value="DEBUG" />
<foreColor value="White" />
</mapping>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%5level %date{HH:mm:ss} [%2thread] %30.30logger - %message%newline" />
</layout>
</appender>
<root>
<level value="DEBUG" />
<appender-ref ref="ColoredConsoleAppender" />
</root>
</log4net>
<akka>
<hocon>
<![CDATA[
akka {
actor {
provider = "Akka.Cluster.ClusterActorRefProvider, Akka.Cluster"
serializers {
wire = "Akka.Serialization.WireSerializer, Akka.Serialization.Wire"
}
serialization-bindings {
"System.Object" = wire
}
}
remote {
helios.tcp {
transport-class = "Akka.Remote.Transport.Helios.HeliosTcpTransport, Akka.Remote"
applied-adapters = []
transport-protocol = tcp
hostname = "127.0.0.1"
port = 0
}
}
loggers = ["Akka.Logger.log4net.Log4NetLogger,Akka.Logger.log4net"]
cluster {
seed-nodes = ["akka.tcp://sample@127.0.0.1:7001"]
roles = [node1]
}
}
]]>
</hocon>
</akka>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
</startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-9.0.0.0" newVersion="9.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.2.0.0" newVersion="1.2.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
using System;
using System.Threading;
using Akka.Actor;
namespace ClusterWorkerNode
{
class Program
{
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.FullName);
private static readonly ManualResetEvent quitEvent = new ManualResetEvent(false);
private static readonly ManualResetEvent asTerminatedEvent = new ManualResetEvent(false);
static void Main(string[] args)
{
Console.CancelKeyPress += (sender, e) =>
{
quitEvent.Set();
e.Cancel = true;
};
log.Debug("Creating actor system");
ActorSystem actorSystem = ActorSystem.Create("sample");
quitEvent.WaitOne();
log.Info("Shutting down");
var cluster = Akka.Cluster.Cluster.Get(actorSystem);
cluster.RegisterOnMemberRemoved(() => MemberRemoved(actorSystem));
cluster.Leave(cluster.SelfAddress);
asTerminatedEvent.WaitOne();
log.Info("Actor system terminated, exiting");
if (System.Diagnostics.Debugger.IsAttached) Console.ReadLine();
}
private static async void MemberRemoved(ActorSystem actorSystem)
{
await actorSystem.Terminate();
asTerminatedEvent.Set();
}
}
}
@ZoolWay
Copy link
Author

ZoolWay commented Jul 12, 2016

To reproduce the leave/shutdown problem:

  • Start seed node instance
  • Start worker node instance
  • Both nodes are marked as Up in the leader node (which is the ssed node)
  • Press Ctrl+C in worker node instance to trigger graceful shutdown

This is the output:

DEBUG 09:43:44 [ 9]        ClusterSeedNode.Program - Creating actor system
 INFO 09:43:44 [13] ent.DummyClassForStringSources - Starting remoting
 INFO 09:43:44 [ 6] ent.DummyClassForStringSources - Remoting started; listening on addresses : [akka.tcp://sample@127.0.0.1:7001]
 INFO 09:43:44 [12] ent.DummyClassForStringSources - Remoting now listens on addresses: [akka.tcp://sample@127.0.0.1:7001]
 INFO 09:43:44 [ 6] ent.DummyClassForStringSources - Cluster Node [akka.tcp://sample@127.0.0.1:7001] - Starting up...
 INFO 09:43:44 [15] ent.DummyClassForStringSources - Cluster Node [akka.tcp://sample@127.0.0.1:7001] - Started up successfully
 INFO 09:43:45 [15] Akka.Cluster.ClusterCoreDaemon - Node [akka.tcp://sample@127.0.0.1:7001] is JOINING, roles [seed]
 INFO 09:43:45 [ 6] Akka.Cluster.ClusterCoreDaemon - Leader is moving node [akka.tcp://sample@127.0.0.1:7001] to [Up]
 INFO 09:43:57 [12] Akka.Cluster.ClusterCoreDaemon - Node [akka.tcp://sample@127.0.0.1:14922] is JOINING, roles [node1]
 INFO 09:43:58 [12] Akka.Cluster.ClusterCoreDaemon - Leader is moving node [akka.tcp://sample@127.0.0.1:14922] to [Up]
 INFO 09:43:59 [14] Akka.Cluster.ClusterCoreDaemon - Leader is moving node [akka.tcp://sample@127.0.0.1:14922] to [Up]
 INFO 09:44:27 [27] Akka.Cluster.ClusterCoreDaemon - Leader is moving node [akka.tcp://sample@127.0.0.1:14922] to [Exiting]
ERROR 09:44:27 [ 6] nsport.Helios.TcpServerHandler - Error caught channel [[::ffff:127.0.0.1]:7001->[::ffff:127.0.0.1]:14923](Id=ChannelId(-373585024))
System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'System.Net.Sockets.Socket'.
   at System.Net.Sockets.Socket.Receive(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags, SocketError& errorCode)
   at Helios.Channels.Sockets.TcpSocketChannel.DoReadBytes(IByteBuf buf)
   at Helios.Channels.Sockets.AbstractSocketByteChannel.SocketByteChannelUnsafe.FinishRead(SocketChannelAsyncOperation operation)
 INFO 09:44:27 [15]       Akka.Actor.LocalActorRef - Message Disassociated from NoSender to akka://sample/system/transports/akkaprotocolmanager.tcp.0/akkaProtocol-tcp%3a%2f%2fsample%40%3a%3affff%3a127.0.0.1%3a14923-1 was not delivered. 1 dead letters encountered.
 INFO 09:44:27 [15]       Akka.Actor.LocalActorRef - Message Disassociated from NoSender to akka://sample/system/transports/akkaprotocolmanager.tcp.0/akkaProtocol-tcp%3a%2f%2fsample%40%3a%3affff%3a127.0.0.1%3a14923-1 was not delivered. 2 dead letters encountered.
ERROR 09:44:27 [ 6]   Akka.Actor.OneForOneStrategy - Shut down address: akka.tcp://sample@127.0.0.1:14922
Akka.Remote.ShutDownAssociation: Shut down address: akka.tcp://sample@127.0.0.1:14922 ---> Akka.Remote.Transport.InvalidAssociationException: The remote system terminated the association because it is shutting down.
   --- End of inner exception stack trace ---
   at Akka.Remote.EndpointWriter.PublishAndThrow(Exception reason, LogLevel level)
   at Akka.Remote.EndpointWriter.<SupervisorStrategy>b__20_0(Exception ex)
   at Akka.Actor.LocalOnlyDecider.Decide(Exception cause)
   at Akka.Actor.OneForOneStrategy.Handle(IActorRef child, Exception x)
   at Akka.Actor.SupervisorStrategy.HandleFailure(ActorCell actorCell, Exception cause, ChildRestartStats failedChildStats, IReadOnlyCollection`1 allChildren)
   at Akka.Actor.ActorCell.HandleFailed(Failed f)
   at Akka.Actor.ActorCell.SysMsgInvokeAll(EarliestFirstSystemMessageList messages, Int32 currentState)
--- End of stack trace from previous location where exception was thrown ---
   at Akka.Actor.ActorCell.HandleFailed(Failed f)
   at Akka.Actor.ActorCell.SysMsgInvokeAll(EarliestFirstSystemMessageList messages, Int32 currentState)
 INFO 09:44:27 [14]       Akka.Actor.LocalActorRef - Message DisassociateUnderlying from akka://sample/system/endpointManager/reliableEndpointWriter-akka.tcp%3a%2f%2fsample%40127.0.0.1%3a14922-1/endpointWriter to akka://sample/system/transports/akkaprotocolmanager.tcp.0/akkaProtocol-tcp%3a%2f%2fsample%40%3a%3affff%3a127.0.0.1%3a14923-1 was not delivered. 3 dead letters encountered.
 INFO 09:44:27 [14]       Akka.Actor.LocalActorRef - Message AckIdleCheckTimer from akka://sample/system/endpointManager/reliableEndpointWriter-akka.tcp%3a%2f%2fsample%40127.0.0.1%3a14922-1/endpointWriter to akka://sample/system/endpointManager/reliableEndpointWriter-akka.tcp%3a%2f%2fsample%40127.0.0.1%3a14922-1/endpointWriter was not delivered. 4 dead letters encountered.
 INFO 09:44:28 [28] vider+RemoteDeadLetterActorRef - Message GossipEnvelope from akka://sample/system/cluster/core/daemon to akka://sample/deadLetters was not delivered. 5 dead letters encountered.
 INFO 09:44:28 [11] vider+RemoteDeadLetterActorRef - Message Heartbeat from akka://sample/system/cluster/core/daemon/heartbeatSender to akka://sample/deadLetters was not delivered. 6 dead letters encountered.
 INFO 09:44:29 [14] vider+RemoteDeadLetterActorRef - Message GossipEnvelope from akka://sample/system/cluster/core/daemon to akka://sample/deadLetters was not delivered. 7 dead letters encountered.
 INFO 09:44:29 [ 6] vider+RemoteDeadLetterActorRef - Message Heartbeat from akka://sample/system/cluster/core/daemon/heartbeatSender to akka://sample/deadLetters was not delivered. 8 dead letters encountered.
 INFO 09:44:30 [15] vider+RemoteDeadLetterActorRef - Message GossipEnvelope from akka://sample/system/cluster/core/daemon to akka://sample/deadLetters was not delivered. 9 dead letters encountered.
 WARN 09:44:32 [28] Akka.Cluster.ClusterCoreDaemon - Marking exiting node(s) as UNREACHABLE [akka.tcp://sample@127.0.0.1:7001]. This is expected and they will be removed.
 INFO 09:44:32 [11] Akka.Cluster.ClusterCoreDaemon - Leader is removing exiting node [akka.tcp://sample@127.0.0.1:14922]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment