add better cache for getProfileId
This commit is contained in:
committed by
Carl-Gerhard Lindesvärd
parent
7d703bcd80
commit
b02cbb2946
@@ -11,7 +11,7 @@ import {
|
|||||||
toISOString,
|
toISOString,
|
||||||
} from '@openpanel/common';
|
} from '@openpanel/common';
|
||||||
import type { IServiceCreateEventPayload, IServiceEvent } from '@openpanel/db';
|
import type { IServiceCreateEventPayload, IServiceEvent } from '@openpanel/db';
|
||||||
import { createEvent } from '@openpanel/db';
|
import { createEvent, getProfileIdCached } from '@openpanel/db';
|
||||||
import { getLastScreenViewFromProfileId } from '@openpanel/db/src/services/event.service';
|
import { getLastScreenViewFromProfileId } from '@openpanel/db/src/services/event.service';
|
||||||
import { eventsQueue, findJobByPrefix, sessionsQueue } from '@openpanel/queue';
|
import { eventsQueue, findJobByPrefix, sessionsQueue } from '@openpanel/queue';
|
||||||
import type {
|
import type {
|
||||||
@@ -47,7 +47,10 @@ export async function incomingEvent(job: Job<EventsQueuePayloadIncomingEvent>) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// this will get the profileId from the alias table if it exists
|
// this will get the profileId from the alias table if it exists
|
||||||
const profileId = body.profileId ? String(body.profileId) : '';
|
const profileId = await getProfileIdCached({
|
||||||
|
profileId: body.profileId,
|
||||||
|
projectId,
|
||||||
|
});
|
||||||
const createdAt = new Date(body.timestamp);
|
const createdAt = new Date(body.timestamp);
|
||||||
const url = getProperty('__path');
|
const url = getProperty('__path');
|
||||||
const { path, hash, query, origin } = parsePath(url);
|
const { path, hash, query, origin } = parsePath(url);
|
||||||
|
|||||||
@@ -180,6 +180,7 @@ export async function createProfileAlias({
|
|||||||
alias: string;
|
alias: string;
|
||||||
profileId: string;
|
profileId: string;
|
||||||
}) {
|
}) {
|
||||||
|
await getProfileIdCached.clear({ profileId, projectId });
|
||||||
await ch.insert({
|
await ch.insert({
|
||||||
table: TABLE_NAMES.alias,
|
table: TABLE_NAMES.alias,
|
||||||
format: 'JSONEachRow',
|
format: 'JSONEachRow',
|
||||||
@@ -221,7 +222,7 @@ export async function getProfileId({
|
|||||||
profileId,
|
profileId,
|
||||||
projectId,
|
projectId,
|
||||||
}: {
|
}: {
|
||||||
profileId: string | undefined;
|
profileId: number | string | undefined;
|
||||||
projectId: string;
|
projectId: string;
|
||||||
}) {
|
}) {
|
||||||
if (!profileId) {
|
if (!profileId) {
|
||||||
@@ -240,7 +241,7 @@ export async function getProfileId({
|
|||||||
return res[0].profile_id;
|
return res[0].profile_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
return profileId;
|
return String(profileId);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getProfileIdCached = cacheable(getProfileId, 60 * 30);
|
export const getProfileIdCached = cacheable(getProfileId, 60 * 30);
|
||||||
|
|||||||
@@ -4,11 +4,36 @@ export function cacheable<T extends (...args: any) => any>(
|
|||||||
fn: T,
|
fn: T,
|
||||||
expireInSec: number
|
expireInSec: number
|
||||||
) {
|
) {
|
||||||
return async function (
|
const cachePrefix = `cachable:${fn.name}`;
|
||||||
|
function stringify(obj: unknown): string {
|
||||||
|
if (obj === null) return 'null';
|
||||||
|
if (obj === undefined) return 'undefined';
|
||||||
|
if (typeof obj === 'boolean') return obj ? 'true' : 'false';
|
||||||
|
if (typeof obj === 'number') return String(obj);
|
||||||
|
if (typeof obj === 'string') return obj;
|
||||||
|
if (typeof obj === 'function') return obj.toString();
|
||||||
|
|
||||||
|
if (Array.isArray(obj)) {
|
||||||
|
return '[' + obj.map(stringify).join(',') + ']';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof obj === 'object') {
|
||||||
|
const pairs = Object.entries(obj)
|
||||||
|
.sort(([a], [b]) => a.localeCompare(b))
|
||||||
|
.map(([key, value]) => `${key}:${stringify(value)}`);
|
||||||
|
return pairs.join(':');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback for any other types
|
||||||
|
return String(obj);
|
||||||
|
}
|
||||||
|
const getKey = (...args: Parameters<T>) =>
|
||||||
|
`${cachePrefix}:${stringify(args)}`;
|
||||||
|
const cachedFn = async function (
|
||||||
...args: Parameters<T>
|
...args: Parameters<T>
|
||||||
): Promise<Awaited<ReturnType<T>>> {
|
): Promise<Awaited<ReturnType<T>>> {
|
||||||
// JSON.stringify here is not bullet proof since ordering of object keys matters etc
|
// JSON.stringify here is not bullet proof since ordering of object keys matters etc
|
||||||
const key = `cachable:${fn.name}:${JSON.stringify(args)}`;
|
const key = getKey(...args);
|
||||||
const cached = await getRedisCache().get(key);
|
const cached = await getRedisCache().get(key);
|
||||||
if (cached) {
|
if (cached) {
|
||||||
try {
|
try {
|
||||||
@@ -25,4 +50,13 @@ export function cacheable<T extends (...args: any) => any>(
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
cachedFn.getKey = getKey;
|
||||||
|
cachedFn.clear = async function (...args: Parameters<T>) {
|
||||||
|
const key = getKey(...args);
|
||||||
|
console.log('[cachable] Clear', key);
|
||||||
|
return getRedisCache().del(key);
|
||||||
|
};
|
||||||
|
|
||||||
|
return cachedFn;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user