datasquirel/package-shared/functions/dsql/sync-databases/index.ts
Benjamin Toby 7e8bb37c09 Updates
2025-07-05 14:59:30 +01:00

118 lines
3.6 KiB
TypeScript

import mysql, { Connection } from "mysql";
import { exec } from "child_process";
import { promisify } from "util";
// Configuration interface
interface DatabaseConfig {
host: string;
user: string;
password: string;
database?: string; // Optional for global connection
}
// Master status interface
interface MasterStatus {
File: string;
Position: number;
Binlog_Do_DB?: string;
Binlog_Ignore_DB?: string;
}
function getConnection(config: DatabaseConfig): Connection {
return mysql.createConnection(config);
}
function getMasterStatus(config: DatabaseConfig): Promise<MasterStatus> {
return new Promise((resolve, reject) => {
const connection = getConnection(config);
connection.query("SHOW MASTER STATUS", (error, results) => {
connection.end();
if (error) reject(error);
else resolve(results[0] as MasterStatus);
});
});
}
async function syncDatabases() {
const config: DatabaseConfig = {
host: "localhost",
user: "root",
password: "your_password",
};
let lastPosition: number | null = null; // Track last synced position
while (true) {
try {
// Get current master status
const { File, Position } = await getMasterStatus(config);
// Determine start position (use lastPosition or 4 if first run)
const startPosition = lastPosition !== null ? lastPosition + 1 : 4;
if (startPosition >= Position) {
await new Promise((resolve) => setTimeout(resolve, 5000)); // Wait 5 seconds if no new changes
continue;
}
// Execute mysqlbinlog to get changes
const execPromise = promisify(exec);
const { stdout } = await execPromise(
`mysqlbinlog --database=db_master ${File} --start-position=${startPosition} --stop-position=${Position}`
);
if (stdout) {
const connection = getConnection({
...config,
database: "db_slave",
});
return new Promise((resolve, reject) => {
connection.query(stdout, (error) => {
connection.end();
if (error) reject(error);
else {
lastPosition = Position;
console.log(
`Synced up to position ${Position} at ${new Date().toISOString()}`
);
resolve(null);
}
});
});
}
} catch (error) {
console.error("Sync error:", error);
}
await new Promise((resolve) => setTimeout(resolve, 5000)); // Check every 5 seconds
}
}
// Initialize db_slave with db_master data
async function initializeSlave() {
const config: DatabaseConfig = {
host: "localhost",
user: "root",
password: "your_password",
};
try {
await promisify(exec)(
`mysqldump -u ${config.user} -p${config.password} db_master > db_master_backup.sql`
);
await promisify(exec)(
`mysql -u ${config.user} -p${config.password} db_slave < db_master_backup.sql`
);
console.log("Slave initialized with master data");
} catch (error) {
console.error("Initialization error:", error);
}
}
// Run the sync process
async function main() {
await initializeSlave();
await syncDatabases();
}
main().catch(console.error);