Flushing fixes
gitea/mylogger/pipeline/head There was a failure building this commit
Details
gitea/mylogger/pipeline/head There was a failure building this commit
Details
This commit is contained in:
parent
e57ccf6e41
commit
ce14583a71
|
@ -6,7 +6,7 @@ pipeline {
|
||||||
disableConcurrentBuilds()
|
disableConcurrentBuilds()
|
||||||
}
|
}
|
||||||
environment {
|
environment {
|
||||||
PROJECT_NAME = 'mycdc'
|
PROJECT_NAME = 'mylogger'
|
||||||
STACK_NAME = "${env.PROJECT_NAME}-${env.BRANCH_NAME}"
|
STACK_NAME = "${env.PROJECT_NAME}-${env.BRANCH_NAME}"
|
||||||
}
|
}
|
||||||
stages {
|
stages {
|
||||||
|
@ -17,7 +17,7 @@ pipeline {
|
||||||
env.VERSION = packageJson.version
|
env.VERSION = packageJson.version
|
||||||
}
|
}
|
||||||
configFileProvider([
|
configFileProvider([
|
||||||
configFile(fileId: "mycdc.groovy",
|
configFile(fileId: "mylogger.groovy",
|
||||||
variable: 'GROOVY_FILE')
|
variable: 'GROOVY_FILE')
|
||||||
]) {
|
]) {
|
||||||
load env.GROOVY_FILE
|
load env.GROOVY_FILE
|
||||||
|
|
|
@ -1,14 +1,17 @@
|
||||||
debug: true
|
debug: true
|
||||||
testMode: false
|
testMode: false
|
||||||
db:
|
srcDb:
|
||||||
|
host: localhost
|
||||||
|
port: 3306
|
||||||
|
user: root
|
||||||
|
password: root
|
||||||
|
database: vn
|
||||||
|
dstDb:
|
||||||
host: localhost
|
host: localhost
|
||||||
port: 3306
|
port: 3306
|
||||||
user: root
|
user: root
|
||||||
password: root
|
password: root
|
||||||
database: vn
|
database: vn
|
||||||
showField:
|
|
||||||
- name
|
|
||||||
description
|
|
||||||
logs:
|
logs:
|
||||||
ticket:
|
ticket:
|
||||||
logTable: clientLog
|
logTable: clientLog
|
||||||
|
|
11
config.yml
11
config.yml
|
@ -3,12 +3,20 @@ debug: false
|
||||||
testMode: false
|
testMode: false
|
||||||
pingInterval: 60
|
pingInterval: 60
|
||||||
flushInterval: 10
|
flushInterval: 10
|
||||||
db:
|
queueFlushDelay: 100
|
||||||
|
maxBulkLog: 100
|
||||||
|
srcDb:
|
||||||
host: localhost
|
host: localhost
|
||||||
port: 3306
|
port: 3306
|
||||||
user: zongji
|
user: zongji
|
||||||
password: password
|
password: password
|
||||||
database: util
|
database: util
|
||||||
|
dstDb:
|
||||||
|
host: localhost
|
||||||
|
port: 3306
|
||||||
|
user: root
|
||||||
|
password: password
|
||||||
|
database: util
|
||||||
showFields:
|
showFields:
|
||||||
- name
|
- name
|
||||||
- description
|
- description
|
||||||
|
@ -24,7 +32,6 @@ logs:
|
||||||
- image
|
- image
|
||||||
- supplyResponseFk
|
- supplyResponseFk
|
||||||
types:
|
types:
|
||||||
id: number
|
|
||||||
isPrinted: boolean
|
isPrinted: boolean
|
||||||
- name: itemTag
|
- name: itemTag
|
||||||
relation: itemFk
|
relation: itemFk
|
||||||
|
|
183
mylogger.js
183
mylogger.js
|
@ -5,11 +5,11 @@ const path = require('path');
|
||||||
const ZongJi = require('./zongji');
|
const ZongJi = require('./zongji');
|
||||||
const mysql = require('mysql2/promise');
|
const mysql = require('mysql2/promise');
|
||||||
|
|
||||||
const allEvents = [
|
const catchEvents = new Set([
|
||||||
'writerows',
|
'writerows',
|
||||||
'updaterows',
|
'updaterows',
|
||||||
'deleterows'
|
'deleterows'
|
||||||
];
|
]);
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
writerows: 'insert',
|
writerows: 'insert',
|
||||||
|
@ -20,10 +20,12 @@ const actions = {
|
||||||
module.exports = class MyLogger {
|
module.exports = class MyLogger {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.running = false;
|
this.running = false;
|
||||||
this.filename = null;
|
this.binlogName = null;
|
||||||
this.position = null;
|
this.binlogPosition = null;
|
||||||
this.schemaMap = new Map();
|
this.schemaMap = new Map();
|
||||||
this.logMap = new Map();
|
this.logMap = new Map();
|
||||||
|
this.isFlushed = true;
|
||||||
|
this.queue = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
async start() {
|
async start() {
|
||||||
|
@ -35,7 +37,7 @@ module.exports = class MyLogger {
|
||||||
Object.assign(conf, localConfig);
|
Object.assign(conf, localConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultSchema = conf.db.database;
|
const defaultSchema = conf.srcDb.database;
|
||||||
function parseTable(tableString) {
|
function parseTable(tableString) {
|
||||||
let name, schema;
|
let name, schema;
|
||||||
const split = tableString.split('.');
|
const split = tableString.split('.');
|
||||||
|
@ -145,7 +147,7 @@ module.exports = class MyLogger {
|
||||||
|
|
||||||
// DB connection
|
// DB connection
|
||||||
|
|
||||||
const db = this.db = await mysql.createConnection(conf.db);
|
const db = this.db = await mysql.createConnection(conf.dstDb);
|
||||||
db.on('error', this.onErrorListener);
|
db.on('error', this.onErrorListener);
|
||||||
|
|
||||||
for (const logInfo of this.logMap.values()) {
|
for (const logInfo of this.logMap.values()) {
|
||||||
|
@ -192,7 +194,7 @@ module.exports = class MyLogger {
|
||||||
);
|
);
|
||||||
|
|
||||||
for (const {col, type, def} of dbCols) {
|
for (const {col, type, def} of dbCols) {
|
||||||
if (!tableInfo.exclude.has(col))
|
if (!tableInfo.exclude.has(col) && col != 'editorFk')
|
||||||
tableInfo.columns.set(col, {type, def});
|
tableInfo.columns.set(col, {type, def});
|
||||||
|
|
||||||
const castType = conf.castTypes[type];
|
const castType = conf.castTypes[type];
|
||||||
|
@ -259,14 +261,6 @@ module.exports = class MyLogger {
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
console.debug(
|
|
||||||
table,
|
|
||||||
schema,
|
|
||||||
mainTable.name,
|
|
||||||
mainTable.schema,
|
|
||||||
mainTableInfo.idName
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!relations.length)
|
if (!relations.length)
|
||||||
throw new Error(`No relation to main table found for table: ${schema}.${table}`);
|
throw new Error(`No relation to main table found for table: ${schema}.${table}`);
|
||||||
if (relations.length > 1)
|
if (relations.length > 1)
|
||||||
|
@ -279,7 +273,7 @@ module.exports = class MyLogger {
|
||||||
|
|
||||||
// Zongji
|
// Zongji
|
||||||
|
|
||||||
const zongji = new ZongJi(conf.db);
|
const zongji = new ZongJi(conf.srcDb);
|
||||||
this.zongji = zongji;
|
this.zongji = zongji;
|
||||||
|
|
||||||
this.onBinlogListener = evt => this.onBinlog(evt);
|
this.onBinlogListener = evt => this.onBinlog(evt);
|
||||||
|
@ -291,11 +285,11 @@ module.exports = class MyLogger {
|
||||||
);
|
);
|
||||||
if (res.length) {
|
if (res.length) {
|
||||||
const [row] = res;
|
const [row] = res;
|
||||||
this.filename = row.logName;
|
this.binlogName = row.logName;
|
||||||
this.position = row.position;
|
this.binlogPosition = row.position;
|
||||||
Object.assign(this.opts, {
|
Object.assign(this.opts, {
|
||||||
filename: this.filename,
|
filename: row.logName,
|
||||||
position: this.position
|
position: row.position
|
||||||
});
|
});
|
||||||
} else
|
} else
|
||||||
this.opts.startAtEnd = true;
|
this.opts.startAtEnd = true;
|
||||||
|
@ -342,6 +336,9 @@ module.exports = class MyLogger {
|
||||||
|
|
||||||
clearInterval(this.flushInterval);
|
clearInterval(this.flushInterval);
|
||||||
clearInterval(this.pingInterval);
|
clearInterval(this.pingInterval);
|
||||||
|
clearInterval(this.flushTimeout);
|
||||||
|
await this.flushQueue();
|
||||||
|
|
||||||
zongji.off('binlog', this.onBinlogListener);
|
zongji.off('binlog', this.onBinlogListener);
|
||||||
zongji.off('error', this.onErrorListener);
|
zongji.off('error', this.onErrorListener);
|
||||||
this.zongji = null;
|
this.zongji = null;
|
||||||
|
@ -409,29 +406,36 @@ module.exports = class MyLogger {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onBinlog(evt) {
|
async onBinlog(evt) {
|
||||||
//evt.dump();
|
//evt.dump();
|
||||||
const eventName = evt.getEventName();
|
try {
|
||||||
let position = evt.nextPosition;
|
let shouldFlush;
|
||||||
|
const eventName = evt.getEventName();
|
||||||
|
|
||||||
switch (eventName) {
|
if (eventName == 'rotate') {
|
||||||
case 'rotate':
|
if (evt.binlogName !== this.binlogName) {
|
||||||
this.filename = evt.binlogName;
|
shouldFlush = true;
|
||||||
position = evt.position;
|
this.binlogName = evt.binlogName;
|
||||||
console.log(`[${eventName}] filename: ${this.filename}`, `position: ${this.position}, nextPosition: ${evt.nextPosition}`);
|
this.binlogPosition = evt.position;
|
||||||
break;
|
console.log(
|
||||||
case 'writerows':
|
`[${eventName}] filename: ${this.binlogName}`,
|
||||||
case 'deleterows':
|
`position: ${this.binlogPosition}`
|
||||||
case 'updaterows':
|
);
|
||||||
this.onRowEvent(evt, eventName);
|
}
|
||||||
break;
|
} else {
|
||||||
|
shouldFlush = true;
|
||||||
|
this.binlogPosition = evt.nextPosition;
|
||||||
|
if (catchEvents.has(eventName))
|
||||||
|
this.onRowEvent(evt, eventName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldFlush) this.isFlushed = false;
|
||||||
|
} catch(err) {
|
||||||
|
this.handleError(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.position = position;
|
|
||||||
this.flushed = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async onRowEvent(evt, eventName) {
|
onRowEvent(evt, eventName) {
|
||||||
const table = evt.tableMap[evt.tableId];
|
const table = evt.tableMap[evt.tableId];
|
||||||
const tableName = table.tableName;
|
const tableName = table.tableName;
|
||||||
const tableMap = this.schemaMap.get(table.parentSchema);
|
const tableMap = this.schemaMap.get(table.parentSchema);
|
||||||
|
@ -450,7 +454,6 @@ module.exports = class MyLogger {
|
||||||
return !!value;
|
return !!value;
|
||||||
default:
|
default:
|
||||||
return value;
|
return value;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -464,7 +467,6 @@ module.exports = class MyLogger {
|
||||||
|
|
||||||
for (const col in before) {
|
for (const col in before) {
|
||||||
if (columns.has(col)
|
if (columns.has(col)
|
||||||
&& after[col] !== undefined
|
|
||||||
&& !equals(after[col], before[col])) {
|
&& !equals(after[col], before[col])) {
|
||||||
if (before[col] !== null)
|
if (before[col] !== null)
|
||||||
oldI[col] = castValue(col, before[col]);
|
oldI[col] = castValue(col, before[col]);
|
||||||
|
@ -480,12 +482,10 @@ module.exports = class MyLogger {
|
||||||
|
|
||||||
for (const row of evt.rows) {
|
for (const row of evt.rows) {
|
||||||
const instance = {};
|
const instance = {};
|
||||||
|
|
||||||
for (const col of cols) {
|
for (const col of cols) {
|
||||||
if (row[col] !== null)
|
if (row[col] !== null)
|
||||||
instance[col] = castValue(col, row[col]);
|
instance[col] = castValue(col, row[col]);
|
||||||
}
|
}
|
||||||
|
|
||||||
changes.push({row, instance});
|
changes.push({row, instance});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -497,6 +497,85 @@ module.exports = class MyLogger {
|
||||||
`${tableName}(${changes}) [${eventName}]`);
|
`${tableName}(${changes}) [${eventName}]`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.queue.push({
|
||||||
|
tableInfo,
|
||||||
|
action,
|
||||||
|
evt,
|
||||||
|
changes,
|
||||||
|
tableName,
|
||||||
|
binlogName: this.binlogName
|
||||||
|
});
|
||||||
|
if (!this.flushTimeout)
|
||||||
|
this.flushTimeout = setTimeout(
|
||||||
|
() => this.flushQueue(),
|
||||||
|
this.conf.queueFlushDelay
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async flushQueue() {
|
||||||
|
if (this.isFlushed || this.isFlushing) return;
|
||||||
|
this.isFlushing = true;
|
||||||
|
const {conf, db} = this;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (this.queue.length) {
|
||||||
|
do {
|
||||||
|
let appliedOps;
|
||||||
|
try {
|
||||||
|
await db.query('START TRANSACTION');
|
||||||
|
let op;
|
||||||
|
appliedOps = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < conf.maxBulkLog && this.queue.length; i++) {
|
||||||
|
op = this.queue.shift();
|
||||||
|
appliedOps.push(op);
|
||||||
|
await this.applyOp(op);
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.savePosition(op.binlogName, op.evt.nextPosition)
|
||||||
|
await db.query('COMMIT');
|
||||||
|
} catch(err) {
|
||||||
|
this.queue = appliedOps.concat(this.queue);
|
||||||
|
await db.query('ROLLBACK');
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
} while (this.queue.length);
|
||||||
|
} else {
|
||||||
|
await this.savePosition(this.binlogName, this.binlogPosition);
|
||||||
|
}
|
||||||
|
} catch(err) {
|
||||||
|
this.handleError(err);
|
||||||
|
} finally {
|
||||||
|
this.flushTimeout = null;
|
||||||
|
this.isFlushing = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async savePosition(binlogName, binlogPosition) {
|
||||||
|
this.debug('Flush', `filename: ${binlogName}, position: ${binlogPosition}`);
|
||||||
|
|
||||||
|
const replaceQuery =
|
||||||
|
'REPLACE INTO `util`.`binlogQueue` SET `code` = ?, `logName` = ?, `position` = ?';
|
||||||
|
if (!this.conf.testMode)
|
||||||
|
await this.db.query(replaceQuery, [this.conf.code, binlogName, binlogPosition]);
|
||||||
|
|
||||||
|
this.isFlushed = this.binlogName == binlogName
|
||||||
|
&& this.binlogPosition == binlogPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
handleError(err) {
|
||||||
|
console.error('Super error:', err);
|
||||||
|
}
|
||||||
|
|
||||||
|
async applyOp(op) {
|
||||||
|
const {
|
||||||
|
tableInfo,
|
||||||
|
action,
|
||||||
|
evt,
|
||||||
|
changes,
|
||||||
|
tableName
|
||||||
|
} = op;
|
||||||
|
|
||||||
const logInfo = tableInfo.log;
|
const logInfo = tableInfo.log;
|
||||||
const isDelete = action == 'delete';
|
const isDelete = action == 'delete';
|
||||||
|
|
||||||
|
@ -558,26 +637,6 @@ module.exports = class MyLogger {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async flushQueue() {
|
|
||||||
if (this.flushed) return;
|
|
||||||
const position = this.nextPosition;
|
|
||||||
|
|
||||||
if (position) {
|
|
||||||
const filename = this.nextFilename;
|
|
||||||
this.debug('Flush', `filename: ${filename}, position: ${position}`);
|
|
||||||
|
|
||||||
const replaceQuery =
|
|
||||||
'REPLACE INTO `util`.`binlogQueue` SET `code` = ?, `logName` = ?, `position` = ?';
|
|
||||||
if (!this.conf.testMode)
|
|
||||||
await this.db.query(replaceQuery, [this.conf.code, filename, position]);
|
|
||||||
|
|
||||||
this.flushed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.nextFilename = this.filename;
|
|
||||||
this.nextPosition = this.position;
|
|
||||||
}
|
|
||||||
|
|
||||||
async connectionPing() {
|
async connectionPing() {
|
||||||
this.debug('Ping', 'Sending ping to database.');
|
this.debug('Ping', 'Sending ping to database.');
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue