perf(website/server): Make zlib operations asynchronous to prevent event loop blocking

Replace synchronous zlib.inflateSync/deflateSync with async alternatives to prevent blocking the event loop under high load.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Kazuki Yamada
2025-06-07 17:22:30 +09:00
parent 1affddbe88
commit 90989c6413
3 changed files with 13 additions and 9 deletions

View File

@@ -54,7 +54,7 @@ export async function processZipFile(
); );
// Check if the result is already cached // Check if the result is already cached
const cachedResult = cache.get(cacheKey); const cachedResult = await cache.get(cacheKey);
if (cachedResult) { if (cachedResult) {
return cachedResult; return cachedResult;
} }
@@ -123,7 +123,7 @@ export async function processZipFile(
}; };
// Save the result to cache // Save the result to cache
cache.set(cacheKey, packResultData); await cache.set(cacheKey, packResultData);
return packResultData; return packResultData;
} catch (error) { } catch (error) {

View File

@@ -35,7 +35,7 @@ export async function processRemoteRepo(
const cacheKey = generateCacheKey(validatedData.url, validatedData.format, validatedData.options, 'url'); const cacheKey = generateCacheKey(validatedData.url, validatedData.format, validatedData.options, 'url');
// Check if the result is already cached // Check if the result is already cached
const cachedResult = cache.get(cacheKey); const cachedResult = await cache.get(cacheKey);
if (cachedResult) { if (cachedResult) {
return cachedResult; return cachedResult;
} }
@@ -100,7 +100,7 @@ export async function processRemoteRepo(
}; };
// Save the result to cache // Save the result to cache
cache.set(cacheKey, packResultData); await cache.set(cacheKey, packResultData);
return packResultData; return packResultData;
} catch (error) { } catch (error) {

View File

@@ -1,6 +1,10 @@
import * as zlib from 'node:zlib'; import * as zlib from 'node:zlib';
import { promisify } from 'node:util';
import type { PackOptions } from '../types.js'; import type { PackOptions } from '../types.js';
const inflateAsync = promisify(zlib.inflate);
const deflateAsync = promisify(zlib.deflate);
interface CacheEntry<T> { interface CacheEntry<T> {
value: Uint8Array; // Compressed data value: Uint8Array; // Compressed data
timestamp: number; timestamp: number;
@@ -17,7 +21,7 @@ export class RequestCache<T> {
setInterval(() => this.cleanup(), ttlInSeconds * 1000); setInterval(() => this.cleanup(), ttlInSeconds * 1000);
} }
get(key: string): T | undefined { async get(key: string): Promise<T | undefined> {
const entry = this.cache.get(key); const entry = this.cache.get(key);
if (!entry) { if (!entry) {
return undefined; return undefined;
@@ -31,8 +35,8 @@ export class RequestCache<T> {
try { try {
// Decompress and return the data // Decompress and return the data
const decompressedData = zlib.inflateSync(entry.value).toString('utf8'); const decompressedData = await inflateAsync(entry.value);
return JSON.parse(decompressedData); return JSON.parse(decompressedData.toString('utf8'));
} catch (error) { } catch (error) {
console.error('Error decompressing cache entry:', error); console.error('Error decompressing cache entry:', error);
this.cache.delete(key); this.cache.delete(key);
@@ -40,11 +44,11 @@ export class RequestCache<T> {
} }
} }
set(key: string, value: T): void { async set(key: string, value: T): Promise<void> {
try { try {
// Convert data to JSON string and compress // Convert data to JSON string and compress
const jsonString = JSON.stringify(value); const jsonString = JSON.stringify(value);
const compressedData = zlib.deflateSync(Buffer.from(jsonString, 'utf8')); const compressedData = await deflateAsync(Buffer.from(jsonString, 'utf8'));
this.cache.set(key, { this.cache.set(key, {
value: compressedData, value: compressedData,