feature/IO-2967-Better-Refetch-Handling - Implementation
Signed-off-by: Dave Richer <dave@imexsystems.ca>
This commit is contained in:
@@ -23,6 +23,9 @@ function ProductionBoardKanbanContainer({ bodyshop, currentUser, subscriptionTyp
|
|||||||
const fired = useRef(false);
|
const fired = useRef(false);
|
||||||
const client = useApolloClient();
|
const client = useApolloClient();
|
||||||
const { socket } = useContext(SocketContext); // Get the socket from context
|
const { socket } = useContext(SocketContext); // Get the socket from context
|
||||||
|
const reconnectTimeout = useRef(null); // To store the reconnect timeout
|
||||||
|
const disconnectTime = useRef(null); // To track disconnection time
|
||||||
|
const acceptableReconnectTime = 2000; // 2 seconds threshold
|
||||||
|
|
||||||
const {
|
const {
|
||||||
treatments: { Websocket_Production }
|
treatments: { Websocket_Production }
|
||||||
@@ -126,19 +129,44 @@ function ProductionBoardKanbanContainer({ bodyshop, currentUser, subscriptionTyp
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleReconnect = () => {
|
const handleDisconnect = () => {
|
||||||
//If we were disconnected from the board, we missed stuff. We need to refresh it entirely.
|
// Capture the disconnection time
|
||||||
if (refetch) refetch();
|
disconnectTime.current = Date.now();
|
||||||
};
|
};
|
||||||
// Listen for 'job-changed' events
|
|
||||||
|
const handleReconnect = () => {
|
||||||
|
const reconnectTime = Date.now();
|
||||||
|
const disconnectionDuration = reconnectTime - disconnectTime.current;
|
||||||
|
|
||||||
|
// Only refetch if disconnection was longer than the acceptable reconnect time
|
||||||
|
if (disconnectionDuration >= acceptableReconnectTime) {
|
||||||
|
if (!reconnectTimeout.current) {
|
||||||
|
reconnectTimeout.current = setTimeout(() => {
|
||||||
|
const randomDelay = Math.floor(Math.random() * (30000 - 10000 + 1)) + 10000; // Random delay between 10 and 30 seconds
|
||||||
|
setTimeout(() => {
|
||||||
|
if (refetch) refetch().catch((err) => console.error(`Issue `));
|
||||||
|
reconnectTimeout.current = null; // Clear the timeout reference after refetch
|
||||||
|
}, randomDelay);
|
||||||
|
}, acceptableReconnectTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Listen for 'job-changed', 'disconnect', and 'connect' events
|
||||||
socket.on("production-job-updated", handleJobUpdates);
|
socket.on("production-job-updated", handleJobUpdates);
|
||||||
socket.on("reconnect", handleReconnect);
|
socket.on("disconnect", handleDisconnect);
|
||||||
|
socket.on("connect", handleReconnect);
|
||||||
|
|
||||||
// Clean up on unmount or when dependencies change
|
// Clean up on unmount or when dependencies change
|
||||||
return () => {
|
return () => {
|
||||||
socket.off("production-job-updated", handleJobUpdates);
|
socket.off("production-job-updated", handleJobUpdates);
|
||||||
socket.off("reconnect", handleReconnect);
|
socket.off("disconnect", handleDisconnect);
|
||||||
|
socket.off("connect", handleReconnect);
|
||||||
|
if (reconnectTimeout.current) {
|
||||||
|
clearTimeout(reconnectTimeout.current);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}, [subscriptionEnabled, socket, bodyshop, data, client, refetch]);
|
}, [subscriptionEnabled, socket, bodyshop, client, refetch]);
|
||||||
|
|
||||||
const filteredAssociationSettings = useMemo(() => {
|
const filteredAssociationSettings = useMemo(() => {
|
||||||
return associationSettings?.associations[0] || null;
|
return associationSettings?.associations[0] || null;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useApolloClient, useQuery, useSubscription } from "@apollo/client";
|
import { useApolloClient, useQuery, useSubscription } from "@apollo/client";
|
||||||
import React, { useContext, useEffect, useState } from "react";
|
import React, { useContext, useEffect, useState, useRef } from "react";
|
||||||
import {
|
import {
|
||||||
QUERY_EXACT_JOB_IN_PRODUCTION,
|
QUERY_EXACT_JOB_IN_PRODUCTION,
|
||||||
QUERY_EXACT_JOBS_IN_PRODUCTION,
|
QUERY_EXACT_JOBS_IN_PRODUCTION,
|
||||||
@@ -16,6 +16,10 @@ export default function ProductionListTableContainer({ bodyshop, subscriptionTyp
|
|||||||
const client = useApolloClient();
|
const client = useApolloClient();
|
||||||
const { socket } = useContext(SocketContext);
|
const { socket } = useContext(SocketContext);
|
||||||
const [joblist, setJoblist] = useState([]);
|
const [joblist, setJoblist] = useState([]);
|
||||||
|
const reconnectTimeout = useRef(null); // To store the reconnect timeout
|
||||||
|
const disconnectTime = useRef(null); // To store the time of disconnection
|
||||||
|
|
||||||
|
const acceptableReconnectTime = 2000; // 2 seconds threshold
|
||||||
|
|
||||||
// Get Split treatment
|
// Get Split treatment
|
||||||
const {
|
const {
|
||||||
@@ -128,18 +132,47 @@ export default function ProductionListTableContainer({ bodyshop, subscriptionTyp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const handleReconnect = () => {
|
|
||||||
//If we were disconnected from the board, we missed stuff. We need to refresh it entirely.
|
const handleDisconnect = () => {
|
||||||
if (refetch) refetch();
|
// Capture the time when the disconnection happens
|
||||||
|
disconnectTime.current = Date.now();
|
||||||
};
|
};
|
||||||
// Listen for 'production-job-updated' events
|
|
||||||
|
const handleReconnect = () => {
|
||||||
|
// Calculate how long the disconnection lasted
|
||||||
|
const reconnectTime = Date.now();
|
||||||
|
const disconnectionDuration = reconnectTime - disconnectTime.current;
|
||||||
|
|
||||||
|
// If disconnection lasted less than acceptable reconnect time, do nothing
|
||||||
|
if (disconnectionDuration < acceptableReconnectTime) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Schedule a refetch with a random delay between 10 and 30 seconds
|
||||||
|
if (!reconnectTimeout.current) {
|
||||||
|
reconnectTimeout.current = setTimeout(() => {
|
||||||
|
const randomDelay = Math.floor(Math.random() * (30000 - 10000 + 1)) + 10000; // Random delay between 10 and 30 seconds
|
||||||
|
setTimeout(() => {
|
||||||
|
if (refetch) refetch();
|
||||||
|
reconnectTimeout.current = null; // Clear the timeout reference after refetch
|
||||||
|
}, randomDelay);
|
||||||
|
}, acceptableReconnectTime);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Listen for 'production-job-updated', 'disconnect', and 'connect' events
|
||||||
socket.on("production-job-updated", handleJobUpdates);
|
socket.on("production-job-updated", handleJobUpdates);
|
||||||
socket.on("reconnect", handleReconnect);
|
socket.on("disconnect", handleDisconnect);
|
||||||
|
socket.on("connect", handleReconnect);
|
||||||
|
|
||||||
// Clean up on unmount or when dependencies change
|
// Clean up on unmount or when dependencies change
|
||||||
return () => {
|
return () => {
|
||||||
socket.off("production-job-updated", handleJobUpdates);
|
socket.off("production-job-updated", handleJobUpdates);
|
||||||
socket.off("reconnect", handleReconnect);
|
socket.off("disconnect", handleDisconnect);
|
||||||
|
socket.off("connect", handleReconnect);
|
||||||
|
if (reconnectTimeout.current) {
|
||||||
|
clearTimeout(reconnectTimeout.current);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}, [subscriptionEnabled, socket, bodyshop, client, refetch]);
|
}, [subscriptionEnabled, socket, bodyshop, client, refetch]);
|
||||||
|
|
||||||
@@ -151,6 +184,7 @@ export default function ProductionListTableContainer({ bodyshop, subscriptionTyp
|
|||||||
fetchPolicy: "network-only"
|
fetchPolicy: "network-only"
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const getUpdatedJobsData = (jobIds) => {
|
const getUpdatedJobsData = (jobIds) => {
|
||||||
client.query({
|
client.query({
|
||||||
query: QUERY_EXACT_JOBS_IN_PRODUCTION,
|
query: QUERY_EXACT_JOBS_IN_PRODUCTION,
|
||||||
|
|||||||
@@ -30,52 +30,72 @@ const redisSocketEvents = (io, { addUserToRoom, getUsersInRoom, removeUserFromRo
|
|||||||
// Room management and broadcasting events
|
// Room management and broadcasting events
|
||||||
function registerRoomAndBroadcastEvents(socket) {
|
function registerRoomAndBroadcastEvents(socket) {
|
||||||
socket.on("join-bodyshop-room", async (bodyshopUUID) => {
|
socket.on("join-bodyshop-room", async (bodyshopUUID) => {
|
||||||
const room = getBodyshopRoom(bodyshopUUID);
|
try {
|
||||||
socket.join(room);
|
const room = getBodyshopRoom(bodyshopUUID);
|
||||||
await addUserToRoom(room, { uid: socket.user.uid, email: socket.user.email });
|
socket.join(room);
|
||||||
createLogEvent(socket, "DEBUG", `Client joined bodyshop room: ${bodyshopUUID}`);
|
await addUserToRoom(room, { uid: socket.user.uid, email: socket.user.email });
|
||||||
|
createLogEvent(socket, "DEBUG", `Client joined bodyshop room: ${bodyshopUUID}`);
|
||||||
|
|
||||||
// Notify all users in the room about the updated user list
|
// Notify all users in the room about the updated user list
|
||||||
const usersInRoom = await getUsersInRoom(bodyshopUUID);
|
const usersInRoom = await getUsersInRoom(room);
|
||||||
io.to(room).emit("room-users-updated", usersInRoom);
|
io.to(room).emit("room-users-updated", usersInRoom);
|
||||||
|
} catch (error) {
|
||||||
|
createLogEvent(socket, "ERROR", `Error joining room: ${error}`);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("leave-bodyshop-room", async (bodyshopUUID) => {
|
socket.on("leave-bodyshop-room", async (bodyshopUUID) => {
|
||||||
const room = getBodyshopRoom(bodyshopUUID);
|
try {
|
||||||
socket.leave(room);
|
const room = getBodyshopRoom(bodyshopUUID);
|
||||||
createLogEvent(socket, "DEBUG", `Client left bodyshop room: ${room}`);
|
socket.leave(room);
|
||||||
|
createLogEvent(socket, "DEBUG", `Client left bodyshop room: ${room}`);
|
||||||
|
} catch (error) {
|
||||||
|
createLogEvent(socket, "ERROR", `Error joining room: ${error}`);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("get-room-users", async (bodyshopUUID, callback) => {
|
socket.on("get-room-users", async (bodyshopUUID, callback) => {
|
||||||
const usersInRoom = await getUsersInRoom(getBodyshopRoom(bodyshopUUID));
|
try {
|
||||||
callback(usersInRoom);
|
const usersInRoom = await getUsersInRoom(getBodyshopRoom(bodyshopUUID));
|
||||||
|
callback(usersInRoom);
|
||||||
|
} catch (error) {
|
||||||
|
createLogEvent(socket, "ERROR", `Error getting room: ${error}`);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("broadcast-to-bodyshop", async (bodyshopUUID, message) => {
|
socket.on("broadcast-to-bodyshop", async (bodyshopUUID, message) => {
|
||||||
const room = getBodyshopRoom(bodyshopUUID);
|
try {
|
||||||
io.to(room).emit("bodyshop-message", message);
|
const room = getBodyshopRoom(bodyshopUUID);
|
||||||
createLogEvent(socket, "INFO", `Broadcast message to bodyshop ${room}`);
|
io.to(room).emit("bodyshop-message", message);
|
||||||
|
createLogEvent(socket, "INFO", `Broadcast message to bodyshop ${room}`);
|
||||||
|
} catch (error) {
|
||||||
|
createLogEvent(socket, "ERROR", `Error getting room: ${error}`);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("disconnect", async () => {
|
socket.on("disconnect", async () => {
|
||||||
createLogEvent(socket, "DEBUG", `User disconnected.`);
|
try {
|
||||||
|
createLogEvent(socket, "DEBUG", `User disconnected.`);
|
||||||
|
|
||||||
// Get all rooms the socket is part of
|
// Get all rooms the socket is part of
|
||||||
const rooms = Array.from(socket.rooms).filter((room) => room !== socket.id);
|
const rooms = Array.from(socket.rooms).filter((room) => room !== socket.id);
|
||||||
|
|
||||||
for (const bodyshopRoom of rooms) {
|
for (const bodyshopRoom of rooms) {
|
||||||
await removeUserFromRoom(bodyshopRoom, { uid: socket.user.uid, email: socket.user.email });
|
await removeUserFromRoom(bodyshopRoom, { uid: socket.user.uid, email: socket.user.email });
|
||||||
|
|
||||||
// Notify all users in the room about the updated user list
|
// Notify all users in the room about the updated user list
|
||||||
const usersInRoom = await getUsersInRoom(bodyshopRoom);
|
const usersInRoom = await getUsersInRoom(bodyshopRoom);
|
||||||
io.to(bodyshopRoom).emit("room-users-updated", usersInRoom);
|
io.to(bodyshopRoom).emit("room-users-updated", usersInRoom);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
createLogEvent(socket, "ERROR", `Error getting room: ${error}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register all socket events for a given socket connection
|
// Register all socket events for a given socket connection
|
||||||
function registerSocketEvents(socket) {
|
function registerSocketEvents(socket) {
|
||||||
createLogEvent(socket, "DEBUG", `Connected and Authenticated.`);
|
createLogEvent(socket, "DEBUG", `Registering RedisIO Socket Events.`);
|
||||||
|
|
||||||
// Register room and broadcasting events
|
// Register room and broadcasting events
|
||||||
registerRoomAndBroadcastEvents(socket);
|
registerRoomAndBroadcastEvents(socket);
|
||||||
|
|||||||
Reference in New Issue
Block a user