mirror of
https://github.com/RayLabsHQ/gitea-mirror.git
synced 2025-12-18 05:28:08 +03:00
feat: enhance SSE connection with reconnect logic and error handling
- Updated `useSSE` hook to include max reconnect attempts and exponential backoff for reconnections. - Improved error handling for SSE messages and connection errors. - Added connection status reset on successful connection. fix: improve SQLite database connection handling - Simplified database initialization and connection logic. - Ensured the database file is created if it doesn't exist. fix: enhance Redis client connection with retry strategy - Implemented exponential backoff for Redis connection retries. - Added event handlers for connection success and error handling. feat: improve SSE API endpoint with robust Redis connection management - Added connection retry logic for Redis in the SSE API. - Implemented heartbeat messages to keep the connection alive. - Enhanced error handling for Redis subscription and connection attempts.
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { z } from "zod";
|
||||
import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";
|
||||
import { Database } from "bun:sqlite";
|
||||
import { drizzle } from "drizzle-orm/bun-sqlite";
|
||||
import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import { configSchema } from "./schema";
|
||||
@@ -13,38 +13,45 @@ if (!fs.existsSync(dataDir)) {
|
||||
fs.mkdirSync(dataDir, { recursive: true });
|
||||
}
|
||||
|
||||
const dbUrl =
|
||||
process.env.DATABASE_URL || `file:${path.join(dataDir, "gitea-mirror.db")}`;
|
||||
const dbPath = path.join(dataDir, "gitea-mirror.db");
|
||||
|
||||
// Create a SQLite database instance using Bun's native driver
|
||||
// Create an empty database file if it doesn't exist
|
||||
if (!fs.existsSync(dbPath)) {
|
||||
fs.writeFileSync(dbPath, "");
|
||||
}
|
||||
|
||||
// Create SQLite database instance using Bun's native driver
|
||||
let sqlite: Database;
|
||||
try {
|
||||
// Create an empty database file if it doesn't exist
|
||||
if (!fs.existsSync(path.join(dataDir, "gitea-mirror.db"))) {
|
||||
fs.writeFileSync(path.join(dataDir, "gitea-mirror.db"), "");
|
||||
}
|
||||
sqlite = new Database(dbUrl);
|
||||
sqlite = new Database(dbPath);
|
||||
console.log("Successfully connected to SQLite database using Bun's native driver");
|
||||
} catch (error) {
|
||||
console.error("Error opening database:", error);
|
||||
throw error;
|
||||
}
|
||||
|
||||
// Simple async wrapper around Bun's SQLite API for compatibility
|
||||
// Create drizzle instance with the SQLite client
|
||||
export const db = drizzle({ client: sqlite });
|
||||
|
||||
// Simple async wrapper around SQLite API for compatibility
|
||||
// This maintains backward compatibility with existing code
|
||||
export const client = {
|
||||
async execute(sql: string, params?: any[]) {
|
||||
const stmt = sqlite.query(sql);
|
||||
if (/^\s*select/i.test(sql)) {
|
||||
const rows = stmt.all(params ?? []);
|
||||
return { rows } as { rows: any[] };
|
||||
try {
|
||||
const stmt = sqlite.query(sql);
|
||||
if (/^\s*select/i.test(sql)) {
|
||||
const rows = stmt.all(params ?? []);
|
||||
return { rows } as { rows: any[] };
|
||||
}
|
||||
stmt.run(params ?? []);
|
||||
return { rows: [] } as { rows: any[] };
|
||||
} catch (error) {
|
||||
console.error(`Error executing SQL: ${sql}`, error);
|
||||
throw error;
|
||||
}
|
||||
stmt.run(params ?? []);
|
||||
return { rows: [] } as { rows: any[] };
|
||||
},
|
||||
};
|
||||
|
||||
// Create a drizzle instance
|
||||
export const db = drizzle(sqlite);
|
||||
|
||||
// Define the tables
|
||||
export const users = sqliteTable("users", {
|
||||
id: text("id").primaryKey(),
|
||||
|
||||
@@ -2,22 +2,38 @@ import { RedisClient } from "bun";
|
||||
|
||||
// Connect to Redis using REDIS_URL environment variable or default to redis://redis:6379
|
||||
// This ensures we have a fallback URL when running with Docker Compose
|
||||
const redisUrl = process.env.REDIS_URL ?? "redis://redis:6379";
|
||||
const redisUrl = process.env.REDIS_URL ?? "redis://localhost:6379";
|
||||
|
||||
console.log(`Connecting to Redis at: ${redisUrl}`);
|
||||
|
||||
// Configure Redis client with connection options
|
||||
// Configure Redis client with connection options and retry logic
|
||||
function createClient() {
|
||||
return new RedisClient(redisUrl, {
|
||||
const client = new RedisClient(redisUrl, {
|
||||
autoReconnect: true,
|
||||
connectTimeout: 30000, // Increase timeout to 30 seconds
|
||||
retryStrategy: (attempt: number) => {
|
||||
// Exponential backoff with jitter
|
||||
const delay = Math.min(Math.pow(2, attempt) * 100, 10000);
|
||||
console.log(`Redis connection attempt ${attempt}, retrying in ${delay}ms`);
|
||||
return delay;
|
||||
},
|
||||
});
|
||||
|
||||
// Set up event handlers
|
||||
client.onconnect = () => console.log("Redis client connected successfully");
|
||||
client.onclose = (err: Error | null) => {
|
||||
if (err) {
|
||||
console.error("Redis connection error:", err);
|
||||
console.log("Redis will attempt to reconnect automatically");
|
||||
} else {
|
||||
console.log("Redis connection closed");
|
||||
}
|
||||
};
|
||||
|
||||
return client;
|
||||
}
|
||||
|
||||
// Create Redis clients with improved error handling
|
||||
export const redis = createClient();
|
||||
export const redisPublisher = createClient();
|
||||
export const redisSubscriber = createClient();
|
||||
|
||||
redis.onconnect = () => console.log("Connected to Redis server");
|
||||
redis.onclose = (err) => {
|
||||
if (err) console.error("Disconnected from Redis server:", err);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user