update deps (MisskeyIO#889)
- メンテナンスされないredis-lockを自前実装に変更 - 既にロックされている場合のリトライ間隔を調整
This commit is contained in:
parent
46edd40409
commit
90e2dfef4e
|
@ -161,7 +161,6 @@
|
||||||
"ratelimiter": "3.4.1",
|
"ratelimiter": "3.4.1",
|
||||||
"re2": "1.21.5",
|
"re2": "1.21.5",
|
||||||
"redis-info": "3.1.0",
|
"redis-info": "3.1.0",
|
||||||
"redis-lock": "1.0.0",
|
|
||||||
"reflect-metadata": "0.2.2",
|
"reflect-metadata": "0.2.2",
|
||||||
"rename": "1.0.4",
|
"rename": "1.0.4",
|
||||||
"rss-parser": "3.13.0",
|
"rss-parser": "3.13.0",
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare module 'redis-lock' {
|
|
||||||
import type Redis from 'ioredis';
|
|
||||||
|
|
||||||
type Lock = (lockName: string, timeout?: number, taskToPerform?: () => Promise<void>) => void;
|
|
||||||
function redisLock(client: Redis.Redis, retryDelay: number): Lock;
|
|
||||||
|
|
||||||
export = redisLock;
|
|
||||||
}
|
|
|
@ -1,44 +0,0 @@
|
||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { promisify } from 'node:util';
|
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
|
||||||
import redisLock from 'redis-lock';
|
|
||||||
import * as Redis from 'ioredis';
|
|
||||||
import { DI } from '@/di-symbols.js';
|
|
||||||
import { bindThis } from '@/decorators.js';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retry delay (ms) for lock acquisition
|
|
||||||
*/
|
|
||||||
const retryDelay = 100;
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class AppLockService {
|
|
||||||
private lock: (key: string, timeout?: number, _?: (() => Promise<void>) | undefined) => Promise<() => void>;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
@Inject(DI.redis)
|
|
||||||
private redisClient: Redis.Redis,
|
|
||||||
) {
|
|
||||||
this.lock = promisify(redisLock(this.redisClient, retryDelay));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get AP Object lock
|
|
||||||
* @param uri AP object ID
|
|
||||||
* @param timeout Lock timeout (ms), The timeout releases previous lock.
|
|
||||||
* @returns Unlock function
|
|
||||||
*/
|
|
||||||
@bindThis
|
|
||||||
public getApLock(uri: string, timeout = 30 * 1000): Promise<() => void> {
|
|
||||||
return this.lock(`ap-object:${uri}`, timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
@bindThis
|
|
||||||
public getChartInsertLock(lockKey: string, timeout = 30 * 1000): Promise<() => void> {
|
|
||||||
return this.lock(`chart-insert:${lockKey}`, timeout);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -20,7 +20,6 @@ import { AccountUpdateService } from './AccountUpdateService.js';
|
||||||
import { AiService } from './AiService.js';
|
import { AiService } from './AiService.js';
|
||||||
import { AnnouncementService } from './AnnouncementService.js';
|
import { AnnouncementService } from './AnnouncementService.js';
|
||||||
import { AntennaService } from './AntennaService.js';
|
import { AntennaService } from './AntennaService.js';
|
||||||
import { AppLockService } from './AppLockService.js';
|
|
||||||
import { AchievementService } from './AchievementService.js';
|
import { AchievementService } from './AchievementService.js';
|
||||||
import { AvatarDecorationService } from './AvatarDecorationService.js';
|
import { AvatarDecorationService } from './AvatarDecorationService.js';
|
||||||
import { CaptchaService } from './CaptchaService.js';
|
import { CaptchaService } from './CaptchaService.js';
|
||||||
|
@ -162,7 +161,6 @@ const $AccountUpdateService: Provider = { provide: 'AccountUpdateService', useEx
|
||||||
const $AiService: Provider = { provide: 'AiService', useExisting: AiService };
|
const $AiService: Provider = { provide: 'AiService', useExisting: AiService };
|
||||||
const $AnnouncementService: Provider = { provide: 'AnnouncementService', useExisting: AnnouncementService };
|
const $AnnouncementService: Provider = { provide: 'AnnouncementService', useExisting: AnnouncementService };
|
||||||
const $AntennaService: Provider = { provide: 'AntennaService', useExisting: AntennaService };
|
const $AntennaService: Provider = { provide: 'AntennaService', useExisting: AntennaService };
|
||||||
const $AppLockService: Provider = { provide: 'AppLockService', useExisting: AppLockService };
|
|
||||||
const $AchievementService: Provider = { provide: 'AchievementService', useExisting: AchievementService };
|
const $AchievementService: Provider = { provide: 'AchievementService', useExisting: AchievementService };
|
||||||
const $AvatarDecorationService: Provider = { provide: 'AvatarDecorationService', useExisting: AvatarDecorationService };
|
const $AvatarDecorationService: Provider = { provide: 'AvatarDecorationService', useExisting: AvatarDecorationService };
|
||||||
const $CaptchaService: Provider = { provide: 'CaptchaService', useExisting: CaptchaService };
|
const $CaptchaService: Provider = { provide: 'CaptchaService', useExisting: CaptchaService };
|
||||||
|
@ -312,7 +310,6 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||||
AiService,
|
AiService,
|
||||||
AnnouncementService,
|
AnnouncementService,
|
||||||
AntennaService,
|
AntennaService,
|
||||||
AppLockService,
|
|
||||||
AchievementService,
|
AchievementService,
|
||||||
AvatarDecorationService,
|
AvatarDecorationService,
|
||||||
CaptchaService,
|
CaptchaService,
|
||||||
|
@ -458,7 +455,6 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||||
$AiService,
|
$AiService,
|
||||||
$AnnouncementService,
|
$AnnouncementService,
|
||||||
$AntennaService,
|
$AntennaService,
|
||||||
$AppLockService,
|
|
||||||
$AchievementService,
|
$AchievementService,
|
||||||
$AvatarDecorationService,
|
$AvatarDecorationService,
|
||||||
$CaptchaService,
|
$CaptchaService,
|
||||||
|
@ -605,7 +601,6 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||||
AiService,
|
AiService,
|
||||||
AnnouncementService,
|
AnnouncementService,
|
||||||
AntennaService,
|
AntennaService,
|
||||||
AppLockService,
|
|
||||||
AchievementService,
|
AchievementService,
|
||||||
AvatarDecorationService,
|
AvatarDecorationService,
|
||||||
CaptchaService,
|
CaptchaService,
|
||||||
|
@ -750,7 +745,6 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||||
$AiService,
|
$AiService,
|
||||||
$AnnouncementService,
|
$AnnouncementService,
|
||||||
$AntennaService,
|
$AntennaService,
|
||||||
$AppLockService,
|
|
||||||
$AchievementService,
|
$AchievementService,
|
||||||
$AvatarDecorationService,
|
$AvatarDecorationService,
|
||||||
$CaptchaService,
|
$CaptchaService,
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { In } from 'typeorm';
|
import { In } from 'typeorm';
|
||||||
|
import * as Redis from 'ioredis';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import type { Config } from '@/config.js';
|
import type { Config } from '@/config.js';
|
||||||
import { UserFollowingService } from '@/core/UserFollowingService.js';
|
import { UserFollowingService } from '@/core/UserFollowingService.js';
|
||||||
|
@ -14,8 +15,8 @@ import { NotePiningService } from '@/core/NotePiningService.js';
|
||||||
import { UserBlockingService } from '@/core/UserBlockingService.js';
|
import { UserBlockingService } from '@/core/UserBlockingService.js';
|
||||||
import { NoteDeleteService } from '@/core/NoteDeleteService.js';
|
import { NoteDeleteService } from '@/core/NoteDeleteService.js';
|
||||||
import { NoteCreateService } from '@/core/NoteCreateService.js';
|
import { NoteCreateService } from '@/core/NoteCreateService.js';
|
||||||
|
import { acquireApObjectLock } from '@/misc/distributed-lock.js';
|
||||||
import { concat, toArray, toSingle, unique } from '@/misc/prelude/array.js';
|
import { concat, toArray, toSingle, unique } from '@/misc/prelude/array.js';
|
||||||
import { AppLockService } from '@/core/AppLockService.js';
|
|
||||||
import type Logger from '@/logger.js';
|
import type Logger from '@/logger.js';
|
||||||
import { IdService } from '@/core/IdService.js';
|
import { IdService } from '@/core/IdService.js';
|
||||||
import { StatusError } from '@/misc/status-error.js';
|
import { StatusError } from '@/misc/status-error.js';
|
||||||
|
@ -48,8 +49,8 @@ export class ApInboxService {
|
||||||
@Inject(DI.config)
|
@Inject(DI.config)
|
||||||
private config: Config,
|
private config: Config,
|
||||||
|
|
||||||
@Inject(DI.meta)
|
@Inject(DI.redisForTimelines)
|
||||||
private meta: MiMeta,
|
private redisForTimelines: Redis.Redis,
|
||||||
|
|
||||||
@Inject(DI.usersRepository)
|
@Inject(DI.usersRepository)
|
||||||
private usersRepository: UsersRepository,
|
private usersRepository: UsersRepository,
|
||||||
|
@ -76,7 +77,6 @@ export class ApInboxService {
|
||||||
private userBlockingService: UserBlockingService,
|
private userBlockingService: UserBlockingService,
|
||||||
private noteCreateService: NoteCreateService,
|
private noteCreateService: NoteCreateService,
|
||||||
private noteDeleteService: NoteDeleteService,
|
private noteDeleteService: NoteDeleteService,
|
||||||
private appLockService: AppLockService,
|
|
||||||
private apResolverService: ApResolverService,
|
private apResolverService: ApResolverService,
|
||||||
private apDbResolverService: ApDbResolverService,
|
private apDbResolverService: ApDbResolverService,
|
||||||
private apLoggerService: ApLoggerService,
|
private apLoggerService: ApLoggerService,
|
||||||
|
@ -311,7 +311,7 @@ export class ApInboxService {
|
||||||
// アナウンス先が許可されているかチェック
|
// アナウンス先が許可されているかチェック
|
||||||
if (!this.utilityService.isFederationAllowedUri(uri)) return;
|
if (!this.utilityService.isFederationAllowedUri(uri)) return;
|
||||||
|
|
||||||
const unlock = await this.appLockService.getApLock(uri);
|
const unlock = await acquireApObjectLock(this.redisForTimelines, uri);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 既に同じURIを持つものが登録されていないかチェック
|
// 既に同じURIを持つものが登録されていないかチェック
|
||||||
|
@ -438,7 +438,7 @@ export class ApInboxService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const unlock = await this.appLockService.getApLock(uri);
|
const unlock = await acquireApObjectLock(this.redisForTimelines, uri);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const exist = await this.apNoteService.fetchNote(note);
|
const exist = await this.apNoteService.fetchNote(note);
|
||||||
|
@ -522,7 +522,7 @@ export class ApInboxService {
|
||||||
private async deleteNote(actor: MiRemoteUser, uri: string): Promise<string> {
|
private async deleteNote(actor: MiRemoteUser, uri: string): Promise<string> {
|
||||||
this.logger.info(`Deleting the Note: ${uri}`);
|
this.logger.info(`Deleting the Note: ${uri}`);
|
||||||
|
|
||||||
const unlock = await this.appLockService.getApLock(uri);
|
const unlock = await acquireApObjectLock(this.redisForTimelines, uri);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const note = await this.apDbResolverService.getNoteFromApId(uri);
|
const note = await this.apDbResolverService.getNoteFromApId(uri);
|
||||||
|
|
|
@ -5,14 +5,15 @@
|
||||||
|
|
||||||
import { forwardRef, Inject, Injectable } from '@nestjs/common';
|
import { forwardRef, Inject, Injectable } from '@nestjs/common';
|
||||||
import { In } from 'typeorm';
|
import { In } from 'typeorm';
|
||||||
|
import * as Redis from 'ioredis';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import type { PollsRepository, EmojisRepository, MiMeta } from '@/models/_.js';
|
import type { PollsRepository, EmojisRepository, MiMeta } from '@/models/_.js';
|
||||||
import type { Config } from '@/config.js';
|
import type { Config } from '@/config.js';
|
||||||
import type { MiRemoteUser } from '@/models/User.js';
|
import type { MiRemoteUser } from '@/models/User.js';
|
||||||
import type { MiNote } from '@/models/Note.js';
|
import type { MiNote } from '@/models/Note.js';
|
||||||
|
import { acquireApObjectLock } from '@/misc/distributed-lock.js';
|
||||||
import { toArray, toSingle, unique } from '@/misc/prelude/array.js';
|
import { toArray, toSingle, unique } from '@/misc/prelude/array.js';
|
||||||
import type { MiEmoji } from '@/models/Emoji.js';
|
import type { MiEmoji } from '@/models/Emoji.js';
|
||||||
import { AppLockService } from '@/core/AppLockService.js';
|
|
||||||
import type { MiDriveFile } from '@/models/DriveFile.js';
|
import type { MiDriveFile } from '@/models/DriveFile.js';
|
||||||
import { NoteCreateService } from '@/core/NoteCreateService.js';
|
import { NoteCreateService } from '@/core/NoteCreateService.js';
|
||||||
import type Logger from '@/logger.js';
|
import type Logger from '@/logger.js';
|
||||||
|
@ -48,6 +49,9 @@ export class ApNoteService {
|
||||||
@Inject(DI.meta)
|
@Inject(DI.meta)
|
||||||
private meta: MiMeta,
|
private meta: MiMeta,
|
||||||
|
|
||||||
|
@Inject(DI.redisForTimelines)
|
||||||
|
private redisForTimelines: Redis.Redis,
|
||||||
|
|
||||||
@Inject(DI.pollsRepository)
|
@Inject(DI.pollsRepository)
|
||||||
private pollsRepository: PollsRepository,
|
private pollsRepository: PollsRepository,
|
||||||
|
|
||||||
|
@ -67,7 +71,6 @@ export class ApNoteService {
|
||||||
private apMentionService: ApMentionService,
|
private apMentionService: ApMentionService,
|
||||||
private apImageService: ApImageService,
|
private apImageService: ApImageService,
|
||||||
private apQuestionService: ApQuestionService,
|
private apQuestionService: ApQuestionService,
|
||||||
private appLockService: AppLockService,
|
|
||||||
private pollService: PollService,
|
private pollService: PollService,
|
||||||
private noteCreateService: NoteCreateService,
|
private noteCreateService: NoteCreateService,
|
||||||
private apDbResolverService: ApDbResolverService,
|
private apDbResolverService: ApDbResolverService,
|
||||||
|
@ -354,7 +357,7 @@ export class ApNoteService {
|
||||||
throw new StatusError('blocked host', 451);
|
throw new StatusError('blocked host', 451);
|
||||||
}
|
}
|
||||||
|
|
||||||
const unlock = await this.appLockService.getApLock(uri);
|
const unlock = await acquireApObjectLock(this.redisForTimelines, uri);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
//#region このサーバーに既に登録されていたらそれを返す
|
//#region このサーバーに既に登録されていたらそれを返す
|
||||||
|
|
|
@ -5,11 +5,12 @@
|
||||||
|
|
||||||
import { Injectable, Inject } from '@nestjs/common';
|
import { Injectable, Inject } from '@nestjs/common';
|
||||||
import { DataSource } from 'typeorm';
|
import { DataSource } from 'typeorm';
|
||||||
import { AppLockService } from '@/core/AppLockService.js';
|
import * as Redis from 'ioredis';
|
||||||
import type { MiUser } from '@/models/User.js';
|
import type { MiUser } from '@/models/User.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import { IdService } from '@/core/IdService.js';
|
import { IdService } from '@/core/IdService.js';
|
||||||
|
import { acquireChartInsertLock } from '@/misc/distributed-lock.js';
|
||||||
import Chart from '../core.js';
|
import Chart from '../core.js';
|
||||||
import { ChartLoggerService } from '../ChartLoggerService.js';
|
import { ChartLoggerService } from '../ChartLoggerService.js';
|
||||||
import { name, schema } from './entities/active-users.js';
|
import { name, schema } from './entities/active-users.js';
|
||||||
|
@ -28,11 +29,13 @@ export default class ActiveUsersChart extends Chart<typeof schema> { // eslint-d
|
||||||
@Inject(DI.db)
|
@Inject(DI.db)
|
||||||
private db: DataSource,
|
private db: DataSource,
|
||||||
|
|
||||||
private appLockService: AppLockService,
|
@Inject(DI.redisForTimelines)
|
||||||
|
private redisForTimelines: Redis.Redis,
|
||||||
|
|
||||||
private chartLoggerService: ChartLoggerService,
|
private chartLoggerService: ChartLoggerService,
|
||||||
private idService: IdService,
|
private idService: IdService,
|
||||||
) {
|
) {
|
||||||
super(db, (k) => appLockService.getChartInsertLock(k), chartLoggerService.logger, name, schema);
|
super(db, (k) => acquireChartInsertLock(redisForTimelines, k), chartLoggerService.logger, name, schema);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async tickMajor(): Promise<Partial<KVs<typeof schema>>> {
|
protected async tickMajor(): Promise<Partial<KVs<typeof schema>>> {
|
||||||
|
|
|
@ -5,9 +5,10 @@
|
||||||
|
|
||||||
import { Injectable, Inject } from '@nestjs/common';
|
import { Injectable, Inject } from '@nestjs/common';
|
||||||
import { DataSource } from 'typeorm';
|
import { DataSource } from 'typeorm';
|
||||||
import { AppLockService } from '@/core/AppLockService.js';
|
import * as Redis from 'ioredis';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
import { acquireChartInsertLock } from '@/misc/distributed-lock.js';
|
||||||
import Chart from '../core.js';
|
import Chart from '../core.js';
|
||||||
import { ChartLoggerService } from '../ChartLoggerService.js';
|
import { ChartLoggerService } from '../ChartLoggerService.js';
|
||||||
import { name, schema } from './entities/ap-request.js';
|
import { name, schema } from './entities/ap-request.js';
|
||||||
|
@ -22,10 +23,12 @@ export default class ApRequestChart extends Chart<typeof schema> { // eslint-dis
|
||||||
@Inject(DI.db)
|
@Inject(DI.db)
|
||||||
private db: DataSource,
|
private db: DataSource,
|
||||||
|
|
||||||
private appLockService: AppLockService,
|
@Inject(DI.redisForTimelines)
|
||||||
|
private redisForTimelines: Redis.Redis,
|
||||||
|
|
||||||
private chartLoggerService: ChartLoggerService,
|
private chartLoggerService: ChartLoggerService,
|
||||||
) {
|
) {
|
||||||
super(db, (k) => appLockService.getChartInsertLock(k), chartLoggerService.logger, name, schema);
|
super(db, (k) => acquireChartInsertLock(redisForTimelines, k), chartLoggerService.logger, name, schema);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async tickMajor(): Promise<Partial<KVs<typeof schema>>> {
|
protected async tickMajor(): Promise<Partial<KVs<typeof schema>>> {
|
||||||
|
|
|
@ -5,10 +5,11 @@
|
||||||
|
|
||||||
import { Injectable, Inject } from '@nestjs/common';
|
import { Injectable, Inject } from '@nestjs/common';
|
||||||
import { DataSource } from 'typeorm';
|
import { DataSource } from 'typeorm';
|
||||||
|
import * as Redis from 'ioredis';
|
||||||
import type { MiDriveFile } from '@/models/DriveFile.js';
|
import type { MiDriveFile } from '@/models/DriveFile.js';
|
||||||
import { AppLockService } from '@/core/AppLockService.js';
|
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
import { acquireChartInsertLock } from '@/misc/distributed-lock.js';
|
||||||
import Chart from '../core.js';
|
import Chart from '../core.js';
|
||||||
import { ChartLoggerService } from '../ChartLoggerService.js';
|
import { ChartLoggerService } from '../ChartLoggerService.js';
|
||||||
import { name, schema } from './entities/drive.js';
|
import { name, schema } from './entities/drive.js';
|
||||||
|
@ -23,10 +24,12 @@ export default class DriveChart extends Chart<typeof schema> { // eslint-disable
|
||||||
@Inject(DI.db)
|
@Inject(DI.db)
|
||||||
private db: DataSource,
|
private db: DataSource,
|
||||||
|
|
||||||
private appLockService: AppLockService,
|
@Inject(DI.redisForTimelines)
|
||||||
|
private redisForTimelines: Redis.Redis,
|
||||||
|
|
||||||
private chartLoggerService: ChartLoggerService,
|
private chartLoggerService: ChartLoggerService,
|
||||||
) {
|
) {
|
||||||
super(db, (k) => appLockService.getChartInsertLock(k), chartLoggerService.logger, name, schema);
|
super(db, (k) => acquireChartInsertLock(redisForTimelines, k), chartLoggerService.logger, name, schema);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async tickMajor(): Promise<Partial<KVs<typeof schema>>> {
|
protected async tickMajor(): Promise<Partial<KVs<typeof schema>>> {
|
||||||
|
|
|
@ -5,10 +5,11 @@
|
||||||
|
|
||||||
import { Injectable, Inject } from '@nestjs/common';
|
import { Injectable, Inject } from '@nestjs/common';
|
||||||
import { DataSource } from 'typeorm';
|
import { DataSource } from 'typeorm';
|
||||||
|
import * as Redis from 'ioredis';
|
||||||
import type { FollowingsRepository, InstancesRepository, MiMeta } from '@/models/_.js';
|
import type { FollowingsRepository, InstancesRepository, MiMeta } from '@/models/_.js';
|
||||||
import { AppLockService } from '@/core/AppLockService.js';
|
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
import { acquireChartInsertLock } from '@/misc/distributed-lock.js';
|
||||||
import Chart from '../core.js';
|
import Chart from '../core.js';
|
||||||
import { ChartLoggerService } from '../ChartLoggerService.js';
|
import { ChartLoggerService } from '../ChartLoggerService.js';
|
||||||
import { name, schema } from './entities/federation.js';
|
import { name, schema } from './entities/federation.js';
|
||||||
|
@ -26,16 +27,18 @@ export default class FederationChart extends Chart<typeof schema> { // eslint-di
|
||||||
@Inject(DI.meta)
|
@Inject(DI.meta)
|
||||||
private meta: MiMeta,
|
private meta: MiMeta,
|
||||||
|
|
||||||
|
@Inject(DI.redisForTimelines)
|
||||||
|
private redisForTimelines: Redis.Redis,
|
||||||
|
|
||||||
@Inject(DI.followingsRepository)
|
@Inject(DI.followingsRepository)
|
||||||
private followingsRepository: FollowingsRepository,
|
private followingsRepository: FollowingsRepository,
|
||||||
|
|
||||||
@Inject(DI.instancesRepository)
|
@Inject(DI.instancesRepository)
|
||||||
private instancesRepository: InstancesRepository,
|
private instancesRepository: InstancesRepository,
|
||||||
|
|
||||||
private appLockService: AppLockService,
|
|
||||||
private chartLoggerService: ChartLoggerService,
|
private chartLoggerService: ChartLoggerService,
|
||||||
) {
|
) {
|
||||||
super(db, (k) => appLockService.getChartInsertLock(k), chartLoggerService.logger, name, schema);
|
super(db, (k) => acquireChartInsertLock(redisForTimelines, k), chartLoggerService.logger, name, schema);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async tickMajor(): Promise<Partial<KVs<typeof schema>>> {
|
protected async tickMajor(): Promise<Partial<KVs<typeof schema>>> {
|
||||||
|
|
|
@ -5,13 +5,14 @@
|
||||||
|
|
||||||
import { Injectable, Inject } from '@nestjs/common';
|
import { Injectable, Inject } from '@nestjs/common';
|
||||||
import { DataSource } from 'typeorm';
|
import { DataSource } from 'typeorm';
|
||||||
|
import * as Redis from 'ioredis';
|
||||||
import type { DriveFilesRepository, FollowingsRepository, UsersRepository, NotesRepository } from '@/models/_.js';
|
import type { DriveFilesRepository, FollowingsRepository, UsersRepository, NotesRepository } from '@/models/_.js';
|
||||||
import type { MiDriveFile } from '@/models/DriveFile.js';
|
import type { MiDriveFile } from '@/models/DriveFile.js';
|
||||||
import type { MiNote } from '@/models/Note.js';
|
import type { MiNote } from '@/models/Note.js';
|
||||||
import { AppLockService } from '@/core/AppLockService.js';
|
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { UtilityService } from '@/core/UtilityService.js';
|
import { UtilityService } from '@/core/UtilityService.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
import { acquireChartInsertLock } from '@/misc/distributed-lock.js';
|
||||||
import Chart from '../core.js';
|
import Chart from '../core.js';
|
||||||
import { ChartLoggerService } from '../ChartLoggerService.js';
|
import { ChartLoggerService } from '../ChartLoggerService.js';
|
||||||
import { name, schema } from './entities/instance.js';
|
import { name, schema } from './entities/instance.js';
|
||||||
|
@ -26,6 +27,9 @@ export default class InstanceChart extends Chart<typeof schema> { // eslint-disa
|
||||||
@Inject(DI.db)
|
@Inject(DI.db)
|
||||||
private db: DataSource,
|
private db: DataSource,
|
||||||
|
|
||||||
|
@Inject(DI.redisForTimelines)
|
||||||
|
private redisForTimelines: Redis.Redis,
|
||||||
|
|
||||||
@Inject(DI.usersRepository)
|
@Inject(DI.usersRepository)
|
||||||
private usersRepository: UsersRepository,
|
private usersRepository: UsersRepository,
|
||||||
|
|
||||||
|
@ -39,10 +43,9 @@ export default class InstanceChart extends Chart<typeof schema> { // eslint-disa
|
||||||
private followingsRepository: FollowingsRepository,
|
private followingsRepository: FollowingsRepository,
|
||||||
|
|
||||||
private utilityService: UtilityService,
|
private utilityService: UtilityService,
|
||||||
private appLockService: AppLockService,
|
|
||||||
private chartLoggerService: ChartLoggerService,
|
private chartLoggerService: ChartLoggerService,
|
||||||
) {
|
) {
|
||||||
super(db, (k) => appLockService.getChartInsertLock(k), chartLoggerService.logger, name, schema, true);
|
super(db, (k) => acquireChartInsertLock(redisForTimelines, k), chartLoggerService.logger, name, schema, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async tickMajor(group: string): Promise<Partial<KVs<typeof schema>>> {
|
protected async tickMajor(group: string): Promise<Partial<KVs<typeof schema>>> {
|
||||||
|
|
|
@ -5,11 +5,12 @@
|
||||||
|
|
||||||
import { Injectable, Inject } from '@nestjs/common';
|
import { Injectable, Inject } from '@nestjs/common';
|
||||||
import { Not, IsNull, DataSource } from 'typeorm';
|
import { Not, IsNull, DataSource } from 'typeorm';
|
||||||
|
import * as Redis from 'ioredis';
|
||||||
import type { NotesRepository } from '@/models/_.js';
|
import type { NotesRepository } from '@/models/_.js';
|
||||||
import type { MiNote } from '@/models/Note.js';
|
import type { MiNote } from '@/models/Note.js';
|
||||||
import { AppLockService } from '@/core/AppLockService.js';
|
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
import { acquireChartInsertLock } from '@/misc/distributed-lock.js';
|
||||||
import Chart from '../core.js';
|
import Chart from '../core.js';
|
||||||
import { ChartLoggerService } from '../ChartLoggerService.js';
|
import { ChartLoggerService } from '../ChartLoggerService.js';
|
||||||
import { name, schema } from './entities/notes.js';
|
import { name, schema } from './entities/notes.js';
|
||||||
|
@ -24,13 +25,15 @@ export default class NotesChart extends Chart<typeof schema> { // eslint-disable
|
||||||
@Inject(DI.db)
|
@Inject(DI.db)
|
||||||
private db: DataSource,
|
private db: DataSource,
|
||||||
|
|
||||||
|
@Inject(DI.redisForTimelines)
|
||||||
|
private redisForTimelines: Redis.Redis,
|
||||||
|
|
||||||
@Inject(DI.notesRepository)
|
@Inject(DI.notesRepository)
|
||||||
private notesRepository: NotesRepository,
|
private notesRepository: NotesRepository,
|
||||||
|
|
||||||
private appLockService: AppLockService,
|
|
||||||
private chartLoggerService: ChartLoggerService,
|
private chartLoggerService: ChartLoggerService,
|
||||||
) {
|
) {
|
||||||
super(db, (k) => appLockService.getChartInsertLock(k), chartLoggerService.logger, name, schema);
|
super(db, (k) => acquireChartInsertLock(redisForTimelines, k), chartLoggerService.logger, name, schema);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async tickMajor(): Promise<Partial<KVs<typeof schema>>> {
|
protected async tickMajor(): Promise<Partial<KVs<typeof schema>>> {
|
||||||
|
|
|
@ -5,12 +5,13 @@
|
||||||
|
|
||||||
import { Injectable, Inject } from '@nestjs/common';
|
import { Injectable, Inject } from '@nestjs/common';
|
||||||
import { DataSource } from 'typeorm';
|
import { DataSource } from 'typeorm';
|
||||||
|
import * as Redis from 'ioredis';
|
||||||
import type { DriveFilesRepository } from '@/models/_.js';
|
import type { DriveFilesRepository } from '@/models/_.js';
|
||||||
import type { MiDriveFile } from '@/models/DriveFile.js';
|
import type { MiDriveFile } from '@/models/DriveFile.js';
|
||||||
import { AppLockService } from '@/core/AppLockService.js';
|
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js';
|
import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
import { acquireChartInsertLock } from '@/misc/distributed-lock.js';
|
||||||
import Chart from '../core.js';
|
import Chart from '../core.js';
|
||||||
import { ChartLoggerService } from '../ChartLoggerService.js';
|
import { ChartLoggerService } from '../ChartLoggerService.js';
|
||||||
import { name, schema } from './entities/per-user-drive.js';
|
import { name, schema } from './entities/per-user-drive.js';
|
||||||
|
@ -25,14 +26,16 @@ export default class PerUserDriveChart extends Chart<typeof schema> { // eslint-
|
||||||
@Inject(DI.db)
|
@Inject(DI.db)
|
||||||
private db: DataSource,
|
private db: DataSource,
|
||||||
|
|
||||||
|
@Inject(DI.redisForTimelines)
|
||||||
|
private redisForTimelines: Redis.Redis,
|
||||||
|
|
||||||
@Inject(DI.driveFilesRepository)
|
@Inject(DI.driveFilesRepository)
|
||||||
private driveFilesRepository: DriveFilesRepository,
|
private driveFilesRepository: DriveFilesRepository,
|
||||||
|
|
||||||
private appLockService: AppLockService,
|
|
||||||
private driveFileEntityService: DriveFileEntityService,
|
private driveFileEntityService: DriveFileEntityService,
|
||||||
private chartLoggerService: ChartLoggerService,
|
private chartLoggerService: ChartLoggerService,
|
||||||
) {
|
) {
|
||||||
super(db, (k) => appLockService.getChartInsertLock(k), chartLoggerService.logger, name, schema, true);
|
super(db, (k) => acquireChartInsertLock(redisForTimelines, k), chartLoggerService.logger, name, schema, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async tickMajor(group: string): Promise<Partial<KVs<typeof schema>>> {
|
protected async tickMajor(group: string): Promise<Partial<KVs<typeof schema>>> {
|
||||||
|
|
|
@ -5,12 +5,13 @@
|
||||||
|
|
||||||
import { Injectable, Inject } from '@nestjs/common';
|
import { Injectable, Inject } from '@nestjs/common';
|
||||||
import { Not, IsNull, DataSource } from 'typeorm';
|
import { Not, IsNull, DataSource } from 'typeorm';
|
||||||
|
import * as Redis from 'ioredis';
|
||||||
import type { MiUser } from '@/models/User.js';
|
import type { MiUser } from '@/models/User.js';
|
||||||
import { AppLockService } from '@/core/AppLockService.js';
|
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
import type { FollowingsRepository } from '@/models/_.js';
|
import type { FollowingsRepository } from '@/models/_.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
import { acquireChartInsertLock } from '@/misc/distributed-lock.js';
|
||||||
import Chart from '../core.js';
|
import Chart from '../core.js';
|
||||||
import { ChartLoggerService } from '../ChartLoggerService.js';
|
import { ChartLoggerService } from '../ChartLoggerService.js';
|
||||||
import { name, schema } from './entities/per-user-following.js';
|
import { name, schema } from './entities/per-user-following.js';
|
||||||
|
@ -25,14 +26,16 @@ export default class PerUserFollowingChart extends Chart<typeof schema> { // esl
|
||||||
@Inject(DI.db)
|
@Inject(DI.db)
|
||||||
private db: DataSource,
|
private db: DataSource,
|
||||||
|
|
||||||
|
@Inject(DI.redisForTimelines)
|
||||||
|
private redisForTimelines: Redis.Redis,
|
||||||
|
|
||||||
@Inject(DI.followingsRepository)
|
@Inject(DI.followingsRepository)
|
||||||
private followingsRepository: FollowingsRepository,
|
private followingsRepository: FollowingsRepository,
|
||||||
|
|
||||||
private appLockService: AppLockService,
|
|
||||||
private userEntityService: UserEntityService,
|
private userEntityService: UserEntityService,
|
||||||
private chartLoggerService: ChartLoggerService,
|
private chartLoggerService: ChartLoggerService,
|
||||||
) {
|
) {
|
||||||
super(db, (k) => appLockService.getChartInsertLock(k), chartLoggerService.logger, name, schema, true);
|
super(db, (k) => acquireChartInsertLock(redisForTimelines, k), chartLoggerService.logger, name, schema, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async tickMajor(group: string): Promise<Partial<KVs<typeof schema>>> {
|
protected async tickMajor(group: string): Promise<Partial<KVs<typeof schema>>> {
|
||||||
|
|
|
@ -5,12 +5,13 @@
|
||||||
|
|
||||||
import { Injectable, Inject } from '@nestjs/common';
|
import { Injectable, Inject } from '@nestjs/common';
|
||||||
import { DataSource } from 'typeorm';
|
import { DataSource } from 'typeorm';
|
||||||
|
import * as Redis from 'ioredis';
|
||||||
import type { MiUser } from '@/models/User.js';
|
import type { MiUser } from '@/models/User.js';
|
||||||
import type { MiNote } from '@/models/Note.js';
|
import type { MiNote } from '@/models/Note.js';
|
||||||
import { AppLockService } from '@/core/AppLockService.js';
|
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import type { NotesRepository } from '@/models/_.js';
|
import type { NotesRepository } from '@/models/_.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
import { acquireChartInsertLock } from '@/misc/distributed-lock.js';
|
||||||
import Chart from '../core.js';
|
import Chart from '../core.js';
|
||||||
import { ChartLoggerService } from '../ChartLoggerService.js';
|
import { ChartLoggerService } from '../ChartLoggerService.js';
|
||||||
import { name, schema } from './entities/per-user-notes.js';
|
import { name, schema } from './entities/per-user-notes.js';
|
||||||
|
@ -25,13 +26,15 @@ export default class PerUserNotesChart extends Chart<typeof schema> { // eslint-
|
||||||
@Inject(DI.db)
|
@Inject(DI.db)
|
||||||
private db: DataSource,
|
private db: DataSource,
|
||||||
|
|
||||||
|
@Inject(DI.redisForTimelines)
|
||||||
|
private redisForTimelines: Redis.Redis,
|
||||||
|
|
||||||
@Inject(DI.notesRepository)
|
@Inject(DI.notesRepository)
|
||||||
private notesRepository: NotesRepository,
|
private notesRepository: NotesRepository,
|
||||||
|
|
||||||
private appLockService: AppLockService,
|
|
||||||
private chartLoggerService: ChartLoggerService,
|
private chartLoggerService: ChartLoggerService,
|
||||||
) {
|
) {
|
||||||
super(db, (k) => appLockService.getChartInsertLock(k), chartLoggerService.logger, name, schema, true);
|
super(db, (k) => acquireChartInsertLock(redisForTimelines, k), chartLoggerService.logger, name, schema, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async tickMajor(group: string): Promise<Partial<KVs<typeof schema>>> {
|
protected async tickMajor(group: string): Promise<Partial<KVs<typeof schema>>> {
|
||||||
|
|
|
@ -5,10 +5,11 @@
|
||||||
|
|
||||||
import { Injectable, Inject } from '@nestjs/common';
|
import { Injectable, Inject } from '@nestjs/common';
|
||||||
import { DataSource } from 'typeorm';
|
import { DataSource } from 'typeorm';
|
||||||
|
import * as Redis from 'ioredis';
|
||||||
import type { MiUser } from '@/models/User.js';
|
import type { MiUser } from '@/models/User.js';
|
||||||
import { AppLockService } from '@/core/AppLockService.js';
|
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
import { acquireChartInsertLock } from '@/misc/distributed-lock.js';
|
||||||
import Chart from '../core.js';
|
import Chart from '../core.js';
|
||||||
import { ChartLoggerService } from '../ChartLoggerService.js';
|
import { ChartLoggerService } from '../ChartLoggerService.js';
|
||||||
import { name, schema } from './entities/per-user-pv.js';
|
import { name, schema } from './entities/per-user-pv.js';
|
||||||
|
@ -23,10 +24,12 @@ export default class PerUserPvChart extends Chart<typeof schema> { // eslint-dis
|
||||||
@Inject(DI.db)
|
@Inject(DI.db)
|
||||||
private db: DataSource,
|
private db: DataSource,
|
||||||
|
|
||||||
private appLockService: AppLockService,
|
@Inject(DI.redisForTimelines)
|
||||||
|
private redisForTimelines: Redis.Redis,
|
||||||
|
|
||||||
private chartLoggerService: ChartLoggerService,
|
private chartLoggerService: ChartLoggerService,
|
||||||
) {
|
) {
|
||||||
super(db, (k) => appLockService.getChartInsertLock(k), chartLoggerService.logger, name, schema, true);
|
super(db, (k) => acquireChartInsertLock(redisForTimelines, k), chartLoggerService.logger, name, schema, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async tickMajor(): Promise<Partial<KVs<typeof schema>>> {
|
protected async tickMajor(): Promise<Partial<KVs<typeof schema>>> {
|
||||||
|
|
|
@ -5,12 +5,13 @@
|
||||||
|
|
||||||
import { Injectable, Inject } from '@nestjs/common';
|
import { Injectable, Inject } from '@nestjs/common';
|
||||||
import { DataSource } from 'typeorm';
|
import { DataSource } from 'typeorm';
|
||||||
|
import * as Redis from 'ioredis';
|
||||||
import type { MiUser } from '@/models/User.js';
|
import type { MiUser } from '@/models/User.js';
|
||||||
import type { MiNote } from '@/models/Note.js';
|
import type { MiNote } from '@/models/Note.js';
|
||||||
import { AppLockService } from '@/core/AppLockService.js';
|
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
import { acquireChartInsertLock } from '@/misc/distributed-lock.js';
|
||||||
import Chart from '../core.js';
|
import Chart from '../core.js';
|
||||||
import { ChartLoggerService } from '../ChartLoggerService.js';
|
import { ChartLoggerService } from '../ChartLoggerService.js';
|
||||||
import { name, schema } from './entities/per-user-reactions.js';
|
import { name, schema } from './entities/per-user-reactions.js';
|
||||||
|
@ -25,11 +26,13 @@ export default class PerUserReactionsChart extends Chart<typeof schema> { // esl
|
||||||
@Inject(DI.db)
|
@Inject(DI.db)
|
||||||
private db: DataSource,
|
private db: DataSource,
|
||||||
|
|
||||||
private appLockService: AppLockService,
|
@Inject(DI.redisForTimelines)
|
||||||
|
private redisForTimelines: Redis.Redis,
|
||||||
|
|
||||||
private userEntityService: UserEntityService,
|
private userEntityService: UserEntityService,
|
||||||
private chartLoggerService: ChartLoggerService,
|
private chartLoggerService: ChartLoggerService,
|
||||||
) {
|
) {
|
||||||
super(db, (k) => appLockService.getChartInsertLock(k), chartLoggerService.logger, name, schema, true);
|
super(db, (k) => acquireChartInsertLock(redisForTimelines, k), chartLoggerService.logger, name, schema, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async tickMajor(group: string): Promise<Partial<KVs<typeof schema>>> {
|
protected async tickMajor(group: string): Promise<Partial<KVs<typeof schema>>> {
|
||||||
|
|
|
@ -5,10 +5,11 @@
|
||||||
|
|
||||||
import { Injectable, Inject } from '@nestjs/common';
|
import { Injectable, Inject } from '@nestjs/common';
|
||||||
import { DataSource } from 'typeorm';
|
import { DataSource } from 'typeorm';
|
||||||
import { AppLockService } from '@/core/AppLockService.js';
|
import * as Redis from 'ioredis';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import Logger from '@/logger.js';
|
import Logger from '@/logger.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
import { acquireChartInsertLock } from '@/misc/distributed-lock.js';
|
||||||
import Chart from '../core.js';
|
import Chart from '../core.js';
|
||||||
import { name, schema } from './entities/test-grouped.js';
|
import { name, schema } from './entities/test-grouped.js';
|
||||||
import type { KVs } from '../core.js';
|
import type { KVs } from '../core.js';
|
||||||
|
@ -24,10 +25,12 @@ export default class TestGroupedChart extends Chart<typeof schema> { // eslint-d
|
||||||
@Inject(DI.db)
|
@Inject(DI.db)
|
||||||
private db: DataSource,
|
private db: DataSource,
|
||||||
|
|
||||||
private appLockService: AppLockService,
|
@Inject(DI.redisForTimelines)
|
||||||
|
private redisForTimelines: Redis.Redis,
|
||||||
|
|
||||||
logger: Logger,
|
logger: Logger,
|
||||||
) {
|
) {
|
||||||
super(db, (k) => appLockService.getChartInsertLock(k), logger, name, schema, true);
|
super(db, (k) => acquireChartInsertLock(redisForTimelines, k), logger, name, schema, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async tickMajor(group: string): Promise<Partial<KVs<typeof schema>>> {
|
protected async tickMajor(group: string): Promise<Partial<KVs<typeof schema>>> {
|
||||||
|
|
|
@ -5,10 +5,11 @@
|
||||||
|
|
||||||
import { Injectable, Inject } from '@nestjs/common';
|
import { Injectable, Inject } from '@nestjs/common';
|
||||||
import { DataSource } from 'typeorm';
|
import { DataSource } from 'typeorm';
|
||||||
import { AppLockService } from '@/core/AppLockService.js';
|
import * as Redis from 'ioredis';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import Logger from '@/logger.js';
|
import Logger from '@/logger.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
import { acquireChartInsertLock } from '@/misc/distributed-lock.js';
|
||||||
import Chart from '../core.js';
|
import Chart from '../core.js';
|
||||||
import { name, schema } from './entities/test-intersection.js';
|
import { name, schema } from './entities/test-intersection.js';
|
||||||
import type { KVs } from '../core.js';
|
import type { KVs } from '../core.js';
|
||||||
|
@ -22,10 +23,12 @@ export default class TestIntersectionChart extends Chart<typeof schema> { // esl
|
||||||
@Inject(DI.db)
|
@Inject(DI.db)
|
||||||
private db: DataSource,
|
private db: DataSource,
|
||||||
|
|
||||||
private appLockService: AppLockService,
|
@Inject(DI.redisForTimelines)
|
||||||
|
private redisForTimelines: Redis.Redis,
|
||||||
|
|
||||||
logger: Logger,
|
logger: Logger,
|
||||||
) {
|
) {
|
||||||
super(db, (k) => appLockService.getChartInsertLock(k), logger, name, schema);
|
super(db, (k) => acquireChartInsertLock(redisForTimelines, k), logger, name, schema);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async tickMajor(): Promise<Partial<KVs<typeof schema>>> {
|
protected async tickMajor(): Promise<Partial<KVs<typeof schema>>> {
|
||||||
|
|
|
@ -5,10 +5,11 @@
|
||||||
|
|
||||||
import { Injectable, Inject } from '@nestjs/common';
|
import { Injectable, Inject } from '@nestjs/common';
|
||||||
import { DataSource } from 'typeorm';
|
import { DataSource } from 'typeorm';
|
||||||
import { AppLockService } from '@/core/AppLockService.js';
|
import * as Redis from 'ioredis';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import Logger from '@/logger.js';
|
import Logger from '@/logger.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
import { acquireChartInsertLock } from '@/misc/distributed-lock.js';
|
||||||
import Chart from '../core.js';
|
import Chart from '../core.js';
|
||||||
import { name, schema } from './entities/test-unique.js';
|
import { name, schema } from './entities/test-unique.js';
|
||||||
import type { KVs } from '../core.js';
|
import type { KVs } from '../core.js';
|
||||||
|
@ -22,10 +23,12 @@ export default class TestUniqueChart extends Chart<typeof schema> { // eslint-di
|
||||||
@Inject(DI.db)
|
@Inject(DI.db)
|
||||||
private db: DataSource,
|
private db: DataSource,
|
||||||
|
|
||||||
private appLockService: AppLockService,
|
@Inject(DI.redisForTimelines)
|
||||||
|
private redisForTimelines: Redis.Redis,
|
||||||
|
|
||||||
logger: Logger,
|
logger: Logger,
|
||||||
) {
|
) {
|
||||||
super(db, (k) => appLockService.getChartInsertLock(k), logger, name, schema);
|
super(db, (k) => acquireChartInsertLock(redisForTimelines, k), logger, name, schema);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async tickMajor(): Promise<Partial<KVs<typeof schema>>> {
|
protected async tickMajor(): Promise<Partial<KVs<typeof schema>>> {
|
||||||
|
|
|
@ -5,10 +5,11 @@
|
||||||
|
|
||||||
import { Injectable, Inject } from '@nestjs/common';
|
import { Injectable, Inject } from '@nestjs/common';
|
||||||
import { DataSource } from 'typeorm';
|
import { DataSource } from 'typeorm';
|
||||||
import { AppLockService } from '@/core/AppLockService.js';
|
import * as Redis from 'ioredis';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import Logger from '@/logger.js';
|
import Logger from '@/logger.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
import { acquireChartInsertLock } from '@/misc/distributed-lock.js';
|
||||||
import Chart from '../core.js';
|
import Chart from '../core.js';
|
||||||
import { name, schema } from './entities/test.js';
|
import { name, schema } from './entities/test.js';
|
||||||
import type { KVs } from '../core.js';
|
import type { KVs } from '../core.js';
|
||||||
|
@ -24,10 +25,12 @@ export default class TestChart extends Chart<typeof schema> { // eslint-disable-
|
||||||
@Inject(DI.db)
|
@Inject(DI.db)
|
||||||
private db: DataSource,
|
private db: DataSource,
|
||||||
|
|
||||||
private appLockService: AppLockService,
|
@Inject(DI.redisForTimelines)
|
||||||
|
private redisForTimelines: Redis.Redis,
|
||||||
|
|
||||||
logger: Logger,
|
logger: Logger,
|
||||||
) {
|
) {
|
||||||
super(db, (k) => appLockService.getChartInsertLock(k), logger, name, schema);
|
super(db, (k) => acquireChartInsertLock(redisForTimelines, k), logger, name, schema);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async tickMajor(): Promise<Partial<KVs<typeof schema>>> {
|
protected async tickMajor(): Promise<Partial<KVs<typeof schema>>> {
|
||||||
|
|
|
@ -5,12 +5,13 @@
|
||||||
|
|
||||||
import { Injectable, Inject } from '@nestjs/common';
|
import { Injectable, Inject } from '@nestjs/common';
|
||||||
import { Not, IsNull, DataSource } from 'typeorm';
|
import { Not, IsNull, DataSource } from 'typeorm';
|
||||||
|
import * as Redis from 'ioredis';
|
||||||
import type { MiUser } from '@/models/User.js';
|
import type { MiUser } from '@/models/User.js';
|
||||||
import { AppLockService } from '@/core/AppLockService.js';
|
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
import type { UsersRepository } from '@/models/_.js';
|
import type { UsersRepository } from '@/models/_.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
import { acquireChartInsertLock } from '@/misc/distributed-lock.js';
|
||||||
import Chart from '../core.js';
|
import Chart from '../core.js';
|
||||||
import { ChartLoggerService } from '../ChartLoggerService.js';
|
import { ChartLoggerService } from '../ChartLoggerService.js';
|
||||||
import { name, schema } from './entities/users.js';
|
import { name, schema } from './entities/users.js';
|
||||||
|
@ -25,14 +26,16 @@ export default class UsersChart extends Chart<typeof schema> { // eslint-disable
|
||||||
@Inject(DI.db)
|
@Inject(DI.db)
|
||||||
private db: DataSource,
|
private db: DataSource,
|
||||||
|
|
||||||
|
@Inject(DI.redisForTimelines)
|
||||||
|
private redisForTimelines: Redis.Redis,
|
||||||
|
|
||||||
@Inject(DI.usersRepository)
|
@Inject(DI.usersRepository)
|
||||||
private usersRepository: UsersRepository,
|
private usersRepository: UsersRepository,
|
||||||
|
|
||||||
private appLockService: AppLockService,
|
|
||||||
private userEntityService: UserEntityService,
|
private userEntityService: UserEntityService,
|
||||||
private chartLoggerService: ChartLoggerService,
|
private chartLoggerService: ChartLoggerService,
|
||||||
) {
|
) {
|
||||||
super(db, (k) => appLockService.getChartInsertLock(k), chartLoggerService.logger, name, schema);
|
super(db, (k) => acquireChartInsertLock(redisForTimelines, k), chartLoggerService.logger, name, schema);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async tickMajor(): Promise<Partial<KVs<typeof schema>>> {
|
protected async tickMajor(): Promise<Partial<KVs<typeof schema>>> {
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
import * as Redis from 'ioredis';
|
||||||
|
|
||||||
|
export async function acquireDistributedLock(
|
||||||
|
redis: Redis.Redis,
|
||||||
|
name: string,
|
||||||
|
timeout: number,
|
||||||
|
maxRetries: number,
|
||||||
|
retryInterval: number,
|
||||||
|
): Promise<() => Promise<void>> {
|
||||||
|
const lockKey = `lock:${name}`;
|
||||||
|
const identifier = Math.random().toString(36).slice(2);
|
||||||
|
|
||||||
|
let retries = 0;
|
||||||
|
while (retries < maxRetries) {
|
||||||
|
const result = await redis.set(lockKey, identifier, 'PX', timeout, 'NX');
|
||||||
|
if (result === 'OK') {
|
||||||
|
return async () => {
|
||||||
|
const currentIdentifier = await redis.get(lockKey);
|
||||||
|
if (currentIdentifier === identifier) {
|
||||||
|
await redis.del(lockKey);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
await new Promise(resolve => setTimeout(resolve, retryInterval));
|
||||||
|
retries++;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error(`Failed to acquire lock ${name}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function acquireApObjectLock(
|
||||||
|
redis: Redis.Redis,
|
||||||
|
uri: string,
|
||||||
|
): Promise<() => Promise<void>> {
|
||||||
|
return acquireDistributedLock(redis, `ap-object:${uri}`, 30 * 1000, 600, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function acquireChartInsertLock(
|
||||||
|
redis: Redis.Redis,
|
||||||
|
name: string,
|
||||||
|
): Promise<() => Promise<void>> {
|
||||||
|
return acquireDistributedLock(redis, `chart-insert:${name}`, 30 * 1000, 120, 500);
|
||||||
|
}
|
|
@ -9,6 +9,7 @@ import * as assert from 'assert';
|
||||||
import { jest } from '@jest/globals';
|
import { jest } from '@jest/globals';
|
||||||
import * as lolex from '@sinonjs/fake-timers';
|
import * as lolex from '@sinonjs/fake-timers';
|
||||||
import { DataSource } from 'typeorm';
|
import { DataSource } from 'typeorm';
|
||||||
|
import * as Redis from 'ioredis';
|
||||||
import TestChart from '@/core/chart/charts/test.js';
|
import TestChart from '@/core/chart/charts/test.js';
|
||||||
import TestGroupedChart from '@/core/chart/charts/test-grouped.js';
|
import TestGroupedChart from '@/core/chart/charts/test-grouped.js';
|
||||||
import TestUniqueChart from '@/core/chart/charts/test-unique.js';
|
import TestUniqueChart from '@/core/chart/charts/test-unique.js';
|
||||||
|
@ -18,16 +19,16 @@ import { entity as TestGroupedChartEntity } from '@/core/chart/charts/entities/t
|
||||||
import { entity as TestUniqueChartEntity } from '@/core/chart/charts/entities/test-unique.js';
|
import { entity as TestUniqueChartEntity } from '@/core/chart/charts/entities/test-unique.js';
|
||||||
import { entity as TestIntersectionChartEntity } from '@/core/chart/charts/entities/test-intersection.js';
|
import { entity as TestIntersectionChartEntity } from '@/core/chart/charts/entities/test-intersection.js';
|
||||||
import { loadConfig } from '@/config.js';
|
import { loadConfig } from '@/config.js';
|
||||||
import type { AppLockService } from '@/core/AppLockService.js';
|
|
||||||
import Logger from '@/logger.js';
|
import Logger from '@/logger.js';
|
||||||
|
|
||||||
describe('Chart', () => {
|
describe('Chart', () => {
|
||||||
const config = loadConfig();
|
const config = loadConfig();
|
||||||
const appLockService = {
|
|
||||||
getChartInsertLock: () => () => Promise.resolve(() => {}),
|
|
||||||
} as unknown as jest.Mocked<AppLockService>;
|
|
||||||
|
|
||||||
let db: DataSource | undefined;
|
let db: DataSource | undefined;
|
||||||
|
let redisForTimelines = {
|
||||||
|
set: () => Promise.resolve('OK'),
|
||||||
|
get: () => Promise.resolve(null),
|
||||||
|
} as unknown as jest.Mocked<Redis.Redis>;
|
||||||
|
|
||||||
let testChart: TestChart;
|
let testChart: TestChart;
|
||||||
let testGroupedChart: TestGroupedChart;
|
let testGroupedChart: TestGroupedChart;
|
||||||
|
@ -64,10 +65,10 @@ describe('Chart', () => {
|
||||||
await db.initialize();
|
await db.initialize();
|
||||||
|
|
||||||
const logger = new Logger('chart'); // TODO: モックにする
|
const logger = new Logger('chart'); // TODO: モックにする
|
||||||
testChart = new TestChart(db, appLockService, logger);
|
testChart = new TestChart(db, redisForTimelines, logger);
|
||||||
testGroupedChart = new TestGroupedChart(db, appLockService, logger);
|
testGroupedChart = new TestGroupedChart(db, redisForTimelines, logger);
|
||||||
testUniqueChart = new TestUniqueChart(db, appLockService, logger);
|
testUniqueChart = new TestUniqueChart(db, redisForTimelines, logger);
|
||||||
testIntersectionChart = new TestIntersectionChart(db, appLockService, logger);
|
testIntersectionChart = new TestIntersectionChart(db, redisForTimelines, logger);
|
||||||
|
|
||||||
clock = lolex.install({
|
clock = lolex.install({
|
||||||
now: new Date(Date.UTC(2000, 0, 1, 0, 0, 0)),
|
now: new Date(Date.UTC(2000, 0, 1, 0, 0, 0)),
|
||||||
|
|
|
@ -369,9 +369,6 @@ importers:
|
||||||
redis-info:
|
redis-info:
|
||||||
specifier: 3.1.0
|
specifier: 3.1.0
|
||||||
version: 3.1.0
|
version: 3.1.0
|
||||||
redis-lock:
|
|
||||||
specifier: 1.0.0
|
|
||||||
version: 1.0.0
|
|
||||||
reflect-metadata:
|
reflect-metadata:
|
||||||
specifier: 0.2.2
|
specifier: 0.2.2
|
||||||
version: 0.2.2
|
version: 0.2.2
|
||||||
|
@ -9160,10 +9157,6 @@ packages:
|
||||||
redis-info@3.1.0:
|
redis-info@3.1.0:
|
||||||
resolution: {integrity: sha512-ER4L9Sh/vm63DkIE0bkSjxluQlioBiBgf5w1UuldaW/3vPcecdljVDisZhmnCMvsxHNiARTTDDHGg9cGwTfrKg==}
|
resolution: {integrity: sha512-ER4L9Sh/vm63DkIE0bkSjxluQlioBiBgf5w1UuldaW/3vPcecdljVDisZhmnCMvsxHNiARTTDDHGg9cGwTfrKg==}
|
||||||
|
|
||||||
redis-lock@1.0.0:
|
|
||||||
resolution: {integrity: sha512-zfI+Il36jXwRT/W8SBsG132Bc2yp3tMuf3KTGjSzXimadI17NEGBvb/KrDkCuAC2hzVxW5uR5ns/rxuqiWeV3Q==}
|
|
||||||
engines: {node: '>=12'}
|
|
||||||
|
|
||||||
redis-parser@3.0.0:
|
redis-parser@3.0.0:
|
||||||
resolution: {integrity: sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==}
|
resolution: {integrity: sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
|
@ -20217,8 +20210,6 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
lodash: 4.17.21
|
lodash: 4.17.21
|
||||||
|
|
||||||
redis-lock@1.0.0: {}
|
|
||||||
|
|
||||||
redis-parser@3.0.0:
|
redis-parser@3.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
redis-errors: 1.2.0
|
redis-errors: 1.2.0
|
||||||
|
|
Loading…
Reference in New Issue