diff --git a/packages/backend/src/misc/app-lock.ts b/packages/backend/src/misc/app-lock.ts index 0891d021f4..198310c884 100644 --- a/packages/backend/src/misc/app-lock.ts +++ b/packages/backend/src/misc/app-lock.ts @@ -12,29 +12,38 @@ const retryDelay = 100; * @param timeout Lock timeout (ms), The timeout releases previous lock. * @returns Unlock function */ -export async function getApLock(uri: string, timeout = 30 * 1000) { +export async function getApLock( + uri: string, + timeout = 30 * 1000, +): Promise { const lock = new Mutex(redisClient, `ap-object:${uri}`, { lockTimeout: timeout, retryInterval: retryDelay, }); await lock.acquire(); + return lock; } export async function getFetchInstanceMetadataLock( host: string, timeout = 30 * 1000, -) { +): Promise { const lock = new Mutex(redisClient, `instance:${host}`, { lockTimeout: timeout, retryInterval: retryDelay, }); await lock.acquire(); + return lock; } -export async function getChartInsertLock(lockKey: string, timeout = 30 * 1000) { +export async function getChartInsertLock( + lockKey: string, + timeout = 30 * 1000, +): Promise { const lock = new Mutex(redisClient, `chart-insert:${lockKey}`, { lockTimeout: timeout, retryInterval: retryDelay, }); await lock.acquire(); + return lock; } diff --git a/packages/backend/src/remote/activitypub/kernel/announce/note.ts b/packages/backend/src/remote/activitypub/kernel/announce/note.ts index acf8c84360..50b59932cf 100644 --- a/packages/backend/src/remote/activitypub/kernel/announce/note.ts +++ b/packages/backend/src/remote/activitypub/kernel/announce/note.ts @@ -32,6 +32,8 @@ export default async function ( // Interrupt if you block the announcement destination if (await shouldBlockInstance(extractDbHost(uri))) return; + const lock = await getApLock(uri); + try { // Check if something with the same URI is already registered const exist = await fetchNote(uri); @@ -78,6 +80,6 @@ export default async function ( uri, }); } finally { - await getApLock(uri); + await lock.release(); } } diff --git a/packages/backend/src/remote/activitypub/kernel/create/note.ts b/packages/backend/src/remote/activitypub/kernel/create/note.ts index fe4cc0906f..92b0ffb1e0 100644 --- a/packages/backend/src/remote/activitypub/kernel/create/note.ts +++ b/packages/backend/src/remote/activitypub/kernel/create/note.ts @@ -31,6 +31,8 @@ export default async function ( } } + const lock = await getApLock(uri); + try { const exist = await fetchNote(note); if (exist) return "skip: note exists"; @@ -44,6 +46,6 @@ export default async function ( throw e; } } finally { - await getApLock(uri); + await lock.release(); } } diff --git a/packages/backend/src/remote/activitypub/kernel/delete/note.ts b/packages/backend/src/remote/activitypub/kernel/delete/note.ts index b37f7d25f9..4656480c2f 100644 --- a/packages/backend/src/remote/activitypub/kernel/delete/note.ts +++ b/packages/backend/src/remote/activitypub/kernel/delete/note.ts @@ -13,6 +13,8 @@ export default async function ( ): Promise { logger.info(`Deleting the Note: ${uri}`); + const lock = await getApLock(uri); + try { const dbResolver = new DbResolver(); const note = await dbResolver.getNoteFromApId(uri); @@ -37,6 +39,6 @@ export default async function ( await deleteNode(actor, note); return "ok: note deleted"; } finally { - await getApLock(uri); + await lock.release(); } } diff --git a/packages/backend/src/remote/activitypub/models/note.ts b/packages/backend/src/remote/activitypub/models/note.ts index 8e305d7195..12b2c19972 100644 --- a/packages/backend/src/remote/activitypub/models/note.ts +++ b/packages/backend/src/remote/activitypub/models/note.ts @@ -415,6 +415,8 @@ export async function resolveNote( `host ${extractDbHost(uri)} is blocked`, ); + const lock = await getApLock(uri); + try { //#region Returns if already registered with this server const exist = await fetchNote(uri); @@ -437,7 +439,7 @@ export async function resolveNote( // Since the attached Note Object may be disguised, always specify the uri and fetch it from the server. return await createNote(uri, resolver, true); } finally { - await getApLock(uri); + await lock.release(); } } diff --git a/packages/backend/src/services/chart/core.ts b/packages/backend/src/services/chart/core.ts index 2fce4de91c..d7a524d488 100644 --- a/packages/backend/src/services/chart/core.ts +++ b/packages/backend/src/services/chart/core.ts @@ -430,6 +430,7 @@ export default abstract class Chart { ? `${this.name}:${date}:${span}:${group}` : `${this.name}:${date}:${span}`; + const lock = await getChartInsertLock(lockKey); try { // ロック内でもう1回チェックする const currentLog = (await repository.findOneBy({ @@ -465,7 +466,7 @@ export default abstract class Chart { return log; } finally { - await getChartInsertLock(lockKey); + await lock.release(); } } diff --git a/packages/backend/src/services/fetch-instance-metadata.ts b/packages/backend/src/services/fetch-instance-metadata.ts index 9a5a9bb080..23a6a703ec 100644 --- a/packages/backend/src/services/fetch-instance-metadata.ts +++ b/packages/backend/src/services/fetch-instance-metadata.ts @@ -15,6 +15,8 @@ export async function fetchInstanceMetadata( instance: Instance, force = false, ): Promise { + const lock = await getFetchInstanceMetadataLock(instance.host); + if (!force) { const _instance = await Instances.findOneBy({ host: instance.host }); const now = Date.now(); @@ -22,7 +24,7 @@ export async function fetchInstanceMetadata( _instance?.infoUpdatedAt && now - _instance.infoUpdatedAt.getTime() < 1000 * 60 * 60 * 24 ) { - await getFetchInstanceMetadataLock(instance.host); + await lock.release(); return; } } @@ -78,7 +80,7 @@ export async function fetchInstanceMetadata( } catch (e) { logger.error(`Failed to update metadata of ${instance.host}: ${e}`); } finally { - await getFetchInstanceMetadataLock(instance.host); + await lock.release(); } }