mirror of
https://github.com/ld3z/new-manga.git
synced 2026-11-09 20:33:44 -07:00
idk anymore...
This commit is contained in:
parent
24eeb93f68
commit
a5d10f26d5
2 changed files with 72 additions and 77 deletions
|
|
@ -7,7 +7,6 @@ export default defineConfig({
|
||||||
adapter: vercel({
|
adapter: vercel({
|
||||||
analytics: true,
|
analytics: true,
|
||||||
maxDuration: 60,
|
maxDuration: 60,
|
||||||
includeFiles: ['.env'],
|
|
||||||
}),
|
}),
|
||||||
image: {
|
image: {
|
||||||
remotePatterns: [{ protocol: "https" }],
|
remotePatterns: [{ protocol: "https" }],
|
||||||
|
|
|
||||||
146
src/lib/db.ts
146
src/lib/db.ts
|
|
@ -7,9 +7,16 @@ interface RedisNetworkError extends Error {
|
||||||
code?: string;
|
code?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Primary Redis configuration
|
// Primary Redis configuration - with more robust fallbacks and logging
|
||||||
const PRIMARY_REDIS_URL = import.meta.env.PRIMARY_REDIS_URL || process.env.PRIMARY_REDIS_URL || process.env.REDIS_URL;
|
const PRIMARY_REDIS_URL = import.meta.env.PRIMARY_REDIS_URL || process.env.PRIMARY_REDIS_URL || process.env.REDIS_URL;
|
||||||
|
|
||||||
|
// Log Redis URL status (without exposing sensitive data)
|
||||||
|
console.log(`Redis URLs status: Primary=${Boolean(PRIMARY_REDIS_URL)}`);
|
||||||
|
|
||||||
|
if (!PRIMARY_REDIS_URL) {
|
||||||
|
console.warn('WARNING: No Redis URL configured. Database functionality will not work properly.');
|
||||||
|
}
|
||||||
|
|
||||||
// Multiple replicas support
|
// Multiple replicas support
|
||||||
const REPLICA_URLS = [
|
const REPLICA_URLS = [
|
||||||
import.meta.env.REPLICA_REDIS_URL_1 || process.env.REPLICA_REDIS_URL_1 || import.meta.env.REPLICA_REDIS_URL || process.env.REPLICA_REDIS_URL,
|
import.meta.env.REPLICA_REDIS_URL_1 || process.env.REPLICA_REDIS_URL_1 || import.meta.env.REPLICA_REDIS_URL || process.env.REPLICA_REDIS_URL,
|
||||||
|
|
@ -17,6 +24,8 @@ const REPLICA_URLS = [
|
||||||
import.meta.env.REPLICA_REDIS_URL_3 || process.env.REPLICA_REDIS_URL_3,
|
import.meta.env.REPLICA_REDIS_URL_3 || process.env.REPLICA_REDIS_URL_3,
|
||||||
].filter(Boolean) as string[];
|
].filter(Boolean) as string[];
|
||||||
|
|
||||||
|
console.log(`Found ${REPLICA_URLS.length} Redis replica URLs`);
|
||||||
|
|
||||||
// Create a mapping of URLs to friendly names for logging
|
// Create a mapping of URLs to friendly names for logging
|
||||||
const redisInstanceNames = new Map<string, string>();
|
const redisInstanceNames = new Map<string, string>();
|
||||||
|
|
||||||
|
|
@ -94,11 +103,19 @@ export async function getRedisClient(): Promise<Redis> {
|
||||||
console.log('Running in Vercel environment - using optimized Redis connection strategy');
|
console.log('Running in Vercel environment - using optimized Redis connection strategy');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if Redis is configured
|
||||||
|
if (!PRIMARY_REDIS_URL && REPLICA_URLS.length === 0) {
|
||||||
|
throw new Error('No Redis URLs configured. Please check your environment variables in the Vercel dashboard.');
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Try primary first
|
// Try primary first
|
||||||
if (!primaryClient) {
|
if (!primaryClient) {
|
||||||
console.log('Creating new primary Redis client');
|
console.log('Creating new primary Redis client');
|
||||||
primaryClient = await createRedisClient(PRIMARY_REDIS_URL!);
|
if (!PRIMARY_REDIS_URL) {
|
||||||
|
throw new Error('Primary Redis URL is not set. Please check your environment variables.');
|
||||||
|
}
|
||||||
|
primaryClient = await createRedisClient(PRIMARY_REDIS_URL);
|
||||||
} else if (primaryClient.status !== 'ready') {
|
} else if (primaryClient.status !== 'ready') {
|
||||||
console.log('Primary Redis client not ready, reconnecting');
|
console.log('Primary Redis client not ready, reconnecting');
|
||||||
try {
|
try {
|
||||||
|
|
@ -106,7 +123,7 @@ export async function getRedisClient(): Promise<Redis> {
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Error disconnecting primary client:', e);
|
console.error('Error disconnecting primary client:', e);
|
||||||
}
|
}
|
||||||
primaryClient = await createRedisClient(PRIMARY_REDIS_URL!);
|
primaryClient = await createRedisClient(PRIMARY_REDIS_URL);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
@ -126,74 +143,20 @@ export async function getRedisClient(): Promise<Redis> {
|
||||||
console.error('Error connecting to primary Redis:', primaryError);
|
console.error('Error connecting to primary Redis:', primaryError);
|
||||||
|
|
||||||
// Special handling for Vercel ETIMEDOUT errors
|
// Special handling for Vercel ETIMEDOUT errors
|
||||||
if (IS_VERCEL && primaryError instanceof Error && primaryError.message.includes('ETIMEDOUT')) {
|
if (IS_VERCEL && primaryError instanceof Error) {
|
||||||
console.log('Encountered ETIMEDOUT in Vercel environment. Retrying with longer timeout...');
|
const errorMsg = primaryError.message;
|
||||||
try {
|
|
||||||
// Try one more time with increased timeout
|
|
||||||
const tempClient = new Redis(PRIMARY_REDIS_URL!, {
|
|
||||||
connectTimeout: 20000, // Increased timeout for last-ditch effort
|
|
||||||
retryStrategy: () => null // No retries for this attempt
|
|
||||||
});
|
|
||||||
|
|
||||||
// Wait for ready or error
|
if (errorMsg.includes('ETIMEDOUT')) {
|
||||||
await new Promise((resolve, reject) => {
|
console.log('Encountered ETIMEDOUT in Vercel environment. This is a common issue with Vercel serverless functions and Redis.');
|
||||||
const timeout = setTimeout(() => {
|
throw new Error('Redis connection timed out. Please ensure your Redis service allows connections from Vercel IP ranges. See Vercel documentation for IP ranges used by their serverless functions.');
|
||||||
tempClient.disconnect();
|
} else if (errorMsg.includes('ECONNREFUSED')) {
|
||||||
reject(new Error('Final connection attempt timed out'));
|
throw new Error('Redis connection refused. Please check if your Redis service is running and accessible from Vercel.');
|
||||||
}, 20000);
|
} else if (errorMsg.includes('ENOTFOUND')) {
|
||||||
|
throw new Error('Redis host not found. Please check your PRIMARY_REDIS_URL environment variable.');
|
||||||
tempClient.once('ready', () => {
|
|
||||||
clearTimeout(timeout);
|
|
||||||
resolve(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
tempClient.once('error', (err) => {
|
|
||||||
clearTimeout(timeout);
|
|
||||||
reject(err);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// If we get here, connection was successful
|
|
||||||
primaryClient = tempClient;
|
|
||||||
return tempClient;
|
|
||||||
} catch (finalError) {
|
|
||||||
console.error('Final Redis connection attempt failed:', finalError);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try connecting to any replica that might be available
|
throw primaryError;
|
||||||
for (const url of REPLICA_URLS) {
|
|
||||||
try {
|
|
||||||
const redisName = getRedisName(url);
|
|
||||||
console.log(`Trying to connect to ${redisName}...`);
|
|
||||||
const client = await createRedisClient(url);
|
|
||||||
|
|
||||||
client
|
|
||||||
.on('ready', () => console.log(`${redisName} connection ready`))
|
|
||||||
.on('error', (err: RedisNetworkError) => {
|
|
||||||
// Log more details for connection errors
|
|
||||||
if (err.code === 'ETIMEDOUT') {
|
|
||||||
console.error(`${redisName} connection timeout. This is common in serverless environments like Vercel. Check your network connectivity and Redis server availability.`);
|
|
||||||
} else if (err.code === 'ECONNREFUSED') {
|
|
||||||
console.error(`${redisName} connection refused. Ensure the Redis server is running and the URL is correct.`);
|
|
||||||
} else if (err.code === 'ENOTFOUND') {
|
|
||||||
console.error(`${redisName} host not found. Check your Redis URL environment variables.`);
|
|
||||||
} else {
|
|
||||||
console.error(`${redisName} error:`, err);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.on('reconnecting', () => console.log(`${redisName} reconnecting`))
|
|
||||||
.on('end', () => console.log(`${redisName} connection closed`));
|
|
||||||
|
|
||||||
replicaClients.set(url, client);
|
|
||||||
return client;
|
|
||||||
} catch (replicaError) {
|
|
||||||
console.error(`Failed to connect to ${getRedisName(url)}:`, replicaError);
|
|
||||||
// Continue to next replica
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error('All Redis connections failed');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -314,24 +277,57 @@ export async function warmChapterCache(slugs: string[], lang: string): Promise<v
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function storeFeedMapping(feedId: string, slugs: string[], lang: string): Promise<void> {
|
export async function storeFeedMapping(feedId: string, slugs: string[], lang: string): Promise<void> {
|
||||||
|
if (!feedId) throw new Error('Feed ID is required');
|
||||||
|
if (!Array.isArray(slugs) || slugs.length === 0) throw new Error('Slugs array is required and cannot be empty');
|
||||||
|
if (!lang) throw new Error('Language is required');
|
||||||
|
|
||||||
const mapping = {
|
const mapping = {
|
||||||
slugs,
|
slugs,
|
||||||
lang,
|
lang,
|
||||||
created_at: new Date().toISOString()
|
created_at: new Date().toISOString()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
console.log(`Attempting to store feed mapping with ID: ${feedId}, language: ${lang}, and ${slugs.length} slugs`);
|
||||||
|
|
||||||
|
// Check if Redis is configured
|
||||||
|
if (!PRIMARY_REDIS_URL && REPLICA_URLS.length === 0) {
|
||||||
|
console.error('No Redis URLs configured. Cannot store feed mapping.');
|
||||||
|
throw new Error('Database connection not configured. Please check your environment variables.');
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await writeToAllRedis(async (redis) => {
|
await writeToAllRedis(async (redis) => {
|
||||||
await redis.set(
|
console.log(`Writing feed mapping to Redis instance...`);
|
||||||
feedId,
|
|
||||||
JSON.stringify(mapping),
|
try {
|
||||||
'EX',
|
await redis.set(
|
||||||
DEFAULT_CACHE_TTL
|
feedId,
|
||||||
);
|
JSON.stringify(mapping),
|
||||||
|
'EX',
|
||||||
|
DEFAULT_CACHE_TTL
|
||||||
|
);
|
||||||
|
console.log(`Successfully stored feed mapping in Redis instance`);
|
||||||
|
} catch (redisError: any) {
|
||||||
|
console.error(`Redis set operation failed:`, redisError);
|
||||||
|
throw new Error(`Redis operation failed: ${redisError.message || 'Unknown Redis error'}`);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
} catch (error) {
|
|
||||||
|
console.log(`Feed mapping successfully stored with ID: ${feedId}`);
|
||||||
|
} catch (error: any) {
|
||||||
console.error('Error storing feed mapping:', error);
|
console.error('Error storing feed mapping:', error);
|
||||||
throw new Error('Failed to store feed mapping');
|
|
||||||
|
// Check for common connection issues
|
||||||
|
const errorMsg = error.message || '';
|
||||||
|
if (errorMsg.includes('ECONNREFUSED')) {
|
||||||
|
throw new Error('Unable to connect to the Redis database. Connection refused.');
|
||||||
|
} else if (errorMsg.includes('ETIMEDOUT')) {
|
||||||
|
throw new Error('Connection to Redis database timed out. This may be due to network issues or firewall settings.');
|
||||||
|
} else if (errorMsg.includes('ENOTFOUND')) {
|
||||||
|
throw new Error('Redis host not found. Please check your database URL configuration.');
|
||||||
|
} else {
|
||||||
|
throw new Error(`Failed to store feed mapping: ${errorMsg}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue