MultiDbClientBuilder.java

package redis.clients.jedis.builders;

import java.util.function.Consumer;

import redis.clients.jedis.MultiDbConfig;
import redis.clients.jedis.annots.Experimental;
import redis.clients.jedis.executors.CommandExecutor;
import redis.clients.jedis.mcf.MultiDbCommandExecutor;
import redis.clients.jedis.mcf.DatabaseSwitchEvent;
import redis.clients.jedis.mcf.MultiDbConnectionProvider;
import redis.clients.jedis.providers.ConnectionProvider;

/**
 * Builder for creating multi-db Redis clients with multi-endpoint support.
 * <p>
 * This builder provides methods specific to multi-db Redis deployments, including multiple weighted
 * endpoints, circuit breaker configuration, health checks, and automatic failover/failback
 * capabilities.
 * </p>
 * <p>
 * <strong>Key Features:</strong>
 * </p>
 * <ul>
 * <li><strong>Multi-Endpoint Configuration:</strong> Add multiple Redis endpoints with individual
 * weights</li>
 * <li><strong>Circuit Breaker Integration:</strong> Built-in circuit breaker with configurable
 * thresholds</li>
 * <li><strong>Health Monitoring:</strong> Automatic health checks with configurable strategies</li>
 * <li><strong>Event Handling:</strong> Listen to database switch events for monitoring and
 * alerting</li>
 * <li><strong>Flexible Configuration:</strong> Support for both simple and advanced multi-database
 * configurations</li>
 * </ul>
 * <p>
 * <strong>Usage Examples:</strong>
 * </p>
 *
 * <pre>
 * MultiDbClient client = MultiDbClient.builder()
 *                 .multiDbConfig(
 *                         MultiDbConfig.builder()
 *                                 .database(
 *                                         DatabaseConfig.builder(
 *                                                         east,
 *                                                         DefaultJedisClientConfig.builder().credentials(credentialsEast).build())
 *                                                 .weight(100.0f)
 *                                                 .build())
 *                                 .database(DatabaseConfig.builder(
 *                                                 west,
 *                                                 DefaultJedisClientConfig.builder().credentials(credentialsWest).build())
 *                                         .weight(50.0f).build())
 *                                 .failureDetector(MultiDbConfig.CircuitBreakerConfig.builder()
 *                                         .failureRateThreshold(50.0f)
 *                                         .build())
 *                                 .commandRetry(MultiDbConfig.RetryConfig.builder()
 *                                         .maxAttempts(3)
 *                                         .build())
 *                                 .build()
 *                 )
 *                 .databaseSwitchListener(event -&gt;
 *                     System.out.println("Switched to: " + event.getEndpoint()))
 *                 .build();
 * </pre>
 * 
 * @param <C> the client type that this builder creates
 * @author Ivo Gaydazhiev
 * @since 7.0.0
 */
@Experimental
public abstract class MultiDbClientBuilder<C>
    extends AbstractClientBuilder<MultiDbClientBuilder<C>, C> {

  // Multi-db specific configuration fields
  private MultiDbConfig multiDbConfig = null;
  private Consumer<DatabaseSwitchEvent> databaseSwitchListener = null;

  /**
   * Sets the multi-database configuration.
   * <p>
   * This configuration controls circuit breaker behavior, retry logic, health checks, failback
   * settings, and other resilience features. If not provided, default configuration will be used.
   * </p>
   * @param config the multi-database configuration
   * @return this builder
   */
  public MultiDbClientBuilder<C> multiDbConfig(MultiDbConfig config) {
    this.multiDbConfig = config;
    return this;
  }

  /**
   * Sets a listener for database switch events.
   * <p>
   * The listener will be called whenever the client switches from one endpoint to another,
   * providing information about the switch reason and the new active endpoint. This is useful for
   * monitoring, alerting, and logging purposes.
   * </p>
   * @param listener the database switch event listener
   * @return this builder
   */
  public MultiDbClientBuilder<C> databaseSwitchListener(Consumer<DatabaseSwitchEvent> listener) {
    this.databaseSwitchListener = listener;
    return this;
  }

  @Override
  protected MultiDbClientBuilder<C> self() {
    return this;
  }

  @Override
  protected ConnectionProvider createDefaultConnectionProvider() {

    if (this.multiDbConfig == null || this.multiDbConfig.getDatabaseConfigs() == null
        || this.multiDbConfig.getDatabaseConfigs().length < 1) {
      throw new IllegalArgumentException("At least one endpoint must be specified");
    }

    // Create the multi-database connection provider
    MultiDbConnectionProvider provider = new MultiDbConnectionProvider(multiDbConfig);

    // Set database switch listener if provided
    if (this.databaseSwitchListener != null) {
      provider.setDatabaseSwitchListener(this.databaseSwitchListener);
    }

    return provider;
  }

  @Override
  protected CommandExecutor createDefaultCommandExecutor() {
    // For multi-db clients, we always use MultiDbCommandExecutor
    return new MultiDbCommandExecutor((MultiDbConnectionProvider) this.connectionProvider);
  }

  @Override
  protected void validateSpecificConfiguration() {

  }

}