CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-mariadb

Fast MariaDB and MySQL connector for Node.js with Promise and callback APIs

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

clustering.mddocs/

Pool Clustering

Pool clustering functionality for load balancing across multiple database pools and high availability scenarios. Pool clusters provide node management, automatic failover, and flexible connection routing for distributed database architectures.

Capabilities

Create Pool Cluster

Creates a new pool cluster for managing multiple database pools.

/**
 * Create a new pool cluster
 * @param config - Optional cluster configuration
 * @returns PoolCluster instance
 */
function createPoolCluster(config?: PoolClusterConfig): PoolCluster;

Usage Example:

import mariadb from "mariadb";

const cluster = mariadb.createPoolCluster({
  canRetry: true,
  removeNodeErrorCount: 5,
  restoreNodeTimeout: 2000,
  defaultSelector: 'RR'
});

// Add database nodes
cluster.add('master', {
  host: 'master.db.example.com',
  user: 'root',
  password: 'password',
  database: 'app'
});

cluster.add('slave1', {
  host: 'slave1.db.example.com',
  user: 'readonly',
  password: 'password',
  database: 'app'
});

cluster.add('slave2', {
  host: 'slave2.db.example.com',
  user: 'readonly', 
  password: 'password',
  database: 'app'
});

// Get connection from cluster (automatic load balancing)
const connection = await cluster.getConnection();
const rows = await connection.query("SELECT * FROM users");
await connection.release();

// Target specific node pattern
const masterConn = await cluster.getConnection('master');
await masterConn.query("INSERT INTO logs (message) VALUES (?)", ["New entry"]);
await masterConn.release();

// Use filtered cluster for read operations
const slaves = cluster.of('slave*', 'RANDOM');
const readConn = await slaves.getConnection();
const data = await readConn.query("SELECT * FROM reports");
await readConn.release();

PoolCluster Interface (Promise-based)

Main cluster interface for managing multiple database pools.

interface PoolCluster extends EventEmitter {
  /** Add pool node to cluster */
  add(id: string, config: PoolConfig): void;
  
  /** Remove pool nodes matching pattern */
  remove(pattern: string): void;
  
  /** Close all pools in cluster */
  end(): Promise<void>;
  
  /** Create filtered cluster view */
  of(pattern?: string, selector?: string): FilteredPoolCluster;
  of(pattern: undefined | null | false, selector: string): FilteredPoolCluster;
  
  /** Get connection from cluster with optional routing */
  getConnection(pattern?: string, selector?: string): Promise<PoolConnection>;
  
  /** Cluster event listeners */
  on(event: 'remove', listener: (nodeKey: string) => void): PoolCluster;
}

FilteredPoolCluster Interface

Filtered view of cluster nodes for targeted operations.

interface FilteredPoolCluster {
  /** Get connection from filtered nodes */
  getConnection(): Promise<PoolConnection>;
  
  /** Execute query on filtered cluster */
  query<T = any>(sql: string | QueryOptions, values?: any): Promise<T>;
  
  /** Execute prepared statement on filtered cluster */
  execute<T = any>(sql: string | QueryOptions, values?: any): Promise<T>;
  
  /** Execute batch operations on filtered cluster */
  batch<T = UpsertResult | UpsertResult[]>(sql: string | QueryOptions, values?: any): Promise<T>;
}

PoolCluster Interface (Callback-based)

Alternative callback-based cluster interface.

interface PoolCluster extends EventEmitter {
  /** Add and remove methods remain synchronous */
  add(id: string, config: PoolConfig): void;
  remove(pattern: string): void;
  
  /** Callback-based methods */
  end(callback: (err: SqlError | null) => void): void;
  getConnection(pattern: string | undefined | null, selector: string | undefined | null, callback: (err: SqlError | null, conn?: PoolConnection) => void): void;
  getConnection(pattern: string | undefined | null, callback: (err: SqlError | null, conn?: PoolConnection) => void): void;
  getConnection(callback: (err: SqlError | null, conn?: PoolConnection) => void): void;
  
  /** Filtered cluster creation remains synchronous */
  of(pattern: string, selector?: string): FilteredPoolCluster;
  of(pattern: undefined | null | false, selector: string): FilteredPoolCluster;
  
  on(event: 'remove', listener: (nodeKey: string) => void): PoolCluster;
}

Cluster Configuration

Configuration options for cluster behavior and node management.

interface PoolClusterConfig {
  /** Enable connection retry on failure (default: true) */
  canRetry?: boolean;
  
  /** Error count before removing node (default: Infinity) */
  removeNodeErrorCount?: number;
  
  /** Milliseconds before attempting node restoration (default: 1000) */
  restoreNodeTimeout?: number;
  
  /** Default load balancing selector (default: 'RR') */
  defaultSelector?: string;
}

Selector Options:

  • 'RR': Round-Robin - Rotate through nodes sequentially
  • 'RANDOM': Random selection from available nodes
  • 'ORDER': Always select first available node

Node Management

Add, remove, and manage database nodes in the cluster.

// Add nodes with different roles
cluster.add('master', {
  host: 'master.db.com',
  user: 'admin',
  password: 'secret',
  database: 'app',
  connectionLimit: 20
});

