チャートInsert時にロックをかけるように (#6100)

* chart lock

* fix
This commit is contained in:
MeiMei 2020-03-06 22:33:54 +09:00 committed by GitHub
parent 3e61aa0835
commit 20ac7e62e9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 24 additions and 15 deletions

View file

@ -24,3 +24,7 @@ export function getApLock(uri: string, timeout = 30 * 1000) {
export function getNodeinfoLock(host: string, timeout = 30 * 1000) { export function getNodeinfoLock(host: string, timeout = 30 * 1000) {
return lock(`nodeinfo:${host}`, timeout); return lock(`nodeinfo:${host}`, timeout);
} }
export function getChartInsertLock(lockKey: string, timeout = 30 * 1000) {
return lock(`chart-insert:${lockKey}`, timeout);
}

View file

@ -9,8 +9,8 @@ import autobind from 'autobind-decorator';
import Logger from '../logger'; import Logger from '../logger';
import { Schema } from '../../misc/schema'; import { Schema } from '../../misc/schema';
import { EntitySchema, getRepository, Repository, LessThan, MoreThanOrEqual } from 'typeorm'; import { EntitySchema, getRepository, Repository, LessThan, MoreThanOrEqual } from 'typeorm';
import { isDuplicateKeyValueError } from '../../misc/is-duplicate-key-value-error';
import { DateUTC, isTimeSame, isTimeBefore, subtractTimespan } from '../../prelude/time'; import { DateUTC, isTimeSame, isTimeBefore, subtractTimespan } from '../../prelude/time';
import { getChartInsertLock } from '../../misc/app-lock';
const logger = new Logger('chart', 'white', process.env.NODE_ENV !== 'test'); const logger = new Logger('chart', 'white', process.env.NODE_ENV !== 'test');
@ -283,30 +283,35 @@ export default abstract class Chart<T extends Record<string, any>> {
logger.info(`${this.name + (group ? `:${group}` : '')} (${span}): Initial commit created`); logger.info(`${this.name + (group ? `:${group}` : '')} (${span}): Initial commit created`);
} }
const date = Chart.dateToTimestamp(current);
const lockKey = `${this.name}:${date}:${group}:${span}`;
const unlock = await getChartInsertLock(lockKey);
try { try {
// ロック内でもう1回チェックする
const currentLog = await this.repository.findOne({
span: span,
date: date,
...(group ? { group: group } : {})
});
// ログがあればそれを返して終了
if (currentLog != null) return currentLog;
// 新規ログ挿入 // 新規ログ挿入
log = await this.repository.save({ log = await this.repository.save({
group: group, group: group,
span: span, span: span,
date: Chart.dateToTimestamp(current), date: date,
...Chart.convertObjectToFlattenColumns(data) ...Chart.convertObjectToFlattenColumns(data)
}); });
logger.info(`${this.name + (group ? `:${group}` : '')} (${span}): New commit created`); logger.info(`${this.name + (group ? `:${group}` : '')} (${span}): New commit created`);
} catch (e) {
// duplicate key error
// 並列動作している他のチャートエンジンプロセスと処理が重なる場合がある
// その場合は再度最も新しいログを持ってくる
if (isDuplicateKeyValueError(e)) {
log = await this.getLatestLog(span, group) as Log;
logger.info(`${this.name + (group ? `:${group}` : '')} (${span}): Commit duplicated`);
} else {
logger.error(e);
throw e;
}
}
return log; return log;
} finally {
unlock();
}
} }
@autobind @autobind