perf: 给SQLITE_IOERR_WRITE增加友好报错提示,将certd:latest镜像改为certd:slim

This commit is contained in:
xiaojunnuo
2026-07-14 21:32:32 +08:00
parent 584b7b6f45
commit b91c9e4ea6
+37 -32
View File
@@ -1,8 +1,8 @@
import * as path from 'path'; import * as path from "path";
import * as fs from 'fs'; import * as fs from "fs";
import { QueryRunner, Table } from 'typeorm'; import { QueryRunner, Table } from "typeorm";
import { FlywayHistory } from './entity.js'; import { FlywayHistory } from "./entity.js";
import * as crypto from 'crypto'; import * as crypto from "crypto";
/** /**
* 脚本文件信息 * 脚本文件信息
@@ -32,10 +32,10 @@ const DefaultLogger = {
}, },
}; };
let customLogger:any = null; let customLogger: any = null;
export function setFlywayLogger (logger: any) { export function setFlywayLogger(logger: any) {
customLogger = logger; customLogger = logger;
}; }
export class Flyway { export class Flyway {
scriptDir; scriptDir;
@@ -45,8 +45,8 @@ export class Flyway {
connection; connection;
logger; logger;
constructor(opts: any) { constructor(opts: any) {
this.scriptDir = opts.scriptDir ?? 'db/migration'; this.scriptDir = opts.scriptDir ?? "db/migration";
this.flywayTableName = opts.flywayTableName ?? 'flyway_history'; this.flywayTableName = opts.flywayTableName ?? "flyway_history";
this.baseline = opts.baseline ?? false; this.baseline = opts.baseline ?? false;
this.allowHashNotMatch = opts.allowHashNotMatch ?? false; this.allowHashNotMatch = opts.allowHashNotMatch ?? false;
this.logger = customLogger || opts.logger || DefaultLogger; this.logger = customLogger || opts.logger || DefaultLogger;
@@ -54,9 +54,9 @@ export class Flyway {
} }
async run(ignores?: (RegExp | string)[]) { async run(ignores?: (RegExp | string)[]) {
this.logger.info('[ midfly ] start-------------'); this.logger.info("[ midfly ] start-------------");
if (!fs.existsSync(this.scriptDir)) { if (!fs.existsSync(this.scriptDir)) {
this.logger.info('[ midfly ] scriptDir<' + this.scriptDir + '> not found'); this.logger.info("[ midfly ] scriptDir<" + this.scriptDir + "> not found");
return; return;
} }
@@ -77,7 +77,7 @@ export class Flyway {
continue; continue;
} }
if (!file.isBaseline) { if (!file.isBaseline) {
this.logger.info('need exec script file: ', file.script); this.logger.info("need exec script file: ", file.script);
//执行sql文件 //执行sql文件
if (/\.sql$/.test(file.script)) { if (/\.sql$/.test(file.script)) {
await this.execSql(filepath, queryRunner); await this.execSql(filepath, queryRunner);
@@ -87,7 +87,7 @@ export class Flyway {
// await this.execJsOrTs(filepath, t); // await this.execJsOrTs(filepath, t);
// } // }
} else { } else {
this.logger.info('baseline script file: ', file.script); this.logger.info("baseline script file: ", file.script);
} }
await this.storeSqlExecLog(file.script, filepath, true, queryRunner); await this.storeSqlExecLog(file.script, filepath, true, queryRunner);
await queryRunner.commitTransaction(); await queryRunner.commitTransaction();
@@ -95,10 +95,15 @@ export class Flyway {
this.logger.error(err); this.logger.error(err);
await this.storeSqlExecLog(file.script, filepath, false, queryRunner); await this.storeSqlExecLog(file.script, filepath, false, queryRunner);
await queryRunner.rollbackTransaction(); await queryRunner.rollbackTransaction();
if (err.code === "SQLITE_IOERR_WRITE") {
this.logger.warn("SQLite数据库写入失败,可能您的操作系统版本太低,请将「certd:latest」镜像改为「certd:slim」即可。(如需指定版本可以修改成「certd:[version]-slim」)", file.script);
}
throw err; throw err;
} }
} }
this.logger.info('[ midfly ] end-------------'); this.logger.info("[ midfly ] end-------------");
} }
private async storeSqlExecLog(filename: string, filepath: string, success: boolean, queryRunner: QueryRunner) { private async storeSqlExecLog(filename: string, filepath: string, success: boolean, queryRunner: QueryRunner) {
@@ -160,17 +165,17 @@ export class Flyway {
name: this.flywayTableName, name: this.flywayTableName,
columns: [ columns: [
{ {
name: 'id', name: "id",
type: this.connection.driver.normalizeType({ type: this.connection.driver.normalizeType({
type: this.connection.driver.mappedDataTypes.migrationId, type: this.connection.driver.mappedDataTypes.migrationId,
}), }),
isGenerated: true, isGenerated: true,
generationStrategy: 'increment', generationStrategy: "increment",
isPrimary: true, isPrimary: true,
isNullable: false, isNullable: false,
}, },
{ {
name: 'timestamp', name: "timestamp",
type: this.connection.driver.normalizeType({ type: this.connection.driver.normalizeType({
type: this.connection.driver.mappedDataTypes.migrationTimestamp, type: this.connection.driver.mappedDataTypes.migrationTimestamp,
}), }),
@@ -178,23 +183,23 @@ export class Flyway {
isNullable: false, isNullable: false,
}, },
{ {
name: 'name', name: "name",
type: this.connection.driver.normalizeType({ type: this.connection.driver.normalizeType({
type: this.connection.driver.mappedDataTypes.migrationName, type: this.connection.driver.mappedDataTypes.migrationName,
}), }),
isNullable: false, isNullable: false,
}, },
{ {
name: 'hash', name: "hash",
type: this.connection.driver.normalizeType({ type: this.connection.driver.normalizeType({
type: this.connection.driver.mappedDataTypes.migrationName, type: this.connection.driver.mappedDataTypes.migrationName,
}), }),
isNullable: true, isNullable: true,
}, },
{ {
name: 'success', name: "success",
type: this.connection.driver.normalizeType({ type: this.connection.driver.normalizeType({
type: 'boolean', type: "boolean",
}), }),
isNullable: true, isNullable: true,
}, },
@@ -210,7 +215,7 @@ export class Flyway {
} }
let ret = false; let ret = false;
for (const ignore of ignores) { for (const ignore of ignores) {
if (typeof ignore === 'string' && file === ignore) { if (typeof ignore === "string" && file === ignore) {
ret = true; ret = true;
break; break;
} }
@@ -233,20 +238,20 @@ export class Flyway {
if (history.hash !== hash && this.allowHashNotMatch === false) { if (history.hash !== hash && this.allowHashNotMatch === false) {
throw new Error(file + `hash conflict ,old: ${history.hash} != new: ${hash}`); throw new Error(file + `hash conflict ,old: ${history.hash} != new: ${hash}`);
} }
this.logger.info('[ midfly ] script<' + file + '> already executed'); this.logger.info("[ midfly ] script<" + file + "> already executed");
return true; return true;
} }
this.logger.info('[ midfly ] script<' + file + '> not yet execute'); this.logger.info("[ midfly ] script<" + file + "> not yet execute");
return false; return false;
} }
private async getFileHash(filepath: string) { private async getFileHash(filepath: string) {
const content = fs.readFileSync(filepath).toString(); const content = fs.readFileSync(filepath).toString();
return crypto.createHash('md5').update(content.toString()).digest('hex'); return crypto.createHash("md5").update(content.toString()).digest("hex");
} }
private async execSql(filepath: string, queryRunner: QueryRunner) { private async execSql(filepath: string, queryRunner: QueryRunner) {
this.logger.info('[ midfly ] exec ', filepath); this.logger.info("[ midfly ] exec ", filepath);
const content = fs.readFileSync(filepath).toString().trim(); const content = fs.readFileSync(filepath).toString().trim();
const arr = this.splitSql2Array(content); const arr = this.splitSql2Array(content);
for (const s of arr) { for (const s of arr) {
@@ -255,11 +260,11 @@ export class Flyway {
} }
private async execOnePart(sql: string, queryRunner: QueryRunner) { private async execOnePart(sql: string, queryRunner: QueryRunner) {
this.logger.debug('exec sql index: ', sql); this.logger.debug("exec sql index: ", sql);
try { try {
await queryRunner.query(sql); await queryRunner.query(sql);
} catch (err: any) { } catch (err: any) {
this.logger.error('exec sql error ', err.message, err); this.logger.error("exec sql error ", err.message, err);
throw err; throw err;
} }
} }
@@ -275,11 +280,11 @@ export class Flyway {
const temp = String(str).trim(); const temp = String(str).trim();
if (temp === 'null') { if (temp === "null") {
return []; return [];
} }
const semicolon = ';'; const semicolon = ";";
const deepChars = ['"', "'"]; const deepChars = ['"', "'"];
const splits = []; const splits = [];
@@ -289,7 +294,7 @@ export class Flyway {
if (deepChars.indexOf(charAt) >= 0) { if (deepChars.indexOf(charAt) >= 0) {
//如果是深度char //如果是深度char
if (i !== 0 && temp.charAt(i - 1) === '\\') { if (i !== 0 && temp.charAt(i - 1) === "\\") {
//如果前一个是转义字符,忽略它 //如果前一个是转义字符,忽略它
} else { } else {
//说明需要进出深度了 //说明需要进出深度了