Skip to content

Commit cd8c357

Browse files
committed
fix(011): improve WebSocket sync and EKS configuration
- Replace optimistic updates with delayed refetch pattern to prevent race conditions - Add NEXT_PUBLIC_WEBSOCKET_URL build arg to frontend Dockerfile for runtime configuration - Upgrade EKS cluster version from 1.28 to 1.29 for latest features - Remove hardcoded availability zones, let eksctl auto-select for better flexibility Why: Optimistic updates were causing UI inconsistencies when WebSocket events arrived before database commits completed. The 500ms delay ensures data consistency. EKS 1.29 provides improved security and performance features.
1 parent 3cf4400 commit cd8c357

3 files changed

Lines changed: 17 additions & 51 deletions

File tree

frontend/Dockerfile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ WORKDIR /app
2424
COPY --from=deps /app/node_modules ./node_modules
2525
COPY . .
2626

27+
# Build arguments for Next.js public env vars
28+
ARG NEXT_PUBLIC_WEBSOCKET_URL
29+
ENV NEXT_PUBLIC_WEBSOCKET_URL=$NEXT_PUBLIC_WEBSOCKET_URL
30+
2731
# Build the application
2832
ENV NEXT_TELEMETRY_DISABLED=1
2933
ENV NODE_ENV=production

frontend/app/dashboard/DashboardClient.tsx

Lines changed: 9 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -102,59 +102,23 @@ export default function DashboardClient({ session: initialSession }: DashboardCl
102102
const { updateName, updateImage } = useProfileUpdate();
103103
const { isSyncing, pendingCount, lastError } = useSyncQueue();
104104

105-
// Phase V: WebSocket for real-time task updates with optimistic updates
105+
// Phase V: WebSocket for real-time task updates
106106
const { connectionState, isConnected } = useWebSocket({
107107
onTaskCreated: useCallback((taskData: Record<string, unknown>) => {
108-
// Optimistically add the new task to local state
109-
revalidateTasks(
110-
(currentTasks) => {
111-
if (!currentTasks) return currentTasks;
112-
const newTask = taskData as Task;
113-
// Check if task already exists (avoid duplicates)
114-
if (currentTasks.some(t => t.id === newTask.id)) {
115-
return currentTasks;
116-
}
117-
return [newTask, ...currentTasks];
118-
},
119-
{ revalidate: false } // Don't refetch from server
120-
);
108+
// Refetch tasks after 500ms delay to allow DB commit
109+
setTimeout(() => revalidateTasks(), 500);
121110
}, [revalidateTasks]),
122111
onTaskUpdated: useCallback((taskData: Record<string, unknown>) => {
123-
// Optimistically update the task in local state
124-
revalidateTasks(
125-
(currentTasks) => {
126-
if (!currentTasks) return currentTasks;
127-
const updatedTask = taskData as Task;
128-
return currentTasks.map(t =>
129-
t.id === updatedTask.id ? updatedTask : t
130-
);
131-
},
132-
{ revalidate: false } // Don't refetch from server
133-
);
112+
// Refetch tasks after 500ms delay to allow DB commit
113+
setTimeout(() => revalidateTasks(), 500);
134114
}, [revalidateTasks]),
135115
onTaskCompleted: useCallback((taskData: Record<string, unknown>) => {
136-
// Optimistically update completion status in local state
137-
revalidateTasks(
138-
(currentTasks) => {
139-
if (!currentTasks) return currentTasks;
140-
const completedTask = taskData as Task;
141-
return currentTasks.map(t =>
142-
t.id === completedTask.id ? { ...t, completed: completedTask.completed } : t
143-
);
144-
},
145-
{ revalidate: false } // Don't refetch from server
146-
);
116+
// Refetch tasks after 500ms delay to allow DB commit
117+
setTimeout(() => revalidateTasks(), 500);
147118
}, [revalidateTasks]),
148119
onTaskDeleted: useCallback((taskData: Record<string, unknown>) => {
149-
// Optimistically remove the task from local state
150-
revalidateTasks(
151-
(currentTasks) => {
152-
if (!currentTasks) return currentTasks;
153-
const deletedTask = taskData as Task;
154-
return currentTasks.filter(t => t.id !== deletedTask.id);
155-
},
156-
{ revalidate: false } // Don't refetch from server
157-
);
120+
// Refetch tasks after 500ms delay to allow DB commit
121+
setTimeout(() => revalidateTasks(), 500);
158122
}, [revalidateTasks]),
159123
});
160124

k8s/aws/eks-cluster-config.yaml

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# EKS Cluster Configuration for LifeStepsAI
2-
# AWS EKS 1.28 with OIDC enabled for IRSA
2+
# AWS EKS 1.29 with OIDC enabled for IRSA
33
# Region: us-east-1, Multi-AZ: us-east-1a, us-east-1b
44
# Node type: 2x t3.medium (4 vCPU, 8GB RAM total)
55

@@ -9,7 +9,7 @@ kind: ClusterConfig
99
metadata:
1010
name: lifestepsai-eks
1111
region: us-east-1
12-
version: "1.28"
12+
version: "1.29"
1313
tags:
1414
Environment: production
1515
Project: LifeStepsAI
@@ -38,10 +38,8 @@ nodeGroups:
3838
volumeSize: 20 # GB
3939
volumeType: gp3 # General Purpose SSD v3 (cost-effective)
4040

41-
# Multi-AZ deployment for availability
42-
availabilityZones:
43-
- us-east-1a
44-
- us-east-1b
41+
# Multi-AZ deployment for availability (let eksctl choose zones automatically)
42+
# availabilityZones will be determined by eksctl based on available subnets
4543

4644
# IAM policies for EKS worker nodes
4745
iam:

0 commit comments

Comments
 (0)