Files
triggerdotdev--trigger.dev/apps/webapp/app/presenters/EnvironmentsStreamPresenter.server.ts
Eric Allam 9a7c08c26a
🚀 Publish Trigger.dev Docker / typecheck (push) Failing after 1s
🚀 Publish Trigger.dev Docker / units (push) Failing after 0s
🚀 Publish Trigger.dev Docker / e2e (push) Failing after 0s
🚀 Publish Trigger.dev Docker / publish (push) Has been skipped
Improvements: Fix dangling SSE issue and compression memory leak (#733)
* Downgrade to remix-auth-email-link to remove yarn dependency

* Turn off the pg listen service for now

* Add snapshot admin route

* A couple logger fixes

* Add ability to disable compression

* Add ability to disable SSE

* Fix SSE memory leak + DB load issue
2023-11-10 16:02:53 +00:00

138 lines
3.7 KiB
TypeScript

import { PrismaClient, prisma } from "~/db.server";
import { Project } from "~/models/project.server";
import { User } from "~/models/user.server";
import { sse } from "~/utils/sse.server";
type EnvironmentSignalsMap = {
[x: string]: {
lastUpdatedAt: number;
lastTotalEndpointUpdatedTime: number;
lastTotalIndexingUpdatedTime: number;
};
};
export class EnvironmentsStreamPresenter {
#prismaClient: PrismaClient;
constructor(prismaClient: PrismaClient = prisma) {
this.#prismaClient = prismaClient;
}
public async call({
request,
userId,
projectSlug,
}: {
request: Request;
userId: User["id"];
projectSlug: Project["slug"];
}) {
let lastEnvironmentSignals: EnvironmentSignalsMap;
return sse({
request,
run: async (send, stop) => {
const nextEnvironmentSignals = await this.#runForUpdates({
userId,
projectSlug,
});
if (!nextEnvironmentSignals) {
return stop();
}
const lastEnvironmentIds = lastEnvironmentSignals
? Object.keys(lastEnvironmentSignals)
: [];
const nextEnvironmentIds = Object.keys(nextEnvironmentSignals);
if (
//push update if the number of environments is different
nextEnvironmentIds.length !== lastEnvironmentIds.length ||
//push update if the list of ids is different
lastEnvironmentIds.some((id) => !nextEnvironmentSignals[id]) ||
nextEnvironmentIds.some((id) => !lastEnvironmentSignals[id]) ||
//push update if any signals changed
nextEnvironmentIds.some(
(id) =>
nextEnvironmentSignals[id].lastUpdatedAt !==
lastEnvironmentSignals[id].lastUpdatedAt ||
nextEnvironmentSignals[id].lastTotalEndpointUpdatedTime !==
lastEnvironmentSignals[id].lastTotalEndpointUpdatedTime ||
nextEnvironmentSignals[id].lastTotalIndexingUpdatedTime !==
lastEnvironmentSignals[id].lastTotalIndexingUpdatedTime
)
) {
send({ data: new Date().toISOString() });
}
lastEnvironmentSignals = nextEnvironmentSignals;
},
});
}
async #runForUpdates({
userId,
projectSlug,
}: {
userId: User["id"];
projectSlug: Project["slug"];
}) {
const environments = await this.#prismaClient.runtimeEnvironment.findMany({
select: {
id: true,
updatedAt: true,
endpoints: {
select: {
updatedAt: true,
indexings: {
select: {
updatedAt: true,
},
},
},
},
},
where: {
project: {
slug: projectSlug,
},
organization: {
members: {
some: {
userId,
},
},
},
},
});
if (!environments) return null;
const environmentSignalsMap = environments.reduce<EnvironmentSignalsMap>((acc, environment) => {
const lastUpdatedAt = environment.updatedAt.getTime();
const lastTotalEndpointUpdatedTime = environment.endpoints.reduce(
(prev, endpoint) => prev + endpoint.updatedAt.getTime(),
0
);
const lastTotalIndexingUpdatedTime = environment.endpoints.reduce(
(prev, endpoint) =>
prev +
endpoint.indexings.reduce((prev, indexing) => prev + indexing.updatedAt.getTime(), 0),
0
);
return {
...acc,
[environment.id]: {
lastUpdatedAt,
lastTotalEndpointUpdatedTime,
lastTotalIndexingUpdatedTime,
},
};
}, {});
return environmentSignalsMap;
}
}