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">
|
||||
const subtexts = {
|
||||
queued: "대기 중",
|
||||
"generation-pending": "준비 중",
|
||||
generating: "생성하는 중",
|
||||
"upload-pending": "업로드를 기다리는 중",
|
||||
|
||||
@@ -8,6 +8,7 @@ import type { FileThumbnailUploadRequest } from "$lib/server/schemas";
|
||||
import { requestFileDownload } from "$lib/services/file";
|
||||
|
||||
export type GenerationStatus =
|
||||
| "queued"
|
||||
| "generation-pending"
|
||||
| "generating"
|
||||
| "upload-pending"
|
||||
@@ -23,6 +24,10 @@ interface File {
|
||||
|
||||
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({
|
||||
files: [] as File[],
|
||||
});
|
||||
@@ -86,18 +91,66 @@ const requestThumbnailUpload = limitFunction(
|
||||
{ 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) => {
|
||||
let status = workingFiles.get(fileInfo.id);
|
||||
if (status && get(status) !== "error") return;
|
||||
|
||||
status = writable("generation-pending");
|
||||
workingFiles.set(fileInfo.id, status);
|
||||
persistentStates.files = persistentStates.files.map((file) =>
|
||||
file.id === fileInfo.id ? { ...file, status } : file,
|
||||
);
|
||||
if (workingFiles.values().some((status) => get(status) !== "error")) {
|
||||
await enqueue(status, fileInfo);
|
||||
}
|
||||
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 {
|
||||
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(
|
||||
status,
|
||||
file,
|
||||
@@ -110,5 +163,8 @@ export const requestThumbnailGeneration = async (fileInfo: FileInfo) => {
|
||||
}
|
||||
} catch {
|
||||
status.set("error");
|
||||
} finally {
|
||||
memoryUsage -= fileSize;
|
||||
queue.shift()?.();
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user