From 6e0388c501f1ae8a0ad341af41e3c6d42db34889 Mon Sep 17 00:00:00 2001 From: Baptiste Arnaud Date: Sat, 6 Apr 2024 15:08:57 +0200 Subject: [PATCH] :loud_sound: Add prisma metrics to prometheus endpoint (#1420) --- apps/chat-api/src/index.ts | 10 +++- packages/bot-engine/queries/createSession.ts | 6 ++- packages/bot-engine/queries/updateSession.ts | 6 ++- packages/bot-engine/queries/upsertResult.ts | 43 ++++++--------- packages/bot-engine/saveStateToDatabase.ts | 36 ++++++++----- packages/prisma/mysql/schema.prisma | 3 +- packages/prisma/package.json | 4 +- packages/prisma/postgresql/schema.prisma | 3 +- pnpm-lock.yaml | 56 ++++++++++---------- 9 files changed, 92 insertions(+), 75 deletions(-) diff --git a/apps/chat-api/src/index.ts b/apps/chat-api/src/index.ts index de37e8b05..d5d0545a7 100644 --- a/apps/chat-api/src/index.ts +++ b/apps/chat-api/src/index.ts @@ -4,6 +4,7 @@ import { whatsAppRuntime } from './runtimes/whatsapp' import { prometheus } from '@hono/prometheus' import { sentry } from '@hono/sentry' import { env } from '@typebot.io/env' +import prisma from '@typebot.io/lib/prisma' const app = new Hono() @@ -12,16 +13,21 @@ app.use( sentry({ environment: env.NODE_ENV, dsn: env.NEXT_PUBLIC_SENTRY_DSN, - release: process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA + '-chat-api', }) ) const { printMetrics, registerMetrics } = prometheus() app.use('*', registerMetrics) -app.get('/metrics', printMetrics) +app.get('/metrics', async (c) => { + const honoMetrics = await (await printMetrics(c)).text() + const prismaMetrics = await prisma.$metrics.prometheus() + return c.text(`${honoMetrics}\n\n${prismaMetrics}`, 200) +}) app.get('/ping', (c) => c.json({ status: 'ok' }, 200)) + app.route('/', webRuntime) + app.route('/', whatsAppRuntime) export default { diff --git a/packages/bot-engine/queries/createSession.ts b/packages/bot-engine/queries/createSession.ts index 3551dbd1e..6d3f352ee 100644 --- a/packages/bot-engine/queries/createSession.ts +++ b/packages/bot-engine/queries/createSession.ts @@ -1,4 +1,5 @@ import prisma from '@typebot.io/lib/prisma' +import { Prisma } from '@typebot.io/prisma' import { SessionState } from '@typebot.io/schemas' type Props = { @@ -6,7 +7,10 @@ type Props = { state: SessionState } -export const createSession = async ({ id, state }: Props) => +export const createSession = ({ + id, + state, +}: Props): Prisma.PrismaPromise => prisma.chatSession.create({ data: { id, diff --git a/packages/bot-engine/queries/updateSession.ts b/packages/bot-engine/queries/updateSession.ts index 8d60e0a6b..92f80bdd6 100644 --- a/packages/bot-engine/queries/updateSession.ts +++ b/packages/bot-engine/queries/updateSession.ts @@ -1,4 +1,5 @@ import prisma from '@typebot.io/lib/prisma' +import { Prisma } from '@typebot.io/prisma' import { SessionState } from '@typebot.io/schemas' type Props = { @@ -6,7 +7,10 @@ type Props = { state: SessionState } -export const updateSession = async ({ id, state }: Props) => +export const updateSession = ({ + id, + state, +}: Props): Prisma.PrismaPromise => prisma.chatSession.updateMany({ where: { id }, data: { diff --git a/packages/bot-engine/queries/upsertResult.ts b/packages/bot-engine/queries/upsertResult.ts index a0d1b1af9..d0dc2ee5d 100644 --- a/packages/bot-engine/queries/upsertResult.ts +++ b/packages/bot-engine/queries/upsertResult.ts @@ -1,4 +1,5 @@ import prisma from '@typebot.io/lib/prisma' +import { Prisma } from '@typebot.io/prisma' import { TypebotInSession } from '@typebot.io/schemas' import { filterVariablesWithValues } from '@typebot.io/variables/filterVariablesWithValues' @@ -8,37 +9,27 @@ type Props = { hasStarted: boolean isCompleted: boolean } -export const upsertResult = async ({ +export const upsertResult = ({ resultId, typebot, hasStarted, isCompleted, -}: Props) => { - const existingResult = await prisma.result.findUnique({ +}: Props): Prisma.PrismaPromise => { + const variablesWithValue = filterVariablesWithValues(typebot.variables) + return prisma.result.upsert({ where: { id: resultId }, + update: { + isCompleted: isCompleted ? true : undefined, + hasStarted, + variables: variablesWithValue, + }, + create: { + id: resultId, + typebotId: typebot.id, + isCompleted: isCompleted ? true : false, + hasStarted, + variables: variablesWithValue, + }, select: { id: true }, }) - const variablesWithValue = filterVariablesWithValues(typebot.variables) - - if (existingResult) { - return prisma.result.updateMany({ - where: { id: resultId }, - data: { - isCompleted: isCompleted ? true : undefined, - hasStarted, - variables: variablesWithValue, - }, - }) - } - return prisma.result.createMany({ - data: [ - { - id: resultId, - typebotId: typebot.id, - isCompleted: isCompleted ? true : false, - hasStarted, - variables: variablesWithValue, - }, - ], - }) } diff --git a/packages/bot-engine/saveStateToDatabase.ts b/packages/bot-engine/saveStateToDatabase.ts index 14f8556ce..b991bbd96 100644 --- a/packages/bot-engine/saveStateToDatabase.ts +++ b/packages/bot-engine/saveStateToDatabase.ts @@ -7,7 +7,8 @@ import { createSession } from './queries/createSession' import { deleteSession } from './queries/deleteSession' import * as Sentry from '@sentry/nextjs' import { saveVisitedEdges } from './queries/saveVisitedEdges' -import { VisitedEdge } from '@typebot.io/prisma' +import { Prisma, VisitedEdge } from '@typebot.io/prisma' +import prisma from '@typebot.io/lib/prisma' type Props = { session: Pick & { id?: string } @@ -36,11 +37,13 @@ export const saveStateToDatabase = async ({ !input && !containsSetVariableClientSideAction && !hasCustomEmbedBubble ) + const queries: Prisma.PrismaPromise[] = [] + const resultId = state.typebotsQueue[0].resultId if (id) { - if (isCompleted && resultId) await deleteSession(id) - else await updateSession({ id, state }) + if (isCompleted && resultId) queries.push(deleteSession(id)) + else queries.push(updateSession({ id, state })) } const session = @@ -48,18 +51,23 @@ export const saveStateToDatabase = async ({ ? { state, id } : await createSession({ id, state }) - if (!resultId) return session + if (!resultId) { + if (queries.length > 0) await prisma.$transaction(queries) + return session + } const answers = state.typebotsQueue[0].answers - await upsertResult({ - resultId, - typebot: state.typebotsQueue[0].typebot, - isCompleted: Boolean( - !input && !containsSetVariableClientSideAction && answers.length > 0 - ), - hasStarted: answers.length > 0, - }) + queries.push( + upsertResult({ + resultId, + typebot: state.typebotsQueue[0].typebot, + isCompleted: Boolean( + !input && !containsSetVariableClientSideAction && answers.length > 0 + ), + hasStarted: answers.length > 0, + }) + ) if (logs && logs.length > 0) try { @@ -75,7 +83,9 @@ export const saveStateToDatabase = async ({ Sentry.captureException(e) } - if (visitedEdges.length > 0) await saveVisitedEdges(visitedEdges) + if (visitedEdges.length > 0) queries.push(saveVisitedEdges(visitedEdges)) + + await prisma.$transaction(queries) return session } diff --git a/packages/prisma/mysql/schema.prisma b/packages/prisma/mysql/schema.prisma index 06a2c82b7..be1be96f8 100644 --- a/packages/prisma/mysql/schema.prisma +++ b/packages/prisma/mysql/schema.prisma @@ -1,5 +1,6 @@ generator client { - provider = "prisma-client-js" + provider = "prisma-client-js" + previewFeatures = ["metrics"] } datasource db { diff --git a/packages/prisma/package.json b/packages/prisma/package.json index 8eed59ecf..21bfce5e6 100644 --- a/packages/prisma/package.json +++ b/packages/prisma/package.json @@ -14,12 +14,12 @@ "db:migrate": "pnpm migrate:deploy" }, "dependencies": { - "@prisma/client": "5.8.0" + "@prisma/client": "5.12.1" }, "devDependencies": { "@types/node": "20.4.2", "dotenv-cli": "7.2.1", - "prisma": "5.8.0", + "prisma": "5.12.1", "@typebot.io/tsconfig": "workspace:*", "tsx": "3.12.7", "typescript": "5.3.2" diff --git a/packages/prisma/postgresql/schema.prisma b/packages/prisma/postgresql/schema.prisma index 29850ce00..296e5bd7c 100644 --- a/packages/prisma/postgresql/schema.prisma +++ b/packages/prisma/postgresql/schema.prisma @@ -1,5 +1,6 @@ generator client { - provider = "prisma-client-js" + provider = "prisma-client-js" + previewFeatures = ["metrics"] } datasource db { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d12a91cd9..5a612ca09 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1751,8 +1751,8 @@ importers: packages/prisma: dependencies: '@prisma/client': - specifier: 5.8.0 - version: 5.8.0(prisma@5.8.0) + specifier: 5.12.1 + version: 5.12.1(prisma@5.12.1) devDependencies: '@typebot.io/tsconfig': specifier: workspace:* @@ -1764,8 +1764,8 @@ importers: specifier: 7.2.1 version: 7.2.1 prisma: - specifier: 5.8.0 - version: 5.8.0 + specifier: 5.12.1 + version: 5.12.1 tsx: specifier: 3.12.7 version: 3.12.7 @@ -7848,8 +7848,8 @@ packages: resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} dev: false - /@prisma/client@5.8.0(prisma@5.8.0): - resolution: {integrity: sha512-QxO6C4MaA/ysTIbC+EcAH1aX/YkpymhXtO6zPdk+FvA7+59tNibIYpd+7koPdViLg2iKES4ojsxWNUGNJaEcbA==} + /@prisma/client@5.12.1(prisma@5.12.1): + resolution: {integrity: sha512-6/JnizEdlSBxDIdiLbrBdMW5NqDxOmhXAJaNXiPpgzAPr/nLZResT6MMpbOHLo5yAbQ1Vv5UU8PTPRzb0WIxdA==} engines: {node: '>=16.13'} requiresBuild: true peerDependencies: @@ -7858,35 +7858,35 @@ packages: prisma: optional: true dependencies: - prisma: 5.8.0 + prisma: 5.12.1 dev: false - /@prisma/debug@5.8.0: - resolution: {integrity: sha512-ZqPpkvbovu/kQJ1bvy57NO4dw97fpQGcbQSCtsqlwSE1UNKJP75R3BKxdznk8ZPMY+GJdMRetWNv4oAvSbWn8Q==} + /@prisma/debug@5.12.1: + resolution: {integrity: sha512-kd/wNsR0klrv79o1ITsbWxYyh4QWuBidvxsXSParPsYSu0ircUmNk3q4ojsgNc3/81b0ozg76iastOG43tbf8A==} - /@prisma/engines-version@5.8.0-37.0a83d8541752d7582de2ebc1ece46519ce72a848: - resolution: {integrity: sha512-cXcoVweYbnv8xRfkWq9oj8BECOdzHUazrSpYCa0ehp5TNz4l5Spa8jbq/VROCTzj3ZncH5D9Q2TmySYTOUeKlw==} + /@prisma/engines-version@5.12.0-21.473ed3124229e22d881cb7addf559799debae1ab: + resolution: {integrity: sha512-6yvO8s80Tym61aB4QNtYZfWVmE3pwqe807jEtzm8C5VDe7nw8O1FGX3TXUaXmWV0fQTIAfRbeL2Gwrndabp/0g==} - /@prisma/engines@5.8.0: - resolution: {integrity: sha512-Qhqm9WWLujNEC13AuZlUO14SQ15tNLe5puaz+tOk7UqINqJ3PtqMmuSuzomiw2diGVqZ+HYiSQzlR3+pPucVHA==} + /@prisma/engines@5.12.1: + resolution: {integrity: sha512-HQDdglLw2bZR/TXD2Y+YfDMvi5Q8H+acbswqOsWyq9pPjBLYJ6gzM+ptlTU/AV6tl0XSZLU1/7F4qaWa8bqpJA==} requiresBuild: true dependencies: - '@prisma/debug': 5.8.0 - '@prisma/engines-version': 5.8.0-37.0a83d8541752d7582de2ebc1ece46519ce72a848 - '@prisma/fetch-engine': 5.8.0 - '@prisma/get-platform': 5.8.0 + '@prisma/debug': 5.12.1 + '@prisma/engines-version': 5.12.0-21.473ed3124229e22d881cb7addf559799debae1ab + '@prisma/fetch-engine': 5.12.1 + '@prisma/get-platform': 5.12.1 - /@prisma/fetch-engine@5.8.0: - resolution: {integrity: sha512-1CAuE+JoYsPNggMEn6qk0zos06Uc9bYZBJ0VBPHD6R7REL05614koAbOCmn52IaYz3nobb7f25hqW6AY7rLkIw==} + /@prisma/fetch-engine@5.12.1: + resolution: {integrity: sha512-qSs3KcX1HKcea1A+hlJVK/ljj0PNIUHDxAayGMvgJBqmaN32P9tCidlKz1EGv6WoRFICYnk3Dd/YFLBwnFIozA==} dependencies: - '@prisma/debug': 5.8.0 - '@prisma/engines-version': 5.8.0-37.0a83d8541752d7582de2ebc1ece46519ce72a848 - '@prisma/get-platform': 5.8.0 + '@prisma/debug': 5.12.1 + '@prisma/engines-version': 5.12.0-21.473ed3124229e22d881cb7addf559799debae1ab + '@prisma/get-platform': 5.12.1 - /@prisma/get-platform@5.8.0: - resolution: {integrity: sha512-Nk3rhTFZ1LYkFZJnpSvQcLPCaBWgJQfteHII6UEENOOkYlmP0k3FuswND54tzzEr4qs39wOdV9pbXKX9U2lv7A==} + /@prisma/get-platform@5.12.1: + resolution: {integrity: sha512-pgIR+pSvhYHiUcqXVEZS31NrFOTENC9yFUdEAcx7cdQBoZPmHVjtjN4Ss6NzVDMYPrKJJ51U14EhEoeuBlMioQ==} dependencies: - '@prisma/debug': 5.8.0 + '@prisma/debug': 5.12.1 /@radix-ui/colors@1.0.1: resolution: {integrity: sha512-xySw8f0ZVsAEP+e7iLl3EvcBXX7gsIlC1Zso/sPBW9gIWerBTgz6axrjU+MZ39wD+WFi5h5zdWpsg3+hwt2Qsg==} @@ -19692,13 +19692,13 @@ packages: react: 18.2.0 dev: false - /prisma@5.8.0: - resolution: {integrity: sha512-hDKoEqPt2qEUTH5yGO3l27CBnPtwvte0CGMKrpCr9+/A919JghfqJ3qgCGgMbOwdkXUOzdho0RH9tyUF3UhpMw==} + /prisma@5.12.1: + resolution: {integrity: sha512-SkMnb6wyIxTv9ACqiHBI2u9gD6y98qXRoCoLEnZsF6yee5Qg828G+ARrESN+lQHdw4maSZFFSBPPDpvSiVTo0Q==} engines: {node: '>=16.13'} hasBin: true requiresBuild: true dependencies: - '@prisma/engines': 5.8.0 + '@prisma/engines': 5.12.1 /prismjs@1.29.0: resolution: {integrity: sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==}