Fast MariaDB and MySQL connector for Node.js with Promise and callback APIs
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
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.
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();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;
}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>;
}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;
}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 nodeAdd, 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 nodeRoute 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");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 nodesConfigure 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
});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 });
});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
}
}