MCPcopy Create free account
hub / github.com/Openpanel-dev/openpanel / processBuffer

Method processBuffer

packages/db/src/buffers/event-buffer.ts:176–252  ·  view source on GitHub ↗
()

Source from the content-addressed store, hash-verified

174 }
175
176 async processBuffer() {
177 const redis = getRedisCache();
178
179 const lrangeStart = performance.now();
180 const queueEvents = await redis.lrange(
181 this.queueKey,
182 0,
183 this.batchSize - 1
184 );
185 const lrangeMs = performance.now() - lrangeStart;
186
187 if (queueEvents.length === 0) {
188 this.reportFlushStats({ rowsProcessed: 0, phases: { lrangeMs } });
189 return;
190 }
191
192 // We don't need to JSON.parse the events at all — they're already
193 // valid JSONEachRow lines (one stringified event per Redis entry).
194 // The client's custom `json.stringify` (set in CLICKHOUSE_OPTIONS)
195 // passes strings through unchanged, so the bytes go straight from
196 // Redis → CH HTTP body. This skips:
197 // - JSON.parse × N (50–300ms for N=100k)
198 // - The @clickhouse/client's internal JSON.stringify × N (same)
199 // - All the intermediate object allocations (saves ~200MB heap)
200 //
201 // We still need `project_id` per row for the per-project pub/sub.
202 // extractProjectId() does an indexOf-based fast path that's ~50×
203 // faster than JSON.parse, and falls back to a real parse on the
204 // rare line where `project_id` appears more than once (e.g. a
205 // user-supplied `properties.project_id`) — so the count is always
206 // attributed to the top-level field, never a nested one.
207 const countByProject = new Map<string, number>();
208 const yieldEvery = this.getYieldInterval(queueEvents.length, {
209 min: 1000,
210 max: 5000,
211 });
212 for (let i = 0; i < queueEvents.length; i++) {
213 const projectId = extractProjectId(queueEvents[i]!);
214 if (projectId) {
215 countByProject.set(
216 projectId,
217 (countByProject.get(projectId) ?? 0) + 1,
218 );
219 }
220 if ((i + 1) % yieldEvery === 0) {
221 await this.yieldToEventLoop();
222 }
223 }
224
225 const chStart = performance.now();
226 await this.parallelLimit(
227 this.chunks(queueEvents, this.chunkSize),
228 (chunk) =>
229 ch.insert({
230 table: 'events',
231 // Stream the raw JSONEachRow lines straight through — already
232 // serialized in Redis, no client-side parse/stringify needed.
233 values: this.jsonEachRowStream(chunk),

Callers 1

constructorMethod · 0.95

Calls 12

getRedisCacheFunction · 0.90
publishEventFunction · 0.90
extractProjectIdFunction · 0.85
reportFlushStatsMethod · 0.80
getYieldIntervalMethod · 0.80
yieldToEventLoopMethod · 0.80
parallelLimitMethod · 0.80
chunksMethod · 0.80
jsonEachRowStreamMethod · 0.80
getClickhouseSettingsMethod · 0.80
setMethod · 0.45
getMethod · 0.45

Tested by

no test coverage detected