cluster.add('replica-us-east', {
  host: 'replica-east.db.com', 
  user: 'readonly',
  password: 'secret',
  database: 'app',
  connectionLimit: 10
});

cluster.add('replica-us-west', {
  host: 'replica-west.db.com',
  user: 'readonly', 
  password: 'secret',
  database: 'app',
  connectionLimit: 10
});

// Remove nodes by pattern
cluster.remove('replica-*'); // Remove all replica nodes
cluster.remove('master');    // Remove master node

Connection Routing

Route connections to specific nodes or groups using patterns and selectors.

// Get connection from any node (default selector)
const anyConn = await cluster.getConnection();

// Get connection from specific node
const masterConn = await cluster.getConnection('master');

// Get connection using specific selector
const randomConn = await cluster.getConnection('replica-*', 'RANDOM');

// Use filtered clusters for targeted operations
const writeCluster = cluster.of('master');
const readCluster = cluster.of('replica-*', 'RR');

// Execute operations on different clusters
await writeCluster.query("INSERT INTO users (name) VALUES (?)", ["Alice"]);
const users = await readCluster.query("SELECT * FROM users");

Pattern Matching

Use glob-style patterns to match node groups.

// Add nodes with hierarchical naming
cluster.add('prod-master-01', config1);
cluster.add('prod-replica-us-east-01', config2);
cluster.add('prod-replica-us-east-02', config3);
cluster.add('prod-replica-us-west-01', config4);
cluster.add('test-master-01', config5);

// Pattern examples
const prodNodes = cluster.of('prod-*');           // All production nodes
const replicas = cluster.of('*-replica-*');       // All replica nodes
const eastReplicas = cluster.of('*-us-east-*');   // East coast replicas
const testEnv = cluster.of('test-*');             // Test environment nodes

High Availability Configuration

Configure automatic failover and node recovery for high availability.

const cluster = mariadb.createPoolCluster({
  canRetry: true,              // Enable retry on connection failure
  removeNodeErrorCount: 3,     // Remove node after 3 consecutive errors
  restoreNodeTimeout: 5000,    // Try to restore failed nodes after 5 seconds
  defaultSelector: 'RR'        // Round-robin load balancing
});

// Configure pools with health checking
cluster.add('primary', {
  host: 'primary.db.com',
  user: 'app',
  password: 'secret',
  database: 'production',
  acquireTimeout: 3000,        // Fail fast on connection issues
  idleTimeout: 300,            // Keep connections fresh
  connectionLimit: 15
});

cluster.add('secondary', {
  host: 'secondary.db.com',
  user: 'app', 
  password: 'secret',
  database: 'production',
  acquireTimeout: 3000,
  idleTimeout: 300,
  connectionLimit: 10
});

Cluster Events

Monitor cluster health and node status with event listeners.

// Node removed from cluster due to errors
cluster.on('remove', (nodeKey: string) => {
  console.log(`Node removed from cluster: ${nodeKey}`);
  
  // Alert monitoring system
  alerting.send(`Database node ${nodeKey} has been removed from cluster`);
  
  // Update application metrics
  metrics.increment('cluster.node.removed', { node: nodeKey });
});

Best Practices

Read/Write Splitting:

const cluster = mariadb.createPoolCluster();

cluster.add('master', {
  host: 'master.db.com',
  user: 'app_write',
  password: 'secret',
  database: 'app'
});

cluster.add('slave1', {
  host: 'slave1.db.com', 
  user: 'app_read',
  password: 'secret',
  database: 'app'
});

cluster.add('slave2', {
  host: 'slave2.db.com',
  user: 'app_read', 
  password: 'secret',
  database: 'app'
});

// Create specialized clusters
const writeCluster = cluster.of('master');
const readCluster = cluster.of('slave*', 'RANDOM');

// Use appropriate cluster for operations
async function createUser(userData: UserData) {
  const conn = await writeCluster.getConnection();
  try {
    const result = await conn.query(
      "INSERT INTO users (name, email) VALUES (?, ?)",
      [userData.name, userData.email]
    );
    return result.insertId;
  } finally {
    await conn.release();
  }
}

async function getUsers() {
  const conn = await readCluster.getConnection();
  try {
    return await conn.query("SELECT * FROM users");
  } finally {
    await conn.release();
  }
}

Geographic Distribution:

const cluster = mariadb.createPoolCluster({
  defaultSelector: 'RR'
});

// Add geographically distributed nodes
cluster.add('us-east-1', {
  host: 'db-east-1.us.example.com',
  // ... config
});

cluster.add('us-west-1', {
  host: 'db-west-1.us.example.com', 
  // ... config
});

cluster.add('eu-central-1', {
  host: 'db-central-1.eu.example.com',
  // ... config
});

// Route based on user location
function getClusterForRegion(region: string) {
  switch (region) {
    case 'us-east':
      return cluster.of('us-east-*');
    case 'us-west':
      return cluster.of('us-west-*');
    case 'europe':
      return cluster.of('eu-*');
    default:
      return cluster; // Use default balancing
  }
}

docs

callbacks.md

clustering.md

configuration.md

connections.md

errors.md

index.md

pooling.md

queries.md

types.md

tile.json