Support per app events

This commit is contained in:
Rory Powell 2022-08-08 16:12:38 +01:00
parent ae342910c2
commit b093b18e6a
2 changed files with 65 additions and 8 deletions

View File

@ -1,6 +1,7 @@
import { Event } from "@budibase/types" import { Event } from "@budibase/types"
import { CacheKeys, TTL } from "../../../cache/generic" import { CacheKeys, TTL } from "../../../cache/generic"
import * as cache from "../../../cache/generic" import * as cache from "../../../cache/generic"
import * as context from "../../../context"
type RateLimitedEvent = type RateLimitedEvent =
| Event.SERVED_BUILDER | Event.SERVED_BUILDER
@ -15,6 +16,10 @@ const isRateLimited = (event: Event): event is RateLimitedEvent => {
) )
} }
const isPerApp = (event: RateLimitedEvent) => {
return event === Event.SERVED_APP_PREVIEW || event === Event.SERVED_APP
}
interface EventProperties { interface EventProperties {
timestamp: number timestamp: number
} }
@ -69,7 +74,11 @@ export const limited = async (event: Event): Promise<boolean> => {
} }
const eventKey = (event: RateLimitedEvent) => { const eventKey = (event: RateLimitedEvent) => {
return `${CacheKeys.EVENTS_RATE_LIMIT}:${event}` let key = `${CacheKeys.EVENTS_RATE_LIMIT}:${event}`
if (isPerApp(event)) {
key = key + context.getAppId()
}
return key
} }
const readEvent = async (event: RateLimitedEvent) => { const readEvent = async (event: RateLimitedEvent) => {
@ -81,8 +90,7 @@ const recordEvent = async (
event: RateLimitedEvent, event: RateLimitedEvent,
properties: EventProperties properties: EventProperties
) => { ) => {
const key = `${CacheKeys.EVENTS_RATE_LIMIT}:${event}` const key = eventKey(event)
const limit = RATE_LIMITS[event] const limit = RATE_LIMITS[event]
let ttl let ttl
switch (limit) { switch (limit) {

View File

@ -1,7 +1,10 @@
import "../../../../../tests/utilities/TestConfiguration"
import PosthogProcessor from "../PosthogProcessor" import PosthogProcessor from "../PosthogProcessor"
import { Event, IdentityType, Hosting } from "@budibase/types" import { Event, IdentityType, Hosting } from "@budibase/types"
const tk = require("timekeeper") const tk = require("timekeeper")
import * as Cache from "../../../../cache/generic" import * as cache from "../../../../cache/generic"
import { CacheKeys } from "../../../../cache/generic"
import * as context from "../../../../context"
const newIdentity = () => { const newIdentity = () => {
return { return {
@ -13,8 +16,11 @@ const newIdentity = () => {
} }
describe("PosthogProcessor", () => { describe("PosthogProcessor", () => {
beforeEach(() => { beforeEach(async () => {
jest.clearAllMocks() jest.clearAllMocks()
await cache.bustCache(
`${CacheKeys.EVENTS_RATE_LIMIT}:${Event.SERVED_BUILDER}`
)
}) })
describe("processEvent", () => { describe("processEvent", () => {
@ -71,7 +77,7 @@ describe("PosthogProcessor", () => {
tk.freeze(new Date(2022, 0, 3, 6, 0)) tk.freeze(new Date(2022, 0, 3, 6, 0))
await processor.processEvent(Event.SERVED_BUILDER, identity, properties) await processor.processEvent(Event.SERVED_BUILDER, identity, properties)
expect(processor.posthog.capture).toHaveBeenCalledTimes(4) expect(processor.posthog.capture).toHaveBeenCalledTimes(3)
}) })
it("sends event again after cache expires", async () => { it("sends event again after cache expires", async () => {
@ -82,8 +88,8 @@ describe("PosthogProcessor", () => {
tk.freeze(new Date(2022, 0, 1, 14, 0)) tk.freeze(new Date(2022, 0, 1, 14, 0))
await processor.processEvent(Event.SERVED_BUILDER, identity, properties) await processor.processEvent(Event.SERVED_BUILDER, identity, properties)
await Cache.bustCache( await cache.bustCache(
`${Cache.CacheKeys.EVENTS_RATE_LIMIT}:${Event.SERVED_BUILDER}` `${CacheKeys.EVENTS_RATE_LIMIT}:${Event.SERVED_BUILDER}`
) )
tk.freeze(new Date(2022, 0, 1, 14, 0)) tk.freeze(new Date(2022, 0, 1, 14, 0))
@ -91,6 +97,49 @@ describe("PosthogProcessor", () => {
expect(processor.posthog.capture).toHaveBeenCalledTimes(2) expect(processor.posthog.capture).toHaveBeenCalledTimes(2)
}) })
it("sends per app events once per day per app", async () => {
const processor = new PosthogProcessor("test")
const identity = newIdentity()
const properties = {}
const runAppEvents = async (appId: string) => {
await context.doInAppContext(appId, async () => {
tk.freeze(new Date(2022, 0, 1, 14, 0))
await processor.processEvent(Event.SERVED_APP, identity, properties)
await processor.processEvent(
Event.SERVED_APP_PREVIEW,
identity,
properties
)
// go forward one hour - should be ignored
tk.freeze(new Date(2022, 0, 1, 15, 0))
await processor.processEvent(Event.SERVED_APP, identity, properties)
await processor.processEvent(
Event.SERVED_APP_PREVIEW,
identity,
properties
)
// go forward into next day
tk.freeze(new Date(2022, 0, 2, 9, 0))
await processor.processEvent(Event.SERVED_APP, identity, properties)
await processor.processEvent(
Event.SERVED_APP_PREVIEW,
identity,
properties
)
})
}
await runAppEvents("app_1")
expect(processor.posthog.capture).toHaveBeenCalledTimes(4)
await runAppEvents("app_2")
expect(processor.posthog.capture).toHaveBeenCalledTimes(8)
})
}) })
}) })
}) })