Replication: Using Embedded Instance

Overview

Replication works by using long-living TCP connections between cluster nodes, or in case of External Replication instances external to the cluster. Essentially, Embedded RavenDB is the same as non-embedded, their only difference is what process is a host. Here you can read more in-depth about Embedded RavenDB functionality.

Configuring Replication between Embedded Instance and a Cluster

Configuring Cluster Membership of Embedded Instance through the Studio

One possibility would be to configure it through the studio, by adding the Embedded instance to the cluster, then adding the database replicated to relevant database group.
Studio of the Embedded instance can be opened in the following way:

//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();

Programmatically Configuring Cluster Membership of Embedded Instance

Another possibility would be to configure it programmatically.

//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);
}

Configuring Embedded Instance as External Replication Destination through the Studio

Another possibility to configure the embedded instance as an external replication source or a destination.
This can be done in RavenDB Studio. {NOTE: External Replication is configured only one way, so in order to create two-way external replication, we would need to configure External Replication Tasks at both RavenDB instances. /}

Programmatically Embedded Instance as External Replication Destination

It is also possible to configure external replication programmatically, so the embedded instance can serve as a source, destination or both.

//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
    EmbeddedServer.Instance.StartServer(new ServerOptions
    {
        ServerUrl = "http://localhost:8090",
        AcceptEula = true
    });

    var embeddedServerUrl =
        (await EmbeddedServer.Instance.GetServerUriAsync().ConfigureAwait(false)).ToString();

    // create watcher definition that will be added to existing cluster
    var externalReplicationWatcher = new ExternalReplication(
        database: "Northwind",
        connectionStringName: "Embedded Northwind Instance");

    //create the connection string for the embedded instance on the existing cluster
    await store.Maintenance.SendAsync(
        new PutConnectionStringOperation<RavenConnectionString>(new RavenConnectionString
        {
            Name = externalReplicationWatcher.ConnectionStringName,
            Database = externalReplicationWatcher.Database,
            TopologyDiscoveryUrls = new[] {embeddedServerUrl} //urls to discover topology at destination
        })).ConfigureAwait(false);

    //create External Replication task from the cluster to the embedded RavenDB instance
    await store.Maintenance.SendAsync(new UpdateExternalReplicationOperation(externalReplicationWatcher))
        .ConfigureAwait(false);
}