Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2dd5c8a8aa | ||
|
|
d17b21f04d | ||
|
|
c5a0f44bdd | ||
|
|
011b4912f2 | ||
|
|
a4d773066f |
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "langfuse",
|
||||
"version": "3.97.1",
|
||||
"version": "3.97.2",
|
||||
"author": "engineering@langfuse.com",
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "web",
|
||||
"version": "3.97.1",
|
||||
"version": "3.97.2",
|
||||
"private": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
|
||||
@@ -1 +1 @@
|
||||
export const VERSION = "v3.97.1";
|
||||
export const VERSION = "v3.97.2";
|
||||
|
||||
@@ -5,6 +5,7 @@ import { prisma } from "@langfuse/shared/src/db";
|
||||
import {
|
||||
convertDateToClickhouseDateTime,
|
||||
logger,
|
||||
measureAndReturn,
|
||||
queryClickhouse,
|
||||
traceException,
|
||||
} from "@langfuse/shared/src/server";
|
||||
@@ -37,20 +38,45 @@ export default async function handler(
|
||||
try {
|
||||
if (failIfNoRecentEvents) {
|
||||
const now = new Date();
|
||||
const traces = await queryClickhouse({
|
||||
query: `
|
||||
SELECT id
|
||||
FROM traces
|
||||
WHERE timestamp <= {now: DateTime64(3)}
|
||||
AND timestamp >= {now: DateTime64(3)} - INTERVAL 3 MINUTE
|
||||
LIMIT 1
|
||||
`,
|
||||
params: {
|
||||
const traces = await measureAndReturn({
|
||||
operationName: "healthCheckTraces",
|
||||
projectId: "__CROSS_PROJECT__",
|
||||
input: {
|
||||
now: convertDateToClickhouseDateTime(now),
|
||||
},
|
||||
tags: {
|
||||
feature: "health-check",
|
||||
type: "trace",
|
||||
existingExecution: async (input: { now: string }) => {
|
||||
return queryClickhouse<{ id: string }>({
|
||||
query: `
|
||||
SELECT id
|
||||
FROM traces
|
||||
WHERE timestamp <= {now: DateTime64(3)}
|
||||
AND timestamp >= {now: DateTime64(3)} - INTERVAL 3 MINUTE
|
||||
LIMIT 1
|
||||
`,
|
||||
params: input,
|
||||
tags: {
|
||||
feature: "health-check",
|
||||
type: "trace",
|
||||
experiment_amt: "original",
|
||||
},
|
||||
});
|
||||
},
|
||||
newExecution: async (input: { now: string }) => {
|
||||
return queryClickhouse<{ id: string }>({
|
||||
query: `
|
||||
SELECT id
|
||||
FROM traces_7d_amt
|
||||
WHERE start_time <= {now: DateTime64(3)}
|
||||
AND start_time >= {now: DateTime64(3)} - INTERVAL 3 MINUTE
|
||||
LIMIT 1
|
||||
`,
|
||||
params: input,
|
||||
tags: {
|
||||
feature: "health-check",
|
||||
type: "trace",
|
||||
experiment_amt: "new",
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
const observations = await queryClickhouse({
|
||||
|
||||
@@ -2,7 +2,6 @@ import { VERSION } from "@/src/constants/VERSION";
|
||||
import { env } from "@/src/env.mjs";
|
||||
import { createTRPCRouter, publicProcedure } from "@/src/server/api/trpc";
|
||||
import { logger } from "@langfuse/shared/src/server";
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
const versionSchema = z.string().regex(/^v\d+\.\d+\.\d+(?:[-+].+)?$/); // e.g. v1.2.3, v1.2.3-rc.1, v1.2.3+build.123
|
||||
@@ -79,27 +78,33 @@ export const publicRouter = createTRPCRouter({
|
||||
);
|
||||
body = await response.json();
|
||||
} catch (error) {
|
||||
logger.info(
|
||||
logger.error(
|
||||
"[trpc.public.checkUpdate] failed to fetch latest-release api",
|
||||
{
|
||||
error,
|
||||
},
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
const releases = ReleaseApiRes.safeParse(body);
|
||||
if (!releases.success) {
|
||||
throw new TRPCError({
|
||||
code: "INTERNAL_SERVER_ERROR",
|
||||
message: "Release API response is invalid",
|
||||
});
|
||||
logger.error(
|
||||
"[trpc.public.checkUpdate] Release API response is invalid, does not match schema",
|
||||
{
|
||||
error: releases.error,
|
||||
},
|
||||
);
|
||||
return null;
|
||||
}
|
||||
const langfuseRelease = releases.data.find(
|
||||
(release) => release.repo === "langfuse/langfuse",
|
||||
);
|
||||
if (!langfuseRelease) {
|
||||
throw new TRPCError({
|
||||
code: "INTERNAL_SERVER_ERROR",
|
||||
message: "Release API response is invalid",
|
||||
});
|
||||
logger.error(
|
||||
"[trpc.public.checkUpdate] Release API response is invalid, does not contain langfuse/langfuse",
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
const updateType = compareVersions(VERSION, langfuseRelease.latestRelease);
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "worker",
|
||||
"version": "3.97.1",
|
||||
"version": "3.97.2",
|
||||
"description": "",
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
|
||||
@@ -16,6 +16,7 @@ type MigrationState = {
|
||||
maxDate: string | undefined;
|
||||
minDate: string | undefined;
|
||||
queryTimeoutMinutes: number | undefined;
|
||||
targetTracesAllAmtOnly: boolean | undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -91,9 +92,7 @@ async function executeLongRunningQuery(
|
||||
const abortController = new AbortController();
|
||||
const timeoutMs = timeoutMinutes * 60 * 1000;
|
||||
|
||||
logger.info(
|
||||
`[Background Migration] Executing traces_null backfill query ${queryId}`,
|
||||
);
|
||||
logger.info(`[Background Migration] Executing backfill query ${queryId}`);
|
||||
|
||||
// Start the query execution
|
||||
const queryPromise = client.command({
|
||||
@@ -208,7 +207,7 @@ export default class MigrateTracesToTracesAMTs implements IBackgroundMigration {
|
||||
};
|
||||
}
|
||||
|
||||
// Check if new ClickHouse tables exists
|
||||
// Check if required ClickHouse tables exist
|
||||
const tables = await clickhouseClient().query({
|
||||
query: "SHOW TABLES",
|
||||
});
|
||||
@@ -249,6 +248,10 @@ export default class MigrateTracesToTracesAMTs implements IBackgroundMigration {
|
||||
const queryTimeoutMinutes =
|
||||
initialMigrationState.state?.queryTimeoutMinutes ??
|
||||
(args.queryTimeoutMinutes as number | undefined);
|
||||
const targetTracesAllAmtOnly =
|
||||
initialMigrationState.state?.targetTracesAllAmtOnly ??
|
||||
(args.targetTracesAllAmtOnly as boolean | undefined) ??
|
||||
false;
|
||||
|
||||
const maxDate = initialMigrationState.state?.maxDate
|
||||
? new Date(initialMigrationState.state.maxDate)
|
||||
@@ -264,6 +267,7 @@ export default class MigrateTracesToTracesAMTs implements IBackgroundMigration {
|
||||
maxDate,
|
||||
minDate,
|
||||
queryTimeoutMinutes,
|
||||
targetTracesAllAmtOnly,
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -272,14 +276,21 @@ export default class MigrateTracesToTracesAMTs implements IBackgroundMigration {
|
||||
const queryStart = Date.now();
|
||||
|
||||
// @ts-ignore
|
||||
const migrationState: { state: { maxDate: string; minDate: string } } =
|
||||
await prisma.backgroundMigration.findUniqueOrThrow({
|
||||
where: { id: backgroundMigrationId },
|
||||
select: { state: true },
|
||||
});
|
||||
const migrationState: {
|
||||
state: {
|
||||
maxDate: string;
|
||||
minDate: string;
|
||||
targetTracesAllAmtOnly?: boolean;
|
||||
};
|
||||
} = await prisma.backgroundMigration.findUniqueOrThrow({
|
||||
where: { id: backgroundMigrationId },
|
||||
select: { state: true },
|
||||
});
|
||||
|
||||
const maxDate = new Date(migrationState.state.maxDate);
|
||||
const minDate = new Date(migrationState.state.minDate);
|
||||
const targetTracesAllAmtOnly =
|
||||
migrationState.state.targetTracesAllAmtOnly ?? false;
|
||||
|
||||
// Get current month in YYYYMM format
|
||||
const currentMonth = maxDate.toISOString().slice(0, 7).replace("-", "");
|
||||
@@ -287,45 +298,89 @@ export default class MigrateTracesToTracesAMTs implements IBackgroundMigration {
|
||||
`[Background Migration] Migrating traces for ${currentMonth}`,
|
||||
);
|
||||
|
||||
const query = `
|
||||
INSERT INTO traces_null
|
||||
SELECT
|
||||
-- Identifiers
|
||||
project_id,
|
||||
id,
|
||||
timestamp as start_time,
|
||||
null as end_time,
|
||||
name,
|
||||
|
||||
-- Metadata properties
|
||||
metadata,
|
||||
user_id,
|
||||
session_id,
|
||||
environment,
|
||||
tags,
|
||||
version,
|
||||
release,
|
||||
|
||||
-- UI Properties
|
||||
bookmarked,
|
||||
public,
|
||||
|
||||
-- Aggregations (ignored)
|
||||
[] as observation_ids,
|
||||
[] as score_ids,
|
||||
map() as cost_details,
|
||||
map() as usage_details,
|
||||
|
||||
-- Input/Output
|
||||
input,
|
||||
output,
|
||||
|
||||
created_at,
|
||||
updated_at,
|
||||
event_ts
|
||||
FROM traces
|
||||
WHERE toYYYYMM(timestamp) = ${currentMonth}
|
||||
`;
|
||||
const targetTable = targetTracesAllAmtOnly
|
||||
? "traces_all_amt"
|
||||
: "traces_null";
|
||||
|
||||
const query = targetTracesAllAmtOnly
|
||||
? `
|
||||
INSERT INTO ${targetTable}
|
||||
SELECT
|
||||
-- Identifiers
|
||||
project_id,
|
||||
id,
|
||||
t.timestamp as timestamp,
|
||||
t.timestamp as start_time,
|
||||
t.timestamp as end_time,
|
||||
name,
|
||||
|
||||
-- Metadata properties
|
||||
metadata,
|
||||
user_id,
|
||||
session_id,
|
||||
environment,
|
||||
tags,
|
||||
version,
|
||||
release,
|
||||
|
||||
-- UI Properties
|
||||
arrayReduce('argMaxState', [toNullable(bookmarked)], [event_ts]) as bookmarked,
|
||||
arrayReduce('argMaxState', [toNullable(public)], [event_ts]) as public,
|
||||
|
||||
-- Aggregations
|
||||
[] as observation_ids,
|
||||
[] as score_ids,
|
||||
map() as cost_details,
|
||||
map() as usage_details,
|
||||
|
||||
-- Input/Output
|
||||
arrayReduce('argMaxState', [coalesce(input, '')], [if(coalesce(input, '') <> '', event_ts, toDateTime64(0, 3))]) as input,
|
||||
arrayReduce('argMaxState', [coalesce(output, '')], [if(coalesce(output, '') <> '', event_ts, toDateTime64(0, 3))]) as output,
|
||||
|
||||
created_at,
|
||||
updated_at
|
||||
FROM traces t
|
||||
WHERE toYYYYMM(t.timestamp) = ${currentMonth}
|
||||
`
|
||||
: `
|
||||
INSERT INTO ${targetTable}
|
||||
SELECT
|
||||
-- Identifiers
|
||||
project_id,
|
||||
id,
|
||||
timestamp as start_time,
|
||||
null as end_time,
|
||||
name,
|
||||
|
||||
-- Metadata properties
|
||||
metadata,
|
||||
user_id,
|
||||
session_id,
|
||||
environment,
|
||||
tags,
|
||||
version,
|
||||
release,
|
||||
|
||||
-- UI Properties
|
||||
bookmarked,
|
||||
public,
|
||||
|
||||
-- Aggregations (ignored)
|
||||
[] as observation_ids,
|
||||
[] as score_ids,
|
||||
map() as cost_details,
|
||||
map() as usage_details,
|
||||
|
||||
-- Input/Output
|
||||
input,
|
||||
output,
|
||||
|
||||
created_at,
|
||||
updated_at,
|
||||
event_ts
|
||||
FROM traces
|
||||
WHERE toYYYYMM(timestamp) = ${currentMonth}
|
||||
`;
|
||||
|
||||
await executeLongRunningQuery(query, queryTimeoutMinutes ?? 90);
|
||||
|
||||
@@ -341,7 +396,7 @@ export default class MigrateTracesToTracesAMTs implements IBackgroundMigration {
|
||||
});
|
||||
|
||||
logger.info(
|
||||
`[Background Migration] Inserted traces into traces_null for ${currentMonth} in ${Date.now() - queryStart}ms`,
|
||||
`[Background Migration] Inserted traces into ${targetTable} for ${currentMonth} in ${Date.now() - queryStart}ms`,
|
||||
);
|
||||
|
||||
if (maxDate < minDate) {
|
||||
@@ -412,6 +467,10 @@ async function main() {
|
||||
short: "t",
|
||||
default: "90",
|
||||
},
|
||||
targetTracesAllAmtOnly: {
|
||||
type: "boolean",
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
export const VERSION = "v3.97.1";
|
||||
export const VERSION = "v3.97.2";
|
||||
|
||||
Reference in New Issue
Block a user