mirror of
https://github.com/kmc7468/arkvault.git
synced 2025-12-12 21:08:46 +00:00
썸네일을 일괄적으로 생성하는 경우 발생하던 Out of Memory 문제 해결
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
<script module lang="ts">
|
<script module lang="ts">
|
||||||
const subtexts = {
|
const subtexts = {
|
||||||
|
queued: "대기 중",
|
||||||
"generation-pending": "준비 중",
|
"generation-pending": "준비 중",
|
||||||
generating: "생성하는 중",
|
generating: "생성하는 중",
|
||||||
"upload-pending": "업로드를 기다리는 중",
|
"upload-pending": "업로드를 기다리는 중",
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import type { FileThumbnailUploadRequest } from "$lib/server/schemas";
|
|||||||
import { requestFileDownload } from "$lib/services/file";
|
import { requestFileDownload } from "$lib/services/file";
|
||||||
|
|
||||||
export type GenerationStatus =
|
export type GenerationStatus =
|
||||||
|
| "queued"
|
||||||
| "generation-pending"
|
| "generation-pending"
|
||||||
| "generating"
|
| "generating"
|
||||||
| "upload-pending"
|
| "upload-pending"
|
||||||
@@ -23,6 +24,10 @@ interface File {
|
|||||||
|
|
||||||
const workingFiles = new Map<number, Writable<GenerationStatus>>();
|
const workingFiles = new Map<number, Writable<GenerationStatus>>();
|
||||||
|
|
||||||
|
let queue: (() => void)[] = [];
|
||||||
|
let memoryUsage = 0;
|
||||||
|
const MEMORY_LIMIT = 100 * 1024 * 1024; // 100 MiB
|
||||||
|
|
||||||
export const persistentStates = $state({
|
export const persistentStates = $state({
|
||||||
files: [] as File[],
|
files: [] as File[],
|
||||||
});
|
});
|
||||||
@@ -86,18 +91,66 @@ const requestThumbnailUpload = limitFunction(
|
|||||||
{ concurrency: 4 },
|
{ concurrency: 4 },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const enqueue = async (
|
||||||
|
status: Writable<GenerationStatus> | undefined,
|
||||||
|
fileInfo: FileInfo,
|
||||||
|
priority = false,
|
||||||
|
) => {
|
||||||
|
if (status) {
|
||||||
|
status.set("queued");
|
||||||
|
} else {
|
||||||
|
status = writable("queued");
|
||||||
|
workingFiles.set(fileInfo.id, status);
|
||||||
|
persistentStates.files = persistentStates.files.map((file) =>
|
||||||
|
file.id === fileInfo.id ? { ...file, status } : file,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let resolver;
|
||||||
|
const promise = new Promise((resolve) => {
|
||||||
|
resolver = resolve;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (priority) {
|
||||||
|
queue = [() => resolver!(), ...queue];
|
||||||
|
} else {
|
||||||
|
queue.push(resolver!);
|
||||||
|
}
|
||||||
|
|
||||||
|
await promise;
|
||||||
|
};
|
||||||
|
|
||||||
export const requestThumbnailGeneration = async (fileInfo: FileInfo) => {
|
export const requestThumbnailGeneration = async (fileInfo: FileInfo) => {
|
||||||
let status = workingFiles.get(fileInfo.id);
|
let status = workingFiles.get(fileInfo.id);
|
||||||
if (status && get(status) !== "error") return;
|
if (status && get(status) !== "error") return;
|
||||||
|
|
||||||
status = writable("generation-pending");
|
if (workingFiles.values().some((status) => get(status) !== "error")) {
|
||||||
workingFiles.set(fileInfo.id, status);
|
await enqueue(status, fileInfo);
|
||||||
persistentStates.files = persistentStates.files.map((file) =>
|
}
|
||||||
file.id === fileInfo.id ? { ...file, status } : file,
|
while (memoryUsage >= MEMORY_LIMIT) {
|
||||||
);
|
await enqueue(status, fileInfo, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status) {
|
||||||
|
status.set("generation-pending");
|
||||||
|
} else {
|
||||||
|
status = writable("generation-pending");
|
||||||
|
workingFiles.set(fileInfo.id, status);
|
||||||
|
persistentStates.files = persistentStates.files.map((file) =>
|
||||||
|
file.id === fileInfo.id ? { ...file, status } : file,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let fileSize = 0;
|
||||||
try {
|
try {
|
||||||
const file = await requestFileDownload(fileInfo.id, fileInfo.contentIv!, fileInfo.dataKey!);
|
const file = await requestFileDownload(fileInfo.id, fileInfo.contentIv!, fileInfo.dataKey!);
|
||||||
|
fileSize = file.byteLength;
|
||||||
|
|
||||||
|
memoryUsage += fileSize;
|
||||||
|
if (memoryUsage < MEMORY_LIMIT) {
|
||||||
|
queue.shift()?.();
|
||||||
|
}
|
||||||
|
|
||||||
const thumbnail = await generateThumbnail(
|
const thumbnail = await generateThumbnail(
|
||||||
status,
|
status,
|
||||||
file,
|
file,
|
||||||
@@ -110,5 +163,8 @@ export const requestThumbnailGeneration = async (fileInfo: FileInfo) => {
|
|||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
status.set("error");
|
status.set("error");
|
||||||
|
} finally {
|
||||||
|
memoryUsage -= fileSize;
|
||||||
|
queue.shift()?.();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user