feat: podpora high-availability a multi-replica nasazení
- Socket.io Redis adapter pro sdílený stav přes repliky - graceful shutdown serveru - WATCH/MULTI v updateData pro race-condition-safe aktualizace - lease mechanismus pro push reminder (zabrání duplicitnímu odesílání) - k8s/ manifesty pro testovací kind cluster - Dockerfile: opraven EXPOSE port na 3001 - .gitignore: ignorovány Claude pracovní soubory
This commit is contained in:
+25
-5
@@ -1,12 +1,15 @@
|
||||
import { DefaultEventsMap, Server } from "socket.io";
|
||||
import { createAdapter } from "@socket.io/redis-adapter";
|
||||
import { createClient } from "redis";
|
||||
|
||||
let io: Server<DefaultEventsMap, DefaultEventsMap, DefaultEventsMap, any>;
|
||||
let pubClient: ReturnType<typeof createClient>;
|
||||
let subClient: ReturnType<typeof createClient>;
|
||||
|
||||
export const initWebsocket = (server: any) => {
|
||||
io = new Server(server, {
|
||||
cors: {
|
||||
origin: "*",
|
||||
},
|
||||
cors: { origin: "*" },
|
||||
transports: ["websocket"],
|
||||
});
|
||||
io.on("connection", (socket) => {
|
||||
console.log(`New client connected: ${socket.id}`);
|
||||
@@ -26,7 +29,24 @@ export const initWebsocket = (server: any) => {
|
||||
});
|
||||
});
|
||||
return io;
|
||||
}
|
||||
};
|
||||
|
||||
/** Připojí Redis adapter pro cross-pod broadcasting. Volat až po inicializaci Redis klienta. */
|
||||
export const initRedisAdapter = async () => {
|
||||
const HOST = process.env.REDIS_HOST ?? 'localhost';
|
||||
const PORT = process.env.REDIS_PORT ?? 6379;
|
||||
const url = `redis://${HOST}:${PORT}`;
|
||||
pubClient = createClient({ url }) as ReturnType<typeof createClient>;
|
||||
subClient = pubClient.duplicate();
|
||||
await Promise.all([pubClient.connect(), subClient.connect()]);
|
||||
io.adapter(createAdapter(pubClient as any, subClient as any));
|
||||
console.log('Socket.io: Redis adapter connected');
|
||||
};
|
||||
|
||||
/** Zavře pub/sub Redis klienty adaptéru při graceful shutdown. */
|
||||
export const shutdownWebsocketClients = async () => {
|
||||
await Promise.allSettled([pubClient?.quit(), subClient?.quit()]);
|
||||
};
|
||||
|
||||
export const getWebsocket = () => io;
|
||||
|
||||
@@ -34,4 +54,4 @@ export const getWebsocket = () => io;
|
||||
export const emitToUser = (login: string, event: string, data: unknown) => {
|
||||
if (!io) return;
|
||||
io.to(`user:${login}`).emit(event, data);
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user