public void Follower_as_a_single_node_becomes_leader_automatically() { var hub = new InMemoryTransportHub(); var storageEnvironmentOptions = StorageEnvironmentOptions.CreateMemoryOnly(); storageEnvironmentOptions.OwnsPagers = false; var raftEngineOptions = new RaftEngineOptions( new NodeConnectionInfo { Name = "node1" }, storageEnvironmentOptions, hub.CreateTransportFor("node1"), new DictionaryStateMachine() ) { ElectionTimeout = 1000, HeartbeatTimeout = 1000 / 6 }; PersistentState.ClusterBootstrap(raftEngineOptions); storageEnvironmentOptions.OwnsPagers = true; using (var raftNode = new RaftEngine(raftEngineOptions)) { Assert.Equal(RaftEngineState.Leader, raftNode.State); } }
private static void Main(string[] args) { var options = new TailFeatherCommandLineOptions(); if (Parser.Default.ParseArguments(args, options) == false) { var autoBuild = HelpText.AutoBuild(options); HelpText.DefaultParsingErrorsHandler(options, autoBuild); Console.WriteLine(autoBuild.ToString()); return; } var nodeName = options.NodeName ?? (Environment.MachineName + ":" + options.Port); Console.Title = string.Format("Node name: {0}, port: {1}", nodeName, options.Port); var kvso = StorageEnvironmentOptions.ForPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, options.DataPath, "KeyValue")); using (var statemachine = new KeyValueStateMachine(kvso)) { var storageEnvironmentOptions = StorageEnvironmentOptions.ForPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, options.DataPath, "Raft")); var httpTransport = new HttpTransport(nodeName); var raftEngineOptions = new RaftEngineOptions( new NodeConnectionInfo { Name = nodeName, Uri = new Uri("http://" + Environment.MachineName + ":" + options.Port), }, storageEnvironmentOptions, httpTransport, statemachine ) { ElectionTimeout = 5 * 1000, HeartbeatTimeout = 1000, MaxLogLengthBeforeCompaction = 25 }; if (options.Boostrap) { PersistentState.ClusterBootstrap(raftEngineOptions); Console.WriteLine("Setup node as the cluster seed, exiting..."); return; } using (var raftEngine = new RaftEngine(raftEngineOptions)) { using (WebApp.Start(new StartOptions { Urls = { "http://+:" + options.Port + "/" } }, builder => { var httpConfiguration = new HttpConfiguration(); httpConfiguration.Formatters.Remove(httpConfiguration.Formatters.XmlFormatter); httpConfiguration.Formatters.JsonFormatter.SerializerSettings.Formatting = Newtonsoft.Json.Formatting.Indented; httpConfiguration.Formatters.JsonFormatter.SerializerSettings.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter()); RaftWebApiConfig.Load(); httpConfiguration.MapHttpAttributeRoutes(); httpConfiguration.Properties[typeof(HttpTransportBus)] = httpTransport.Bus; httpConfiguration.Properties[typeof(RaftEngine)] = raftEngine; builder.UseWebApi(httpConfiguration); })) { Console.WriteLine("Ready @ http://" + Environment.MachineName + ":" + options.Port + "/, press ENTER to stop"); Console.ReadLine(); } } } }
protected RaftEngine CreateNetworkAndGetLeader(int nodeCount, int messageTimeout = -1) { var leaderIndex = new Random().Next(0, nodeCount); if (messageTimeout == -1) { messageTimeout = Debugger.IsAttached ? 3 * 1000 : 500; } var nodeNames = new string[nodeCount]; for (int i = 0; i < nodeCount; i++) { nodeNames[i] = "node" + i; } WriteLine("{0} selected as seed", nodeNames[leaderIndex]); var allNodesFinishedJoining = new ManualResetEventSlim(); for (int index = 0; index < nodeNames.Length; index++) { var nodeName = nodeNames[index]; var storageEnvironmentOptions = StorageEnvironmentOptions.CreateMemoryOnly(); storageEnvironmentOptions.OwnsPagers = false; var options = CreateNodeOptions(nodeName, messageTimeout, storageEnvironmentOptions, nodeNames); if (leaderIndex == index) { PersistentState.ClusterBootstrap(options); } storageEnvironmentOptions.OwnsPagers = true; var engine = new RaftEngine(options); _nodes.Add(engine); if (leaderIndex == index) { engine.TopologyChanged += command => { if (command.Requested.AllNodeNames.All(command.Requested.IsVoter)) { allNodesFinishedJoining.Set(); } }; for (int i = 0; i < nodeNames.Length; i++) { if (i == leaderIndex) { continue; } Assert.True(engine.AddToClusterAsync(new NodeConnectionInfo { Name = nodeNames[i] }).Wait(3000)); } } } if (nodeCount == 1) { allNodesFinishedJoining.Set(); } Assert.True(allNodesFinishedJoining.Wait(5000 * nodeCount)); var raftEngine = _nodes[leaderIndex]; var transport = (InMemoryTransportHub.InMemoryTransport)_inMemoryTransportHub.CreateTransportFor(raftEngine.Name); transport.ForceTimeout(); Assert.True(_nodes[leaderIndex].WaitForLeader()); var leader = _nodes.FirstOrDefault(x => x.State == RaftEngineState.Leader); Assert.NotNull(leader); return(_nodes[leaderIndex]); }