> ## Documentation Index
> Fetch the complete documentation index at: https://docs.activeviam.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Distributed Architecture Guide

## Use the Atoti Starter

In a Spring application, the different components used in distribution like the messenger will be automatically created by Atoti starter for Spring Boot `com.activeviam.springboot:atoti-server-starter`. Import this dependency in your project to perform this injection.<br />
In the context of tests, Atoti comes with the class `com.activeviam.atoti.server.test.api.DistributionTestHelper` handling this setup. See [the specific section](../copper/copper_advanced#using-the-testing-framework) for details about its setup and usage.

## Configure your application

The first step to define an application is to define a database. This is done like in a non-distributed application (see [Database Overview](../database/database_overview))

The second step is to define the data nodes and the query nodes.
Here as an example of a data node definition:

```java theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
final IActivePivotInstanceDescription datanode =
    StartBuilding.cube("datanode")
        .withSingleLevelDimension("trade")
        // define here the measures and the hierarchies of the data node
        .asDataCube()
        .withClusterDefinition()
        .withClusterId("Cluster")
        .withMessengerDefinition()
        .withProtocolPath("jgroups-protocols/protocol-tcp.xml")
        .end()
        .withApplicationId("app")
        .withConcealedHierarchies(List.of(HierarchyIdentifier.simple("trade")))
        .withConcealedMeasures("Value.SUM")
        .withConcealedBranches()
        .end()
        .build();
```

The cluster can define its messenger with a protocol path or simply call the `withLocalMessenger` or the `withNettyMessenger` methods.
This is the moment to conceal the hierarchies, the measures or the branches if it applies here (see [Recommendations](./distributed_recommendations))

And of a query node definition:

```java theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
final IDistributedActivePivotInstanceDescription queryNode =
    StartBuilding.cube("querynode")
        .asQueryCube()
        .withClusterDefinition()
        .withClusterId("Cluster")
        .withMessengerDefinition()
        .withProtocolPath("jgroups-protocols/protocol-tcp.xml")
        .end()
        .withApplication("app")
        .withDistributingLevels(LevelIdentifier.simple("trader"))
        .withApplication("app2")
        .withoutDistributingLevels()
        .end()
        .build();
```

The query node will see all the data nodes belonging to the applications listed in its configurations.

Once the nodes have been defined, they should be added to a manager:

```java theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
final IActivePivotManagerDescription manager =
    StartBuilding.managerDescription("MyManager")
        .withCatalog("Catalog")
        .containingAllCubes()
        .withSchema("Schema")
        .withSelection(createSelection())
        .withCube(datanode)
        .withDistributedCube(queryNode)
        .build();
```

The last step is to put the database and the manager together in an application:

```java theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
final ApplicationWithDatastore application =
    StartBuilding.application()
        .withDatastore(createDatastoreSchemaDescription())
        .withManager(manager)
        .build();
```

## Join/Leave a cluster

It is possible to join and leave the cluster programmatically like this:

```java theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
// Join the cluster
((IMultiVersionDataActivePivot) multiVersionActivePivot).startDistribution();
// Leave the cluster
((IMultiVersionDataActivePivot) multiVersionActivePivot).stopDistribution();
```

If a data node leaves the cluster before sending all the expected query results to a query node, a `ServiceUnavailableException` is thrown.
