batching events
This commit is contained in:
committed by
Carl-Gerhard Lindesvärd
parent
244aa3b0d3
commit
5e225b7ae6
@@ -1,12 +1,12 @@
|
||||
import { omit, uniq } from 'ramda';
|
||||
import { escape } from 'sqlstring';
|
||||
import superjson from 'superjson';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
import { toDots } from '@openpanel/common';
|
||||
import { redis, redisPub } from '@openpanel/redis';
|
||||
import { redis } from '@openpanel/redis';
|
||||
import type { IChartEventFilter } from '@openpanel/validation';
|
||||
|
||||
import { eventBuffer } from '../buffers';
|
||||
import {
|
||||
ch,
|
||||
chQuery,
|
||||
@@ -17,7 +17,7 @@ import type { EventMeta, Prisma } from '../prisma-client';
|
||||
import { db } from '../prisma-client';
|
||||
import { createSqlBuilder } from '../sql-builder';
|
||||
import { getEventFiltersWhereClause } from './chart.service';
|
||||
import { getProfileById, getProfiles, upsertProfile } from './profile.service';
|
||||
import { getProfiles, upsertProfile } from './profile.service';
|
||||
import type { IServiceProfile } from './profile.service';
|
||||
|
||||
export interface IClickhouseEvent {
|
||||
@@ -226,17 +226,14 @@ export async function createEvent(
|
||||
payload.profileId = payload.deviceId;
|
||||
}
|
||||
console.log(
|
||||
`create event ${payload.name} for deviceId: ${payload.deviceId} profileId ${payload.profileId}`
|
||||
`create event ${payload.name} for [deviceId]: ${payload.deviceId} [profileId]: ${payload.profileId} [projectId]: ${payload.projectId} [path]: ${payload.path}`
|
||||
);
|
||||
|
||||
const exists = await getProfileById(payload.profileId, payload.projectId);
|
||||
if (!exists && payload.profileId !== '') {
|
||||
if (payload.profileId !== '') {
|
||||
await upsertProfile({
|
||||
id: String(payload.profileId),
|
||||
isExternal: false,
|
||||
isExternal: payload.profileId !== payload.deviceId,
|
||||
projectId: payload.projectId,
|
||||
firstName: '',
|
||||
lastName: '',
|
||||
properties: {
|
||||
path: payload.path,
|
||||
country: payload.country,
|
||||
@@ -287,25 +284,9 @@ export async function createEvent(
|
||||
referrer_type: payload.referrerType ?? '',
|
||||
};
|
||||
|
||||
const res = await ch.insert({
|
||||
table: 'events',
|
||||
values: [event],
|
||||
format: 'JSONEachRow',
|
||||
clickhouse_settings: {
|
||||
date_time_input_format: 'best_effort',
|
||||
},
|
||||
});
|
||||
|
||||
redisPub.publish('event', superjson.stringify(transformEvent(event)));
|
||||
redis.set(
|
||||
`live:event:${event.project_id}:${event.profile_id}`,
|
||||
'',
|
||||
'EX',
|
||||
60 * 5
|
||||
);
|
||||
await eventBuffer.insert(event);
|
||||
|
||||
return {
|
||||
...res,
|
||||
document: event,
|
||||
};
|
||||
}
|
||||
@@ -449,3 +430,27 @@ export function getConversionEventNames(projectId: string) {
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export async function getLastScreenViewFromProfileId({
|
||||
profileId,
|
||||
projectId,
|
||||
}: {
|
||||
profileId: string;
|
||||
projectId: string;
|
||||
}) {
|
||||
const eventInBuffer = await eventBuffer.find(
|
||||
(item) => item.event.profile_id === profileId
|
||||
);
|
||||
|
||||
if (eventInBuffer) {
|
||||
return eventInBuffer;
|
||||
}
|
||||
|
||||
const [eventInDb] = profileId
|
||||
? await getEvents(
|
||||
`SELECT * FROM events WHERE name = 'screen_view' AND profile_id = ${escape(profileId)} AND project_id = ${escape(projectId)} AND created_at >= now() - INTERVAL 30 MINUTE ORDER BY created_at DESC LIMIT 1`
|
||||
)
|
||||
: [];
|
||||
|
||||
return eventInDb || null;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { escape } from 'sqlstring';
|
||||
|
||||
import { toDots, toObject } from '@openpanel/common';
|
||||
import { toObject } from '@openpanel/common';
|
||||
import type { IChartEventFilter } from '@openpanel/validation';
|
||||
|
||||
import { ch, chQuery } from '../clickhouse-client';
|
||||
import { profileBuffer } from '../buffers';
|
||||
import { chQuery, formatClickhouseDate } from '../clickhouse-client';
|
||||
import { createSqlBuilder } from '../sql-builder';
|
||||
|
||||
export type IProfileMetrics = {
|
||||
@@ -66,7 +67,10 @@ export async function getProfiles(ids: string[]) {
|
||||
const data = await chQuery<IClickhouseProfile>(
|
||||
`SELECT *
|
||||
FROM profiles FINAL
|
||||
WHERE id IN (${ids.map((id) => escape(id)).join(',')})
|
||||
WHERE id IN (${ids
|
||||
.map((id) => escape(id))
|
||||
.filter(Boolean)
|
||||
.join(',')})
|
||||
`
|
||||
);
|
||||
|
||||
@@ -172,31 +176,15 @@ export async function upsertProfile({
|
||||
projectId,
|
||||
isExternal,
|
||||
}: IServiceUpsertProfile) {
|
||||
const [profile] = await chQuery<IClickhouseProfile>(
|
||||
`SELECT * FROM profiles WHERE id = ${escape(id)} AND project_id = ${escape(projectId)} ORDER BY created_at DESC LIMIT 1`
|
||||
);
|
||||
|
||||
await ch.insert({
|
||||
table: 'profiles',
|
||||
format: 'JSONEachRow',
|
||||
clickhouse_settings: {
|
||||
date_time_input_format: 'best_effort',
|
||||
},
|
||||
values: [
|
||||
{
|
||||
id,
|
||||
first_name: firstName ?? profile?.first_name ?? '',
|
||||
last_name: lastName ?? profile?.last_name ?? '',
|
||||
email: email ?? profile?.email ?? '',
|
||||
avatar: avatar ?? profile?.avatar ?? '',
|
||||
properties: toDots({
|
||||
...(profile?.properties ?? {}),
|
||||
...(properties ?? {}),
|
||||
}),
|
||||
project_id: projectId ?? profile?.project_id ?? '',
|
||||
created_at: new Date(),
|
||||
is_external: isExternal,
|
||||
},
|
||||
],
|
||||
return profileBuffer.insert({
|
||||
id,
|
||||
first_name: firstName!,
|
||||
last_name: lastName!,
|
||||
email: email!,
|
||||
avatar: avatar!,
|
||||
properties: properties as Record<string, string | undefined>,
|
||||
project_id: projectId,
|
||||
created_at: formatClickhouseDate(new Date()),
|
||||
is_external: isExternal,
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user