> ## 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.

# How to set up distributed mode

> Guide for configuring Atoti What-If in a distributed deployment.

This page explains how to configure Atoti What-If for distributed deployments where data is spread across multiple nodes.

## What is distributed mode

In a distributed Atoti Server deployment, data is partitioned across multiple data nodes, with a query node coordinating requests. Atoti What-If supports this architecture by sending simulation operations to all data nodes via REST calls.

When distributed mode is enabled, the starter creates a `RestDistributedDatabaseService` that:

* Discovers data node addresses from the distributed pivot
* Forwards database operations to all nodes
* Merges query results from multiple nodes
* Handles authentication using JWT tokens

## Prerequisites

Before enabling distributed mode:

* Your Atoti Server application must be configured for distribution
* A query node with `IMultiVersionDistributedActivePivot` must be available
* JWT authentication must be configured
* Data nodes must expose the Database Service REST API

## How to enable distributed mode

Add the following properties to your `application.yml`:

```yaml theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
atoti:
  what-if:
    distribution:
      enabled: true
      query-node-name: "MyQueryNode"
```

The `query-node-name` must match the name of your query node pivot as configured in your Atoti Server application.

## Auto-configured beans

When `distribution.enabled: true`, the starter creates:

| Bean                             | Description                                             |
| -------------------------------- | ------------------------------------------------------- |
| `IDistributedQueryResultsMerger` | Merges results from multiple data nodes                 |
| `AddressSupplier`                | Supplies data node addresses from the distributed pivot |
| `AuthenticatorSupplier`          | Supplies JWT authenticators for REST calls              |
| `RestDistributedDatabaseService` | The distributed database service (marked as `@Primary`) |

## Configuration properties

| Property                                                | Type    | Default | Description                                             |
| ------------------------------------------------------- | ------- | ------- | ------------------------------------------------------- |
| `atoti.what-if.distribution.enabled`                    | boolean | `false` | Enables distributed mode                                |
| `atoti.what-if.distribution.query-node-name`            | String  | `""`    | Name of the query node pivot                            |
| `atoti.what-if.distribution.create-distributed-service` | boolean | `true`  | Whether to auto-create `RestDistributedDatabaseService` |

## How to provide a custom address supplier

By default, the starter discovers data node addresses from the distributed pivot. To use a custom address supplier:

```java theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
@Bean
public AddressSupplier customAddressSupplier() {
    return () -> Set.of(
        "http://data-node-1:8080/",
        "http://data-node-2:8080/",
        "http://data-node-3:8080/"
    );
}
```

## How to provide a custom authenticator

By default, JWT authentication is used. To provide a custom authenticator:

```java theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
@Bean
public AuthenticatorSupplier customAuthenticatorSupplier() {
    return () -> new MyCustomAuthenticator();
}
```

## How to provide a custom distributed database service

To replace the auto-configured `RestDistributedDatabaseService`:

1. Set `create-distributed-service: false` in your configuration:

```yaml theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
atoti:
  what-if:
    distribution:
      enabled: true
      query-node-name: "MyQueryNode"
      create-distributed-service: false
```

2. Define your custom bean:

```java theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
@Bean
@Primary
public IDatabaseService customDistributedDatabaseService(
        IDistributedQueryResultsMerger resultsMerger,
        AddressSupplier addressSupplier,
        AuthenticatorSupplier authenticatorSupplier) {
    return new MyCustomDistributedDatabaseService(
            resultsMerger, addressSupplier, authenticatorSupplier);
}
```

## How to customize result merging

The `DefaultDistributedQueryResultsMerger` combines query results from all data nodes. To customize merging logic:

```java theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
@Bean
public IDistributedQueryResultsMerger customResultsMerger() {
    return new IDistributedQueryResultsMerger() {
        @Override
        public JsonDatabaseQueryResult mergeQueryResults(
                List<JsonDatabaseQueryResult> results) {
            // Custom merge logic
        }
        // Implement other methods as needed
    };
}
```

## Error handling

The `RestDistributedDatabaseService` throws:

* `ActiveViamRuntimeException` if no data node addresses are available
* `InternalServiceException` if operations on distributed nodes fail

Ensure your error handling accounts for partial failures when some nodes are unreachable.
