static void EnsureClusterConfiguration(IDocumentStore store) { using (var s = store.OpenSession()) { var getTopologyCmd = new GetClusterTopologyCommand(); s.Advanced.RequestExecutor.Execute(getTopologyCmd, s.Advanced.Context); var topology = getTopologyCmd.Result.Topology; // Currently do not support clusters with more than one possible primary member. Watchers (passive replication targets) are OK. if (topology.Members.Count != 1) { throw new InvalidOperationException("RavenDB Persistence does not support RavenDB clusters with more than one Leader/Member node. Only clusters with a single Leader and (optionally) Watcher nodes are supported."); } } }
static void EnsureClusterConfiguration(IDocumentStore store) { using (var s = store.OpenSession()) { var getTopologyCmd = new GetClusterTopologyCommand(); s.Advanced.RequestExecutor.Execute(getTopologyCmd, s.Advanced.Context); var topology = getTopologyCmd.Result.Topology; // Currently do not support clusters. if (topology.AllNodes.Count != 1) { throw new InvalidOperationException("RavenDB Persistence does not support RavenDB clusters with multiple nodes. Only a single-node configuration is supported."); } } }
protected async Task <List <ProcessNode> > CreateCluster(string[] peers, IDictionary <string, string> customSettings = null, X509Certificate2 certificate = null) { var processes = new List <ProcessNode>(); foreach (var peer in peers) { processes.Add(await GetServerAsync(peer)); } var chosenOne = processes[0]; using (var requestExecutor = ClusterRequestExecutor.CreateForSingleNode(chosenOne.Url, certificate)) using (requestExecutor.ContextPool.AllocateOperationContext(out JsonOperationContext context)) { foreach (var processNode in processes) { if (processNode == chosenOne) { continue; } var addCommand = new AddClusterNodeCommand(processNode.Url); await requestExecutor.ExecuteAsync(addCommand, context); } var clusterCreated = await WaitForValueAsync(async() => { var clusterTopology = new GetClusterTopologyCommand(); await requestExecutor.ExecuteAsync(clusterTopology, context); return(clusterTopology.Result.Topology.Members.Count); }, peers.Length); Assert.True(clusterCreated == peers.Length, "Failed to create initial cluster"); } return(processes); }
public override async Task <bool> UpdateTopologyAsync(ServerNode node, int timeout, bool forceUpdate = false) { if (Disposed) { return(false); } var lockTaken = await _clusterTopologySemaphore.WaitAsync(timeout).ConfigureAwait(false); if (lockTaken == false) { return(false); } try { if (Disposed) { return(false); } using (ContextPool.AllocateOperationContext(out JsonOperationContext context)) { var command = new GetClusterTopologyCommand(); await ExecuteAsync(node, null, context, command, shouldRetry : false).ConfigureAwait(false); var serverHash = ServerHash.GetServerHash(node.Url); ClusterTopologyLocalCache.TrySavingTopologyToLocalCache(serverHash, command.Result, context); var results = command.Result; var newTopology = new Topology { Nodes = new List <ServerNode>( from member in results.Topology.Members select new ServerNode { Url = member.Value, ClusterTag = member.Key } ) }; if (_nodeSelector == null) { _nodeSelector = new NodeSelector(newTopology); if (_readBalanceBehavior == ReadBalanceBehavior.FastestNode) { _nodeSelector.ScheduleSpeedTest(); } } else if (_nodeSelector.OnUpdateTopology(newTopology, forceUpdate: forceUpdate)) { DisposeAllFailedNodesTimers(); if (_readBalanceBehavior == ReadBalanceBehavior.FastestNode) { _nodeSelector.ScheduleSpeedTest(); } } OnTopologyUpdated(newTopology); } } finally { _clusterTopologySemaphore.Release(); } return(true); }
public override async Task <bool> UpdateTopologyAsync(UpdateTopologyParameters parameters) { if (parameters is null) { throw new ArgumentNullException(nameof(parameters)); } if (Disposed) { return(false); } var lockTaken = await _clusterTopologySemaphore.WaitAsync(parameters.TimeoutInMs).ConfigureAwait(false); if (lockTaken == false) { return(false); } try { if (Disposed) { return(false); } using (ContextPool.AllocateOperationContext(out JsonOperationContext context)) { var command = new GetClusterTopologyCommand(parameters.DebugTag); await ExecuteAsync(parameters.Node, null, context, command, shouldRetry : false, sessionInfo : null, token : CancellationToken.None).ConfigureAwait(false); ClusterTopologyLocalCache.TrySaving(TopologyHash, command.Result, Conventions, context); var results = command.Result; var newTopology = new Topology { Nodes = new List <ServerNode>( from member in results.Topology.Members select new ServerNode { Url = member.Value, ClusterTag = member.Key } ), Etag = results.Etag }; TopologyEtag = results.Etag; if (_nodeSelector == null) { _nodeSelector = new NodeSelector(newTopology); if (Conventions.ReadBalanceBehavior == ReadBalanceBehavior.FastestNode) { _nodeSelector.ScheduleSpeedTest(); } } else if (_nodeSelector.OnUpdateTopology(newTopology, forceUpdate: parameters.ForceUpdate)) { DisposeAllFailedNodesTimers(); if (Conventions.ReadBalanceBehavior == ReadBalanceBehavior.FastestNode) { _nodeSelector.ScheduleSpeedTest(); } } OnTopologyUpdatedInvoke(newTopology); } } catch (Exception) { if (Disposed == false) { throw; } } finally { _clusterTopologySemaphore.Release(); } return(true); }
public async Task Initiate_Embedded_Replication() { #region Embedded_OpenStudio //this starts the embedded server EmbeddedServer.Instance.StartServer(new ServerOptions { ServerUrl = "http://localhost:8090" //if we don't specify a port, it will have random port }); //this opens Embedded RavenDB Studio in the default browser EmbeddedServer.Instance.OpenStudioInBrowser(); #endregion #region Embedded_Replication_Setup //first, initialize connection with one of cluster nodes var ravenClusterNodeUrl = "http://localhost:8080"; using (var store = new DocumentStore { Urls = new[] { ravenClusterNodeUrl }, Database = "Northwind" }) { store.Initialize(); //first, start the embedded server //note: by default the embedded server will use a random port. // if there is a need to replicate TO the embedded server, we would need to specify the port directly EmbeddedServer.Instance.StartServer(new ServerOptions { ServerUrl = "http://localhost:8090" }); //then, add embedded instance to existing cluster //(programmatically, this is done via REST) var embeddedServerUrl = (await EmbeddedServer.Instance.GetServerUriAsync().ConfigureAwait(false)).ToString(); var addToClusterCommandUrl = $"{ravenClusterNodeUrl}/admin/cluster/node?url={embeddedServerUrl}"; await store.GetRequestExecutor() .HttpClient .SendAsync( new HttpRequestMessage( HttpMethod.Put, addToClusterCommandUrl)).ConfigureAwait(false); var getTopologyCommand = new GetClusterTopologyCommand(); var embeddedStore = EmbeddedServer.Instance.GetDocumentStore("Northwind"); string embeddedTag; using (var session = embeddedStore.OpenSession()) { //fetch topology info from embedded, so we can fetch the tag assigned by the cluster await embeddedStore.GetRequestExecutor() .ExecuteAsync(getTopologyCommand, session.Advanced.Context) .ConfigureAwait(false); embeddedTag = getTopologyCommand.Result.Topology.LastNodeId; } //this sends the command to add the database "Northwind" to its database group await store.Maintenance .Server .SendAsync( new AddDatabaseNodeOperation(databaseName : "Northwind", node : embeddedTag)) .ConfigureAwait(false); } #endregion }