Skip to content

Commit 2db897f

Browse files
committed
Improve the dev presence responsiveness
1 parent 1ff0f6b commit 2db897f

4 files changed

Lines changed: 16 additions & 23 deletions

File tree

apps/webapp/app/components/DevPresence.tsx

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,16 @@
11
import { createContext, type ReactNode, useContext, useEffect, useMemo, useState } from "react";
2-
import { useDebounce } from "~/hooks/useDebounce";
32
import { useEnvironment } from "~/hooks/useEnvironment";
43
import { useEventSource } from "~/hooks/useEventSource";
54
import { useOrganization } from "~/hooks/useOrganizations";
65
import { useProject } from "~/hooks/useProject";
76

87
// Define Context types
98
type DevPresenceContextType = {
10-
lastSeen: Date | null;
119
isConnected: boolean;
1210
};
1311

1412
// Create Context with default values
1513
const DevPresenceContext = createContext<DevPresenceContextType>({
16-
lastSeen: null,
1714
isConnected: false,
1815
});
1916

@@ -37,16 +34,12 @@ export function DevPresenceProvider({ children, enabled = true }: DevPresencePro
3734
}
3835
);
3936

40-
const [lastSeen, setLastSeen] = useState<Date | null>(null);
41-
42-
const debouncer = useDebounce((seen: Date | null) => {
43-
setLastSeen(seen);
44-
}, 3_000);
37+
const [isConnected, setIsConnected] = useState<boolean>(false);
4538

4639
useEffect(() => {
4740
// If disabled or no events, set lastSeen to null
4841
if (!enabled || streamedEvents === null) {
49-
debouncer(null);
42+
setIsConnected(false);
5043
return;
5144
}
5245

@@ -55,25 +48,24 @@ export function DevPresenceProvider({ children, enabled = true }: DevPresencePro
5548
if ("lastSeen" in data && data.lastSeen) {
5649
try {
5750
const lastSeenDate = new Date(data.lastSeen);
58-
debouncer(lastSeenDate);
51+
setIsConnected(true);
5952
} catch (error) {
6053
console.log("DevPresence: Failed to parse lastSeen timestamp", { error });
61-
debouncer(null);
54+
setIsConnected(false);
6255
}
6356
} else {
64-
debouncer(null);
57+
setIsConnected(false);
6558
}
6659
} catch (error) {
6760
console.log("DevPresence: Failed to parse presence message", { error });
68-
debouncer(null);
61+
setIsConnected(false);
6962
}
7063
}, [streamedEvents, enabled]);
7164

7265
// Calculate isConnected and memoize the context value
7366
const contextValue = useMemo(() => {
74-
const isConnected = enabled && lastSeen !== null && lastSeen > new Date(Date.now() - 120_000);
75-
return { lastSeen, isConnected };
76-
}, [lastSeen, enabled]);
67+
return { isConnected };
68+
}, [isConnected, enabled]);
7769

7870
return <DevPresenceContext.Provider value={contextValue}>{children}</DevPresenceContext.Provider>;
7971
}

apps/webapp/app/env.server.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -574,8 +574,9 @@ const EnvironmentSchema = z.object({
574574
RUN_ENGINE_RELEASE_CONCURRENCY_BATCH_SIZE: z.coerce.number().int().default(10),
575575

576576
/** How long should the presence ttl last */
577-
DEV_PRESENCE_TTL_MS: z.coerce.number().int().default(30_000),
578-
DEV_PRESENCE_POLL_INTERVAL_MS: z.coerce.number().int().default(5_000),
577+
DEV_PRESENCE_SSE_TIMEOUT: z.coerce.number().int().default(30_000),
578+
DEV_PRESENCE_TTL_MS: z.coerce.number().int().default(5_000),
579+
DEV_PRESENCE_POLL_MS: z.coerce.number().int().default(1_000),
579580
/** How many ms to wait until dequeuing again, if there was a run last time */
580581
DEV_DEQUEUE_INTERVAL_WITH_RUN: z.coerce.number().int().default(250),
581582
/** How many ms to wait until dequeuing again, if there was no run last time */

apps/webapp/app/routes/engine.v1.dev.presence.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ const redis = new Redis({
1616
});
1717

1818
export const loader = createSSELoader({
19-
timeout: env.DEV_PRESENCE_TTL_MS,
20-
interval: env.DEV_PRESENCE_POLL_INTERVAL_MS,
19+
timeout: env.DEV_PRESENCE_SSE_TIMEOUT,
20+
interval: env.DEV_PRESENCE_TTL_MS * 0.8,
2121
debug: true,
2222
handler: async ({ id, controller, debug, request }) => {
2323
const authentication = await authenticateApiRequestWithFailure(request);
@@ -30,7 +30,7 @@ export const loader = createSSELoader({
3030

3131
const presenceKey = DevPresenceStream.getPresenceKey(environmentId);
3232

33-
const ttl = (env.DEV_PRESENCE_POLL_INTERVAL_MS / 1000) * 2;
33+
const ttl = env.DEV_PRESENCE_TTL_MS / 1000;
3434

3535
return {
3636
beforeStream: async () => {

apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.dev.presence.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ import { createSSELoader, type SendFunction } from "~/utils/sse";
88
import Redis from "ioredis";
99

1010
export const loader = createSSELoader({
11-
timeout: env.DEV_PRESENCE_TTL_MS,
12-
interval: env.DEV_PRESENCE_POLL_INTERVAL_MS,
11+
timeout: env.DEV_PRESENCE_SSE_TIMEOUT,
12+
interval: env.DEV_PRESENCE_POLL_MS,
1313
debug: true,
1414
handler: async ({ id, controller, debug, request, params }) => {
1515
const userId = await requireUserId(request);

0 commit comments

Comments
 (0)