Skip to content

Commit 49a6197

Browse files
committed
cleanup code
1 parent 175b728 commit 49a6197

File tree

12 files changed

+189
-98
lines changed

12 files changed

+189
-98
lines changed

apps/sim/app/api/workflows/[id]/deployments/[version]/revert/route.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,10 @@ export async function POST(
9797
const socketServerUrl = env.SOCKET_SERVER_URL || 'http://localhost:3002'
9898
await fetch(`${socketServerUrl}/api/workflow-reverted`, {
9999
method: 'POST',
100-
headers: { 'Content-Type': 'application/json' },
100+
headers: {
101+
'Content-Type': 'application/json',
102+
'x-api-key': env.INTERNAL_API_SECRET,
103+
},
101104
body: JSON.stringify({ workflowId: id, timestamp: Date.now() }),
102105
})
103106
} catch (e) {

apps/sim/app/api/workflows/[id]/route.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,10 @@ export async function DELETE(
361361
const socketUrl = env.SOCKET_SERVER_URL || 'http://localhost:3002'
362362
const socketResponse = await fetch(`${socketUrl}/api/workflow-deleted`, {
363363
method: 'POST',
364-
headers: { 'Content-Type': 'application/json' },
364+
headers: {
365+
'Content-Type': 'application/json',
366+
'x-api-key': env.INTERNAL_API_SECRET,
367+
},
365368
body: JSON.stringify({ workflowId }),
366369
})
367370

apps/sim/app/api/workflows/[id]/state/route.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,10 @@ export async function PUT(request: NextRequest, { params }: { params: Promise<{
254254
const socketUrl = env.SOCKET_SERVER_URL || 'http://localhost:3002'
255255
const notifyResponse = await fetch(`${socketUrl}/api/workflow-updated`, {
256256
method: 'POST',
257-
headers: { 'Content-Type': 'application/json' },
257+
headers: {
258+
'Content-Type': 'application/json',
259+
'x-api-key': env.INTERNAL_API_SECRET,
260+
},
258261
body: JSON.stringify({ workflowId }),
259262
})
260263

apps/sim/app/workspace/providers/socket-provider.tsx

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,11 @@ export function SocketProvider({ children, user }: SocketProviderProps) {
322322
// Handle join workflow success - confirms room membership with presence list
323323
socketInstance.on('join-workflow-success', ({ workflowId, presenceUsers }) => {
324324
isRejoiningRef.current = false
325+
// Ignore stale success responses from previous navigation
326+
if (workflowId !== urlWorkflowIdRef.current) {
327+
logger.debug(`Ignoring stale join-workflow-success for ${workflowId}`)
328+
return
329+
}
325330
setCurrentWorkflowId(workflowId)
326331
setPresenceUsers(presenceUsers || [])
327332
logger.info(`Successfully joined workflow room: ${workflowId}`, {
@@ -516,7 +521,11 @@ export function SocketProvider({ children, user }: SocketProviderProps) {
516521
logger.info('Received workflow state from server')
517522

518523
if (workflowData?.state) {
519-
await rehydrateWorkflowStores(workflowData.id, workflowData.state, 'workflow-state')
524+
try {
525+
await rehydrateWorkflowStores(workflowData.id, workflowData.state, 'workflow-state')
526+
} catch (error) {
527+
logger.error('Error rehydrating workflow state:', error)
528+
}
520529
}
521530
})
522531

@@ -598,10 +607,13 @@ export function SocketProvider({ children, user }: SocketProviderProps) {
598607
const leaveWorkflow = useCallback(() => {
599608
if (socket && currentWorkflowId) {
600609
logger.info(`Leaving workflow: ${currentWorkflowId}`)
601-
try {
602-
const { useOperationQueueStore } = require('@/stores/operation-queue/store')
603-
useOperationQueueStore.getState().cancelOperationsForWorkflow(currentWorkflowId)
604-
} catch {}
610+
import('@/stores/operation-queue/store')
611+
.then(({ useOperationQueueStore }) => {
612+
useOperationQueueStore.getState().cancelOperationsForWorkflow(currentWorkflowId)
613+
})
614+
.catch((error) => {
615+
logger.warn('Failed to cancel operations for workflow:', error)
616+
})
605617
socket.emit('leave-workflow')
606618
setCurrentWorkflowId(null)
607619
setPresenceUsers([])

apps/sim/socket/config/socket.ts

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@ import { getBaseUrl } from '@/lib/core/utils/urls'
99

1010
const logger = createLogger('SocketIOConfig')
1111

12+
/** Socket.IO ping timeout - how long to wait for pong before considering connection dead */
13+
const PING_TIMEOUT_MS = 60000
14+
/** Socket.IO ping interval - how often to send ping packets */
15+
const PING_INTERVAL_MS = 25000
16+
/** Maximum HTTP buffer size for Socket.IO messages */
17+
const MAX_HTTP_BUFFER_SIZE = 1e6
18+
1219
let adapterPubClient: RedisClientType | null = null
1320
let adapterSubClient: RedisClientType | null = null
1421

@@ -41,9 +48,9 @@ export async function createSocketIOServer(httpServer: HttpServer): Promise<Serv
4148
},
4249
transports: ['websocket', 'polling'],
4350
allowEIO3: true,
44-
pingTimeout: 60000,
45-
pingInterval: 25000,
46-
maxHttpBufferSize: 1e6,
51+
pingTimeout: PING_TIMEOUT_MS,
52+
pingInterval: PING_INTERVAL_MS,
53+
maxHttpBufferSize: MAX_HTTP_BUFFER_SIZE,
4754
cookie: {
4855
name: 'io',
4956
path: '/',
@@ -103,9 +110,9 @@ export async function createSocketIOServer(httpServer: HttpServer): Promise<Serv
103110
logger.info('Socket.IO server configured with:', {
104111
allowedOrigins: allowedOrigins.length,
105112
transports: ['websocket', 'polling'],
106-
pingTimeout: 60000,
107-
pingInterval: 25000,
108-
maxHttpBufferSize: 1e6,
113+
pingTimeout: PING_TIMEOUT_MS,
114+
pingInterval: PING_INTERVAL_MS,
115+
maxHttpBufferSize: MAX_HTTP_BUFFER_SIZE,
109116
cookieSecure: isProd,
110117
corsCredentials: true,
111118
redisAdapter: !!env.REDIS_URL,

apps/sim/socket/handlers/operations.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,28 @@ export function setupOperationsHandlers(socket: AuthenticatedSocket, roomManager
2323
const session = await roomManager.getUserSession(socket.id)
2424

2525
if (!workflowId || !session) {
26-
socket.emit('error', {
27-
type: 'NOT_JOINED',
28-
message: 'Not joined to any workflow',
26+
socket.emit('operation-forbidden', {
27+
type: 'SESSION_ERROR',
28+
message: 'Session expired, please rejoin workflow',
2929
})
30+
if (data?.operationId) {
31+
socket.emit('operation-failed', { operationId: data.operationId, error: 'Session expired' })
32+
}
3033
return
3134
}
3235

3336
const hasRoom = await roomManager.hasWorkflowRoom(workflowId)
3437
if (!hasRoom) {
35-
socket.emit('error', {
38+
socket.emit('operation-forbidden', {
3639
type: 'ROOM_NOT_FOUND',
3740
message: 'Workflow room not found',
3841
})
42+
if (data?.operationId) {
43+
socket.emit('operation-failed', {
44+
operationId: data.operationId,
45+
error: 'Workflow room not found',
46+
})
47+
}
3948
return
4049
}
4150

apps/sim/socket/handlers/subblocks.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ import type { IRoomManager } from '@/socket/rooms'
77

88
const logger = createLogger('SubblocksHandlers')
99

10+
/** Debounce interval for coalescing rapid subblock updates before persisting */
11+
const DEBOUNCE_INTERVAL_MS = 25
12+
1013
type PendingSubblock = {
1114
latest: { blockId: string; subblockId: string; value: any; timestamp: number }
1215
timeout: NodeJS.Timeout
@@ -22,7 +25,7 @@ const pendingSubblockUpdates = new Map<string, PendingSubblock>()
2225
* Removes the socket's operationIds from pending updates to prevent memory leaks.
2326
*/
2427
export function cleanupPendingSubblocksForSocket(socketId: string): void {
25-
for (const [key, pending] of pendingSubblockUpdates.entries()) {
28+
for (const [, pending] of pendingSubblockUpdates.entries()) {
2629
// Remove this socket's operation entries
2730
for (const [opId, sid] of pending.opToSocket.entries()) {
2831
if (sid === socketId) {
@@ -52,6 +55,9 @@ export function setupSubblocksHandlers(socket: AuthenticatedSocket, roomManager:
5255
type: 'SESSION_ERROR',
5356
message: 'Session expired, please rejoin workflow',
5457
})
58+
if (operationId) {
59+
socket.emit('operation-failed', { operationId, error: 'Session expired' })
60+
}
5561
return
5662
}
5763

@@ -79,7 +85,7 @@ export function setupSubblocksHandlers(socket: AuthenticatedSocket, roomManager:
7985
existing.timeout = setTimeout(async () => {
8086
await flushSubblockUpdate(workflowId, existing, roomManager)
8187
pendingSubblockUpdates.delete(debouncedKey)
82-
}, 25)
88+
}, DEBOUNCE_INTERVAL_MS)
8389
} else {
8490
const opToSocket = new Map<string, string>()
8591
if (operationId) opToSocket.set(operationId, socket.id)
@@ -89,7 +95,7 @@ export function setupSubblocksHandlers(socket: AuthenticatedSocket, roomManager:
8995
await flushSubblockUpdate(workflowId, pending, roomManager)
9096
pendingSubblockUpdates.delete(debouncedKey)
9197
}
92-
}, 25)
98+
}, DEBOUNCE_INTERVAL_MS)
9399
pendingSubblockUpdates.set(debouncedKey, {
94100
latest: { blockId, subblockId, value, timestamp },
95101
timeout,

apps/sim/socket/handlers/variables.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ import type { IRoomManager } from '@/socket/rooms'
77

88
const logger = createLogger('VariablesHandlers')
99

10+
/** Debounce interval for coalescing rapid variable updates before persisting */
11+
const DEBOUNCE_INTERVAL_MS = 25
12+
1013
type PendingVariable = {
1114
latest: { variableId: string; field: string; value: any; timestamp: number }
1215
timeout: NodeJS.Timeout
@@ -21,7 +24,7 @@ const pendingVariableUpdates = new Map<string, PendingVariable>()
2124
* Removes the socket's operationIds from pending updates to prevent memory leaks.
2225
*/
2326
export function cleanupPendingVariablesForSocket(socketId: string): void {
24-
for (const [key, pending] of pendingVariableUpdates.entries()) {
27+
for (const [, pending] of pendingVariableUpdates.entries()) {
2528
for (const [opId, sid] of pending.opToSocket.entries()) {
2629
if (sid === socketId) {
2730
pending.opToSocket.delete(opId)
@@ -48,6 +51,9 @@ export function setupVariablesHandlers(socket: AuthenticatedSocket, roomManager:
4851
type: 'SESSION_ERROR',
4952
message: 'Session expired, please rejoin workflow',
5053
})
54+
if (operationId) {
55+
socket.emit('operation-failed', { operationId, error: 'Session expired' })
56+
}
5157
return
5258
}
5359

@@ -74,7 +80,7 @@ export function setupVariablesHandlers(socket: AuthenticatedSocket, roomManager:
7480
existing.timeout = setTimeout(async () => {
7581
await flushVariableUpdate(workflowId, existing, roomManager)
7682
pendingVariableUpdates.delete(debouncedKey)
77-
}, 25)
83+
}, DEBOUNCE_INTERVAL_MS)
7884
} else {
7985
const opToSocket = new Map<string, string>()
8086
if (operationId) opToSocket.set(operationId, socket.id)
@@ -84,7 +90,7 @@ export function setupVariablesHandlers(socket: AuthenticatedSocket, roomManager:
8490
await flushVariableUpdate(workflowId, pending, roomManager)
8591
pendingVariableUpdates.delete(debouncedKey)
8692
}
87-
}, 25)
93+
}, DEBOUNCE_INTERVAL_MS)
8894
pendingVariableUpdates.set(debouncedKey, {
8995
latest: { variableId, field, value, timestamp },
9096
timeout,

apps/sim/socket/index.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ import { createHttpHandler } from '@/socket/routes/http'
1010

1111
const logger = createLogger('CollaborativeSocketServer')
1212

13+
/** Maximum time to wait for graceful shutdown before forcing exit */
14+
const SHUTDOWN_TIMEOUT_MS = 10000
15+
1316
async function createRoomManager(io: SocketIOServer): Promise<IRoomManager> {
1417
if (env.REDIS_URL) {
1518
logger.info('Initializing Redis-backed RoomManager for multi-pod support')
@@ -108,7 +111,7 @@ async function main() {
108111
setTimeout(() => {
109112
logger.error('Forced shutdown after timeout')
110113
process.exit(1)
111-
}, 10000)
114+
}, SHUTDOWN_TIMEOUT_MS)
112115
}
113116

114117
process.on('SIGINT', shutdown)

apps/sim/socket/middleware/auth.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export interface AuthenticatedSocket extends Socket {
2121
* Socket.IO authentication middleware.
2222
* Handles both anonymous mode (DISABLE_AUTH=true) and normal token-based auth.
2323
*/
24-
export async function authenticateSocket(socket: AuthenticatedSocket, next: any) {
24+
export async function authenticateSocket(socket: AuthenticatedSocket, next: (err?: Error) => void) {
2525
try {
2626
if (isAuthDisabled) {
2727
socket.userId = ANONYMOUS_USER_ID

0 commit comments

Comments
 (0)