@@ -19,14 +19,8 @@ import {
1919 Status_StatusCode ,
2020} from "@trigger.dev/otlp-importer" ;
2121import type { MetricsV1Input } from "@internal/clickhouse" ;
22- import { ClickHouse } from "@internal/clickhouse" ;
2322import { logger } from "~/services/logger.server" ;
24- import {
25- clickhouseFactory ,
26- ClickhouseFactory ,
27- getDefaultClickhouseClient ,
28- } from "~/services/clickhouse/clickhouseFactory.server" ;
29- import { DynamicFlushScheduler } from "./dynamicFlushScheduler.server" ;
23+ import { clickhouseFactory , type ClickhouseFactory } from "~/services/clickhouse/clickhouseFactory.server" ;
3024
3125import { generateSpanId } from "./eventRepository/common.server" ;
3226import type {
@@ -43,19 +37,13 @@ import { singleton } from "~/utils/singleton";
4337
4438type OTLPExporterConfig = {
4539 clickhouseFactory : ClickhouseFactory ;
46- metrics : {
47- batchSize : number ;
48- flushInterval : number ;
49- maxConcurrency : number ;
50- } ;
5140 verbose : boolean ;
5241 spanAttributeValueLengthLimit : number ;
5342} ;
5443
5544class OTLPExporter {
5645 private _tracer : Tracer ;
5746 private readonly _clickhouseFactory : ClickhouseFactory ;
58- private readonly _defaultMetricsFlushScheduler : DynamicFlushScheduler < MetricsV1Input > ;
5947 private readonly _verbose : boolean ;
6048 private readonly _spanAttributeValueLengthLimit : number ;
6149
@@ -64,16 +52,6 @@ class OTLPExporter {
6452 this . _clickhouseFactory = config . clickhouseFactory ;
6553 this . _verbose = config . verbose ;
6654 this . _spanAttributeValueLengthLimit = config . spanAttributeValueLengthLimit ;
67- this . _defaultMetricsFlushScheduler = new DynamicFlushScheduler < MetricsV1Input > ( {
68- batchSize : config . metrics . batchSize ,
69- flushInterval : config . metrics . flushInterval ,
70- callback : async ( _flushId , batch ) => {
71- await config . metrics . clickhouse . metrics . insert ( batch ) ;
72- } ,
73- minConcurrency : 1 ,
74- maxConcurrency : config . metrics . maxConcurrency ,
75- loadSheddingEnabled : false ,
76- } ) ;
7755 }
7856
7957 async exportTraces ( request : ExportTraceServiceRequest ) : Promise < ExportTraceServiceResponse > {
@@ -96,19 +74,19 @@ class OTLPExporter {
9674
9775 async exportMetrics ( request : ExportMetricsServiceRequest ) : Promise < ExportMetricsServiceResponse > {
9876 return await startSpan ( this . _tracer , "exportMetrics" , async ( span ) => {
99- const rows = this . #filterResourceMetrics( request . resourceMetrics ) . flatMap (
100- ( resourceMetrics ) => {
101- return convertMetricsToClickhouseRows (
77+ const metricsWithStores = this . #filterResourceMetrics( request . resourceMetrics ) . map (
78+ ( resourceMetrics ) =>
79+ convertResourceMetricsToRowsWithStore (
10280 resourceMetrics ,
10381 this . _spanAttributeValueLengthLimit
104- ) ;
105- }
82+ )
10683 ) ;
10784
108- span . setAttribute ( "metric_row_count" , rows . length ) ;
85+ const rowCount = metricsWithStores . reduce ( ( acc , m ) => acc + m . rows . length , 0 ) ;
86+ span . setAttribute ( "metric_row_count" , rowCount ) ;
10987
110- if ( rows . length > 0 ) {
111- this . _defaultMetricsFlushScheduler . addToBatch ( rows ) ;
88+ if ( rowCount > 0 ) {
89+ await this . #exportMetricRows ( metricsWithStores ) ;
11290 }
11391
11492 return ExportMetricsServiceResponse . create ( ) ;
@@ -177,6 +155,37 @@ class OTLPExporter {
177155 return eventCount ;
178156 }
179157
158+ async #exportMetricRows(
159+ metricsWithStores : { rows : MetricsV1Input [ ] ; taskEventStore : string } [ ]
160+ ) : Promise < void > {
161+ const routeCache = new Map < string , { key : string ; repository : IEventRepository } > ( ) ;
162+ const groups = new Map < string , { repository : IEventRepository ; rows : MetricsV1Input [ ] } > ( ) ;
163+ for ( const { rows, taskEventStore } of metricsWithStores ) {
164+ for ( const row of rows ) {
165+ const routeKey = `${ row . organization_id } \0${ taskEventStore } ` ;
166+ let resolved = routeCache . get ( routeKey ) ;
167+ if ( ! resolved ) {
168+ resolved = this . _clickhouseFactory . getEventRepositoryForOrganizationSync (
169+ taskEventStore ,
170+ row . organization_id
171+ ) ;
172+ routeCache . set ( routeKey , resolved ) ;
173+ }
174+
175+ let group = groups . get ( resolved . key ) ;
176+ if ( ! group ) {
177+ group = { repository : resolved . repository , rows : [ ] } ;
178+ groups . set ( resolved . key , group ) ;
179+ }
180+ group . rows . push ( row ) ;
181+ }
182+ }
183+
184+ for ( const [ , { repository, rows } ] of groups ) {
185+ repository . insertManyMetrics ( rows ) ;
186+ }
187+ }
188+
180189 #logEventsVerbose( events : CreateEventInput [ ] , prefix : string ) {
181190 if ( ! this . _verbose ) return ;
182191
@@ -592,6 +601,21 @@ function convertMetricsToClickhouseRows(
592601 return rows ;
593602}
594603
604+ function convertResourceMetricsToRowsWithStore (
605+ resourceMetrics : ResourceMetrics ,
606+ spanAttributeValueLengthLimit : number
607+ ) : { rows : MetricsV1Input [ ] ; taskEventStore : string } {
608+ const resourceAttributes = resourceMetrics . resource ?. attributes ?? [ ] ;
609+ const taskEventStore =
610+ extractStringAttribute ( resourceAttributes , [ SemanticInternalAttributes . TASK_EVENT_STORE ] ) ??
611+ env . EVENT_REPOSITORY_DEFAULT_STORE ;
612+
613+ return {
614+ rows : convertMetricsToClickhouseRows ( resourceMetrics , spanAttributeValueLengthLimit ) ,
615+ taskEventStore,
616+ } ;
617+ }
618+
595619// Prefixes injected by TaskContextMetricExporter — these are extracted into
596620// the nested `trigger` key and should not appear as top-level user attributes.
597621const INTERNAL_METRIC_ATTRIBUTE_PREFIXES = [ "ctx." , "worker." ] ;
@@ -1203,11 +1227,6 @@ export const otlpExporter = singleton("otlpExporter", initializeOTLPExporter);
12031227function initializeOTLPExporter ( ) {
12041228 return new OTLPExporter ( {
12051229 clickhouseFactory,
1206- metrics : {
1207- batchSize : env . METRICS_CLICKHOUSE_BATCH_SIZE ,
1208- flushInterval : env . METRICS_CLICKHOUSE_FLUSH_INTERVAL_MS ,
1209- maxConcurrency : env . METRICS_CLICKHOUSE_MAX_CONCURRENCY ,
1210- } ,
12111230 verbose : process . env . OTLP_EXPORTER_VERBOSE === "1" ,
12121231 spanAttributeValueLengthLimit : process . env . SERVER_OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT
12131232 ? parseInt ( process . env . SERVER_OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT , 10 )
0 commit comments