-
-
Notifications
You must be signed in to change notification settings - Fork 721
Realtime streams now powered by electric #1541
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
--- | ||
"@trigger.dev/react-hooks": patch | ||
"@trigger.dev/sdk": patch | ||
--- | ||
|
||
Realtime streams now powered by electric. Also, this change fixes a realtime bug that was causing too many re-renders, even on records that didn't change |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -1,7 +1,7 @@ | ||||||||||||||||||||||||||||||
import { ActionFunctionArgs } from "@remix-run/server-runtime"; | ||||||||||||||||||||||||||||||
import { z } from "zod"; | ||||||||||||||||||||||||||||||
import { $replica } from "~/db.server"; | ||||||||||||||||||||||||||||||
import { realtimeStreams } from "~/services/realtimeStreamsGlobal.server"; | ||||||||||||||||||||||||||||||
import { v1RealtimeStreams } from "~/services/realtime/v1StreamsGlobal.server"; | ||||||||||||||||||||||||||||||
import { createLoaderApiRoute } from "~/services/routeBuilders/apiBuilder.server"; | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
const ParamsSchema = z.object({ | ||||||||||||||||||||||||||||||
|
@@ -16,7 +16,7 @@ export async function action({ request, params }: ActionFunctionArgs) { | |||||||||||||||||||||||||||||
return new Response("No body provided", { status: 400 }); | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
return realtimeStreams.ingestData(request.body, $params.runId, $params.streamId); | ||||||||||||||||||||||||||||||
return v1RealtimeStreams.ingestData(request.body, $params.runId, $params.streamId); | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
export const loader = createLoaderApiRoute( | ||||||||||||||||||||||||||||||
|
@@ -50,7 +50,13 @@ export const loader = createLoaderApiRoute( | |||||||||||||||||||||||||||||
superScopes: ["read:runs", "read:all", "admin"], | ||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||
async ({ params, request, resource: run }) => { | ||||||||||||||||||||||||||||||
return realtimeStreams.streamResponse(run.friendlyId, params.streamId, request.signal); | ||||||||||||||||||||||||||||||
async ({ params, request, resource: run, authentication }) => { | ||||||||||||||||||||||||||||||
return v1RealtimeStreams.streamResponse( | ||||||||||||||||||||||||||||||
request, | ||||||||||||||||||||||||||||||
run.friendlyId, | ||||||||||||||||||||||||||||||
params.streamId, | ||||||||||||||||||||||||||||||
authentication.environment, | ||||||||||||||||||||||||||||||
request.signal | ||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||
Comment on lines
+54
to
+60
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Use In the Apply this diff: return v1RealtimeStreams.streamResponse(
request,
- run.friendlyId,
+ run.id,
params.streamId,
authentication.environment,
request.signal
); 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
import { z } from "zod"; | ||
import { $replica } from "~/db.server"; | ||
import { | ||
createActionApiRoute, | ||
createLoaderApiRoute, | ||
} from "~/services/routeBuilders/apiBuilder.server"; | ||
import { v2RealtimeStreams } from "~/services/realtime/v2StreamsGlobal.server"; | ||
|
||
const ParamsSchema = z.object({ | ||
runId: z.string(), | ||
streamId: z.string(), | ||
}); | ||
|
||
const { action } = createActionApiRoute( | ||
{ | ||
params: ParamsSchema, | ||
}, | ||
async ({ request, params, authentication }) => { | ||
if (!request.body) { | ||
return new Response("No body provided", { status: 400 }); | ||
} | ||
|
||
const run = await $replica.taskRun.findFirst({ | ||
where: { | ||
friendlyId: params.runId, | ||
runtimeEnvironmentId: authentication.environment.id, | ||
}, | ||
include: { | ||
batch: { | ||
select: { | ||
friendlyId: true, | ||
}, | ||
}, | ||
}, | ||
}); | ||
|
||
if (!run) { | ||
return new Response("Run not found", { status: 404 }); | ||
} | ||
|
||
return v2RealtimeStreams.ingestData(request.body, run.id, params.streamId); | ||
} | ||
); | ||
|
||
export { action }; | ||
|
||
export const loader = createLoaderApiRoute( | ||
{ | ||
params: ParamsSchema, | ||
allowJWT: true, | ||
corsStrategy: "all", | ||
findResource: async (params, auth) => { | ||
return $replica.taskRun.findFirst({ | ||
where: { | ||
friendlyId: params.runId, | ||
runtimeEnvironmentId: auth.environment.id, | ||
}, | ||
include: { | ||
batch: { | ||
select: { | ||
friendlyId: true, | ||
}, | ||
}, | ||
}, | ||
}); | ||
}, | ||
Comment on lines
+53
to
+66
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Confirm that The Apply this diff to include the necessary fields: return $replica.taskRun.findFirst({
where: {
friendlyId: params.runId,
runtimeEnvironmentId: auth.environment.id,
},
include: {
batch: {
select: {
friendlyId: true,
},
},
},
+ select: {
+ runTags: true,
+ taskIdentifier: true,
+ },
});
|
||
authorization: { | ||
action: "read", | ||
resource: (run) => ({ | ||
runs: run.friendlyId, | ||
tags: run.runTags, | ||
batch: run.batch?.friendlyId, | ||
tasks: run.taskIdentifier, | ||
}), | ||
superScopes: ["read:runs", "read:all", "admin"], | ||
}, | ||
}, | ||
async ({ params, request, resource: run, authentication }) => { | ||
return v2RealtimeStreams.streamResponse( | ||
request, | ||
run.id, | ||
params.streamId, | ||
authentication.environment, | ||
request.signal | ||
); | ||
} | ||
); |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,85 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { PrismaClient } from "@trigger.dev/database"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { AuthenticatedEnvironment } from "../apiAuth.server"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { logger } from "../logger.server"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { RealtimeClient } from "../realtimeClient.server"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { StreamIngestor, StreamResponder } from "./types"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
export type DatabaseRealtimeStreamsOptions = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
prisma: PrismaClient; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
realtimeClient: RealtimeClient; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Class implementing both interfaces | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
export class DatabaseRealtimeStreams implements StreamIngestor, StreamResponder { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
constructor(private options: DatabaseRealtimeStreamsOptions) {} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
async streamResponse( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
request: Request, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
runId: string, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
streamId: string, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
environment: AuthenticatedEnvironment, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
signal: AbortSignal | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
): Promise<Response> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return this.options.realtimeClient.streamChunks( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
request.url, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
environment, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
runId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
streamId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
signal, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
request.headers.get("x-trigger-electric-version") ?? undefined | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
async ingestData( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
stream: ReadableStream<Uint8Array>, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
runId: string, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
streamId: string | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
): Promise<Response> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const textStream = stream.pipeThrough(new TextDecoderStream()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const reader = textStream.getReader(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
let sequence = 0; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
while (true) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const { done, value } = await reader.read(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (done) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
break; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
logger.debug("[DatabaseRealtimeStreams][ingestData] Reading data", { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
streamId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
runId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
value, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const chunks = value | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
.split("\n") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
.filter((chunk) => chunk) // Remove empty lines | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
.map((line) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
sequence: sequence++, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
value: line, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
await this.options.prisma.realtimeStreamChunk.createMany({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
data: chunks.map((chunk) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
runId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
key: streamId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
sequence: chunk.sequence, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
value: chunk.value, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+42
to
+76
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix potential data corruption due to incomplete stream chunks When reading from the Apply this diff to handle incomplete lines: const reader = textStream.getReader();
+ let remainder = '';
let sequence = 0;
while (true) {
const { done, value } = await reader.read();
if (done) {
break;
}
- const chunks = value
+ remainder += value;
+ const lines = remainder.split('\n');
+ remainder = lines.pop() ?? '';
+ const chunks = lines
.filter((chunk) => chunk) // Remove empty lines
.map((line) => {
return {
sequence: sequence++,
value: line,
};
});
await this.options.prisma.realtimeStreamChunk.createMany({
data: chunks.map((chunk) => {
return {
runId,
key: streamId,
sequence: chunk.sequence,
value: chunk.value,
};
}),
});
}
+ // Handle any remaining data after the loop
+ if (remainder) {
+ await this.options.prisma.realtimeStreamChunk.create({
+ data: {
+ runId,
+ key: streamId,
+ sequence: sequence++,
+ value: remainder,
+ },
+ });
+ } 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return new Response(null, { status: 200 }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} catch (error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
logger.error("[DatabaseRealtimeStreams][ingestData] Error in ingestData:", { error }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return new Response(null, { status: 500 }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { AuthenticatedEnvironment } from "../apiAuth.server"; | ||
|
||
// Interface for stream ingestion | ||
export interface StreamIngestor { | ||
ingestData( | ||
stream: ReadableStream<Uint8Array>, | ||
runId: string, | ||
streamId: string | ||
): Promise<Response>; | ||
} | ||
|
||
// Interface for stream response | ||
export interface StreamResponder { | ||
streamResponse( | ||
request: Request, | ||
runId: string, | ||
streamId: string, | ||
environment: AuthenticatedEnvironment, | ||
signal: AbortSignal | ||
): Promise<Response>; | ||
} |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -1,9 +1,9 @@ | ||||||
import { env } from "~/env.server"; | ||||||
import { singleton } from "~/utils/singleton"; | ||||||
import { RealtimeStreams } from "./realtimeStreams.server"; | ||||||
import { RedisRealtimeStreams } from "./redisRealtimeStreams.server"; | ||||||
|
||||||
function initializeRealtimeStreams() { | ||||||
return new RealtimeStreams({ | ||||||
function initializeRedisRealtimeStreams() { | ||||||
return new RedisRealtimeStreams({ | ||||||
redis: { | ||||||
port: env.REDIS_PORT, | ||||||
host: env.REDIS_HOST, | ||||||
|
@@ -16,4 +16,4 @@ function initializeRealtimeStreams() { | |||||
}); | ||||||
} | ||||||
|
||||||
export const realtimeStreams = singleton("realtimeStreams", initializeRealtimeStreams); | ||||||
export const v1RealtimeStreams = singleton("realtimeStreams", initializeRedisRealtimeStreams); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Update the singleton key to prevent naming collisions The singleton is currently registered with the key Apply this diff: -export const v1RealtimeStreams = singleton("realtimeStreams", initializeRedisRealtimeStreams);
+export const v1RealtimeStreams = singleton("v1RealtimeStreams", initializeRedisRealtimeStreams); 📝 Committable suggestion
Suggested change
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { prisma } from "~/db.server"; | ||
import { singleton } from "~/utils/singleton"; | ||
import { realtimeClient } from "../realtimeClientGlobal.server"; | ||
import { DatabaseRealtimeStreams } from "./databaseRealtimeStreams.server"; | ||
|
||
function initializeDatabaseRealtimeStreams() { | ||
return new DatabaseRealtimeStreams({ | ||
prisma, | ||
realtimeClient, | ||
}); | ||
} | ||
ericallam marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
export const v2RealtimeStreams = singleton("dbRealtimeStreams", initializeDatabaseRealtimeStreams); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Codebase verification
Based on the evidence gathered, I can now provide a final response:
A minor version bump is warranted for these changes
The changes introduce significant new functionality and behavioral improvements:
These changes represent new features and significant improvements rather than just bug fixes, which aligns with semantic versioning principles for minor version bumps.
🔗 Analysis chain
Consider using minor version bumps instead of patches.
Given that this change introduces a new streaming backend ("electric") and fixes behavioral issues, it might be more appropriate to use minor version bumps instead of patches. Minor versions typically indicate new features or significant changes while maintaining backward compatibility.
Let's check the recent version history of these packages:
Let me gather more information about the changes to better assess the version bump type.
Let me search for changes related to the streaming backend and realtime functionality to better assess the impact.
Let me try a different search approach without specifying file types.
Let me try one final search with simpler commands.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
Length of output: 1215
Script:
Length of output: 62603
Script:
Length of output: 110
Script:
Length of output: 384
Script:
Length of output: 1951