Skip to content

Commit cd8bc95

Browse files
committed
Refactored to make the dev presence stuff
1 parent 667a090 commit cd8bc95

File tree

6 files changed

+49
-66
lines changed

6 files changed

+49
-66
lines changed

apps/webapp/app/components/DevPresence.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,8 @@ export function DevPresenceProvider({ children, enabled = true }: DevPresencePro
4545

4646
try {
4747
const data = JSON.parse(streamedEvents) as any;
48-
if ("lastSeen" in data && data.lastSeen) {
48+
if ("isConnected" in data && data.isConnected) {
4949
try {
50-
const lastSeenDate = new Date(data.lastSeen);
5150
setIsConnected(true);
5251
} catch (error) {
5352
console.log("DevPresence: Failed to parse lastSeen timestamp", { error });
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import Redis, { type RedisOptions } from "ioredis";
2+
import { env } from "~/env.server";
3+
4+
const PRESENCE_KEY_PREFIX = "dev-presence:connection:";
5+
6+
export class DevPresence {
7+
private redis: Redis;
8+
9+
constructor(options: RedisOptions) {
10+
this.redis = new Redis(options);
11+
}
12+
13+
async isConnected(environmentId: string) {
14+
const presenceKey = this.getPresenceKey(environmentId);
15+
const presenceValue = await this.redis.get(presenceKey);
16+
return !!presenceValue;
17+
}
18+
19+
async setConnected(environmentId: string, ttl: number) {
20+
const presenceKey = this.getPresenceKey(environmentId);
21+
await this.redis.setex(presenceKey, ttl, new Date().toISOString());
22+
}
23+
24+
private getPresenceKey(environmentId: string) {
25+
return `${PRESENCE_KEY_PREFIX}${environmentId}`;
26+
}
27+
}
28+
29+
export const devPresence = new DevPresence({
30+
port: env.RUN_ENGINE_DEV_PRESENCE_REDIS_PORT ?? undefined,
31+
host: env.RUN_ENGINE_DEV_PRESENCE_REDIS_HOST ?? undefined,
32+
username: env.RUN_ENGINE_DEV_PRESENCE_REDIS_USERNAME ?? undefined,
33+
password: env.RUN_ENGINE_DEV_PRESENCE_REDIS_PASSWORD ?? undefined,
34+
enableAutoPipelining: true,
35+
...(env.RUN_ENGINE_DEV_PRESENCE_REDIS_TLS_DISABLED === "true" ? {} : { tls: {} }),
36+
});

apps/webapp/app/presenters/v3/DevPresenceStream.server.ts

Lines changed: 0 additions & 7 deletions
This file was deleted.

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

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,10 @@
11
import { json } from "@remix-run/server-runtime";
2-
import { Redis } from "ioredis";
32
import { env } from "~/env.server";
4-
import { DevPresenceStream } from "~/presenters/v3/DevPresenceStream.server";
3+
import { devPresence } from "~/presenters/v3/DevPresence.server";
54
import { authenticateApiRequestWithFailure } from "~/services/apiAuth.server";
65
import { logger } from "~/services/logger.server";
76
import { createSSELoader } from "~/utils/sse";
87

9-
const redis = new Redis({
10-
port: env.RUN_ENGINE_DEV_PRESENCE_REDIS_PORT ?? undefined,
11-
host: env.RUN_ENGINE_DEV_PRESENCE_REDIS_HOST ?? undefined,
12-
username: env.RUN_ENGINE_DEV_PRESENCE_REDIS_USERNAME ?? undefined,
13-
password: env.RUN_ENGINE_DEV_PRESENCE_REDIS_PASSWORD ?? undefined,
14-
enableAutoPipelining: true,
15-
...(env.RUN_ENGINE_DEV_PRESENCE_REDIS_TLS_DISABLED === "true" ? {} : { tls: {} }),
16-
});
17-
188
export const loader = createSSELoader({
199
timeout: env.DEV_PRESENCE_SSE_TIMEOUT,
2010
interval: env.DEV_PRESENCE_TTL_MS * 0.8,
@@ -27,25 +17,21 @@ export const loader = createSSELoader({
2717
}
2818

2919
const environmentId = authentication.environment.id;
30-
31-
const presenceKey = DevPresenceStream.getPresenceKey(environmentId);
32-
3320
const ttl = env.DEV_PRESENCE_TTL_MS / 1000;
3421

3522
return {
3623
beforeStream: async () => {
3724
logger.debug("Start dev presence SSE session", {
3825
environmentId,
39-
presenceKey,
4026
});
4127
},
4228
initStream: async ({ send }) => {
4329
// Set initial presence with more context
44-
await redis.setex(presenceKey, ttl, new Date().toISOString());
30+
await devPresence.setConnected(environmentId, ttl);
4531
send({ event: "start", data: `Started ${id}` });
4632
},
4733
iterator: async ({ send, date }) => {
48-
await redis.setex(presenceKey, ttl, date.toISOString());
34+
await devPresence.setConnected(environmentId, ttl);
4935
send({ event: "time", data: new Date().toISOString() });
5036
},
5137
cleanup: async () => {},

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

Lines changed: 6 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
import { $replica } from "~/db.server";
2-
import { requireUserId } from "~/services/session.server";
3-
import { EnvironmentParamSchema } from "~/utils/pathBuilder";
42
import { env } from "~/env.server";
5-
import { DevPresenceStream } from "~/presenters/v3/DevPresenceStream.server";
3+
import { devPresence } from "~/presenters/v3/DevPresence.server";
64
import { logger } from "~/services/logger.server";
5+
import { requireUserId } from "~/services/session.server";
6+
import { EnvironmentParamSchema } from "~/utils/pathBuilder";
77
import { createSSELoader, type SendFunction } from "~/utils/sse";
8-
import Redis from "ioredis";
98

109
export const loader = createSSELoader({
1110
timeout: env.DEV_PRESENCE_SSE_TIMEOUT,
@@ -32,44 +31,17 @@ export const loader = createSSELoader({
3231
throw new Response("Not Found", { status: 404 });
3332
}
3433

35-
const presenceKey = DevPresenceStream.getPresenceKey(environment.id);
36-
37-
const cmdRedis = new Redis({
38-
port: env.RUN_ENGINE_DEV_PRESENCE_REDIS_PORT ?? undefined,
39-
host: env.RUN_ENGINE_DEV_PRESENCE_REDIS_HOST ?? undefined,
40-
username: env.RUN_ENGINE_DEV_PRESENCE_REDIS_USERNAME ?? undefined,
41-
password: env.RUN_ENGINE_DEV_PRESENCE_REDIS_PASSWORD ?? undefined,
42-
enableAutoPipelining: true,
43-
...(env.RUN_ENGINE_DEV_PRESENCE_REDIS_TLS_DISABLED === "true" ? {} : { tls: {} }),
44-
});
45-
4634
const checkAndSendPresence = async (send: SendFunction) => {
4735
try {
4836
// Use the command client for the GET operation
49-
const currentPresenceValue = await cmdRedis.get(presenceKey);
50-
const isConnected = !!currentPresenceValue;
51-
52-
// Format lastSeen as ISO string if it exists
53-
let lastSeen = null;
54-
if (currentPresenceValue) {
55-
try {
56-
lastSeen = new Date(currentPresenceValue).toISOString();
57-
} catch (e) {
58-
// If parsing fails, use current time as fallback
59-
lastSeen = new Date().toISOString();
60-
logger.warn("Failed to parse lastSeen value, using current time", {
61-
originalValue: currentPresenceValue,
62-
});
63-
}
64-
}
37+
const isConnected = await devPresence.isConnected(environment.id);
6538

6639
send({
6740
event: "presence",
6841
data: JSON.stringify({
69-
type: isConnected ? "connected" : "disconnected",
42+
isConnected,
7043
environmentId: environment.id,
71-
timestamp: new Date().toISOString(), // Also standardize this to ISO
72-
lastSeen: lastSeen,
44+
timestamp: new Date().toISOString(),
7345
}),
7446
});
7547

@@ -85,7 +57,6 @@ export const loader = createSSELoader({
8557
beforeStream: async () => {
8658
logger.debug("Start dev presence listening SSE session", {
8759
environmentId: environment.id,
88-
presenceKey,
8960
});
9061
},
9162
initStream: async ({ send }) => {
@@ -98,7 +69,6 @@ export const loader = createSSELoader({
9869
},
9970
cleanup: async ({ send }) => {
10071
await checkAndSendPresence(send);
101-
await cmdRedis.quit();
10272
},
10373
};
10474
},

apps/webapp/app/v3/services/triggerScheduledTask.server.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { findCurrentWorkerDeployment } from "../models/workerDeployment.server";
99
import { logger } from "~/services/logger.server";
1010
import { env } from "~/env.server";
1111
import Redis from "ioredis";
12-
import { DevPresenceStream } from "~/presenters/v3/DevPresenceStream.server";
12+
import { devPresence, DevPresence } from "~/presenters/v3/DevPresence.server";
1313

1414
const redis = new Redis({
1515
port: env.RUN_ENGINE_DEV_PRESENCE_REDIS_PORT ?? undefined,
@@ -75,10 +75,9 @@ export class TriggerScheduledTaskService extends BaseService {
7575
!instance.environment.currentSession ||
7676
instance.environment.currentSession.disconnectedAt;
7777
//v4
78-
const presenceKey = DevPresenceStream.getPresenceKey(instance.environment.id);
79-
const v4Disconnected = await redis.get(presenceKey);
78+
const v4Connected = await devPresence.isConnected(instance.environment.id);
8079

81-
if (v3Disconnected && v4Disconnected) {
80+
if (v3Disconnected && !v4Connected) {
8281
shouldTrigger = false;
8382
}
8483
}

0 commit comments

Comments
 (0)