Skip to content

Commit 293bb47

Browse files
authored
pass initial kafka timestamp from Ender -> Vulcan for better e2e order latency tracking (#1211)
1 parent 42cbee6 commit 293bb47

30 files changed

+70
-9
lines changed

indexer/packages/kafka/__tests__/batch-kafka-producer.test.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
11
import { KafkaTopics } from '../src';
22
import { BatchKafkaProducer, ProducerMessage } from '../src/batch-kafka-producer';
33
import { producer } from '../src/producer';
4+
import { IHeaders } from 'kafkajs';
45
import _ from 'lodash';
56

67
interface TestMessage {
78
key?: string,
89
value: string,
10+
headers?: IHeaders,
911
}
1012

1113
function testMessage2ProducerMessage(data: TestMessage): ProducerMessage {
1214
const key: Buffer | undefined = data.key === undefined ? undefined : Buffer.from(data.key);
13-
return { key, value: Buffer.from(data.value) };
15+
return { key, value: Buffer.from(data.value), headers: data.headers };
1416
}
1517

1618
function testMessage2ProducerMessages(data: TestMessage[]): ProducerMessage[] {
@@ -35,9 +37,9 @@ describe('batch-kafka-producer', () => {
3537
[
3638
'will send key if key is not undefined',
3739
5,
38-
[{ key: '1', value: 'a' }, { key: '2', value: 'b' }, { key: '3', value: 'c' }],
40+
[{ key: '1', value: 'a' }, { key: '2', value: 'b' }, { key: '3', value: 'c', headers: { timestamp: 'value' } }],
3941
[[{ key: '1', value: 'a' }, { key: '2', value: 'b' }]],
40-
[{ key: '3', value: 'c' }],
42+
[{ key: '3', value: 'c', headers: { timestamp: 'value' } }],
4143
],
4244
[
4345
'will not send message until the batch size is reached',
@@ -104,7 +106,9 @@ describe('batch-kafka-producer', () => {
104106

105107
for (const msg of messages) {
106108
const key: Buffer | undefined = msg.key === undefined ? undefined : Buffer.from(msg.key);
107-
batchProducer.addMessageAndMaybeFlush({ value: Buffer.from(msg.value), key });
109+
batchProducer.addMessageAndMaybeFlush(
110+
{ value: Buffer.from(msg.value), key, headers: msg.headers },
111+
);
108112
}
109113

110114
expect(producerSendMock.mock.calls).toHaveLength(expectedMessagesPerCall.length);

indexer/packages/kafka/src/batch-kafka-producer.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { logger } from '@dydxprotocol-indexer/base';
2-
import { Producer, RecordMetadata } from 'kafkajs';
2+
import { IHeaders, Producer, RecordMetadata } from 'kafkajs';
33
import _ from 'lodash';
44

55
import { KafkaTopics } from './types';
@@ -10,6 +10,7 @@ import { KafkaTopics } from './types';
1010
export type ProducerMessage = {
1111
key?: Buffer,
1212
value: Buffer,
13+
headers?: IHeaders,
1314
};
1415

1516
/**
@@ -52,7 +53,7 @@ export class BatchKafkaProducer {
5253
if (this.currentSize + msgBuffer.byteLength + keyByteLength > this.maxBatchSizeBytes) {
5354
this.sendBatch();
5455
}
55-
this.producerMessages.push({ key: message.key, value: msgBuffer });
56+
this.producerMessages.push({ key: message.key, value: msgBuffer, headers: message.headers });
5657
this.currentSize += msgBuffer.byteLength;
5758
this.currentSize += keyByteLength;
5859
}

indexer/services/bazooka/src/vulcan-helpers.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {
2222
} from '@dydxprotocol-indexer/v4-protos';
2323
import { Long } from '@dydxprotocol-indexer/v4-protos/build/codegen/helpers';
2424
import Big from 'big.js';
25+
import { IHeaders } from 'kafkajs';
2526
import _ from 'lodash';
2627

2728
import config from './config';
@@ -30,6 +31,7 @@ import { ZERO } from './constants';
3031
interface VulcanMessage {
3132
key: Buffer,
3233
value: OffChainUpdateV1,
34+
headers?: IHeaders,
3335
}
3436

3537
type IndexerOrderIdMap = { [orderUuid: string]: IndexerOrderId };
@@ -129,6 +131,7 @@ export async function sendStatefulOrderMessages() {
129131
return {
130132
key: message.key,
131133
value: Buffer.from(Uint8Array.from(OffChainUpdateV1.encode(message.value).finish())),
134+
headers: message.headers,
132135
};
133136
});
134137

indexer/services/ender/__tests__/handlers/stateful-order/conditional-order-triggered-handler.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ describe('conditionalOrderTriggeredHandler', () => {
143143
producerSendMock,
144144
orderId: conditionalOrderId,
145145
offchainUpdate: expectedOffchainUpdate,
146+
headers: { message_received_timestamp: kafkaMessage.timestamp, event_type: 'ConditionalOrderTriggered' },
146147
});
147148
});
148149

indexer/services/ender/__tests__/handlers/stateful-order/stateful-order-placement-handler.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ describe('statefulOrderPlacementHandler', () => {
180180
producerSendMock,
181181
orderId: defaultOrder.orderId!,
182182
offchainUpdate: expectedOffchainUpdate,
183+
headers: { message_received_timestamp: kafkaMessage.timestamp, event_type: 'StatefulOrderPlacement' },
183184
});
184185
});
185186

indexer/services/ender/__tests__/handlers/stateful-order/stateful-order-removal-handler.test.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,10 @@ import { DydxIndexerSubtypes } from '../../../src/lib/types';
2121
import {
2222
defaultDateTime,
2323
defaultHeight,
24-
defaultOrderId, defaultPreviousHeight, defaultTime, defaultTxHash,
24+
defaultOrderId,
25+
defaultPreviousHeight,
26+
defaultTime,
27+
defaultTxHash,
2528
} from '../../helpers/constants';
2629
import { createKafkaMessageFromStatefulOrderEvent } from '../../helpers/kafka-helpers';
2730
import { updateBlockCache } from '../../../src/caches/block-cache';
@@ -130,6 +133,7 @@ describe('statefulOrderRemovalHandler', () => {
130133
producerSendMock,
131134
orderId: defaultOrderId,
132135
offchainUpdate: expectedOffchainUpdate,
136+
headers: { message_received_timestamp: kafkaMessage.timestamp, event_type: 'StatefulOrderRemoval' },
133137
});
134138
});
135139

indexer/services/ender/__tests__/helpers/indexer-proto-helpers.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ import {
5151
PerpetualMarketCreateEventV1,
5252
DeleveragingEventV1,
5353
} from '@dydxprotocol-indexer/v4-protos';
54-
import { Message, ProducerRecord } from 'kafkajs';
54+
import { IHeaders, Message, ProducerRecord } from 'kafkajs';
5555
import _ from 'lodash';
5656

5757
import {
@@ -318,10 +318,12 @@ export function expectVulcanKafkaMessage({
318318
producerSendMock,
319319
orderId,
320320
offchainUpdate,
321+
headers,
321322
}: {
322323
producerSendMock: jest.SpyInstance,
323324
orderId: IndexerOrderId,
324325
offchainUpdate: OffChainUpdateV1,
326+
headers?: IHeaders,
325327
}): void {
326328
expect(producerSendMock.mock.calls.length).toBeGreaterThanOrEqual(1);
327329
expect(producerSendMock.mock.calls[0].length).toBeGreaterThanOrEqual(1);
@@ -339,7 +341,6 @@ export function expectVulcanKafkaMessage({
339341
vulcanProducerRecord.messages,
340342
(message: Message): VulcanMessage => {
341343
expect(Buffer.isBuffer(message.value));
342-
343344
const messageValueBinary: Uint8Array = new Uint8Array(
344345
// Can assume Buffer, since we check above that it is a buffer
345346
message.value as Buffer,
@@ -348,13 +349,15 @@ export function expectVulcanKafkaMessage({
348349
return {
349350
key: message.key as Buffer,
350351
value: OffChainUpdateV1.decode(messageValueBinary),
352+
headers: message.headers,
351353
};
352354
},
353355
);
354356

355357
expect(vulcanMessages).toContainEqual({
356358
key: getOrderIdHash(orderId),
357359
value: offchainUpdate,
360+
headers,
358361
});
359362
}
360363

indexer/services/ender/__tests__/lib/block-processor.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ describe('block-processor', () => {
121121
const blockProcessor: BlockProcessor = new BlockProcessor(
122122
block,
123123
txId,
124+
defaultDateTime.toString(),
124125
);
125126
blockProcessor.batchedHandlers = batchedHandlers;
126127
blockProcessor.syncHandlers = syncHandlers;
@@ -149,6 +150,7 @@ describe('block-processor', () => {
149150
const blockProcessor: BlockProcessor = new BlockProcessor(
150151
block,
151152
txId,
153+
defaultDateTime.toString(),
152154
);
153155
blockProcessor.batchedHandlers = batchedHandlers;
154156
blockProcessor.syncHandlers = syncHandlers;

indexer/services/ender/src/handlers/handler.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
OffChainUpdateV1,
1919
SubaccountId,
2020
} from '@dydxprotocol-indexer/v4-protos';
21+
import { IHeaders } from 'kafkajs';
2122
import { DateTime } from 'luxon';
2223
import * as pg from 'pg';
2324

@@ -33,6 +34,7 @@ export type HandlerInitializer = new (
3334
indexerTendermintEvent: IndexerTendermintEvent,
3435
txId: number,
3536
event: EventMessage,
37+
messageReceivedTimestamp?: string,
3638
) => Handler<EventMessage>;
3739

3840
/**
@@ -49,20 +51,23 @@ export abstract class Handler<T> {
4951
blockEventIndex: number;
5052
event: T;
5153
abstract eventType: string;
54+
messageReceivedTimestamp?: string;
5255

5356
constructor(
5457
block: IndexerTendermintBlock,
5558
blockEventIndex: number,
5659
indexerTendermintEvent: IndexerTendermintEvent,
5760
txId: number,
5861
event: T,
62+
messageReceivedTimestamp?: string,
5963
) {
6064
this.block = block;
6165
this.blockEventIndex = blockEventIndex;
6266
this.indexerTendermintEvent = indexerTendermintEvent;
6367
this.timestamp = DateTime.fromJSDate(block.time!);
6468
this.txId = txId;
6569
this.event = event;
70+
this.messageReceivedTimestamp = messageReceivedTimestamp;
6671
}
6772

6873
/**
@@ -178,6 +183,7 @@ export abstract class Handler<T> {
178183
protected generateConsolidatedVulcanKafkaEvent(
179184
key: Buffer,
180185
offChainUpdate: OffChainUpdateV1,
186+
headers?: IHeaders,
181187
): ConsolidatedKafkaEvent {
182188
stats.increment(`${config.SERVICE_NAME}.create_vulcan_kafka_event`, 1);
183189

@@ -186,6 +192,7 @@ export abstract class Handler<T> {
186192
message: {
187193
key,
188194
value: offChainUpdate,
195+
headers,
189196
},
190197
};
191198
}

indexer/services/ender/src/handlers/stateful-order/conditional-order-triggered-handler.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ export class ConditionalOrderTriggeredHandler extends
5454
this.generateConsolidatedVulcanKafkaEvent(
5555
getOrderIdHash(order.orderId!),
5656
offChainUpdate,
57+
{
58+
message_received_timestamp: this.messageReceivedTimestamp,
59+
event_type: 'ConditionalOrderTriggered',
60+
},
5761
),
5862
];
5963
}

indexer/services/ender/src/handlers/stateful-order/stateful-order-placement-handler.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ export class StatefulOrderPlacementHandler extends
5454
kafakEvents.push(this.generateConsolidatedVulcanKafkaEvent(
5555
getOrderIdHash(order.orderId!),
5656
offChainUpdate,
57+
{
58+
message_received_timestamp: this.messageReceivedTimestamp,
59+
event_type: 'StatefulOrderPlacement',
60+
},
5761
));
5862

5963
return kafakEvents;

indexer/services/ender/src/handlers/stateful-order/stateful-order-removal-handler.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ export class StatefulOrderRemovalHandler extends
4242
this.generateConsolidatedVulcanKafkaEvent(
4343
getOrderIdHash(orderIdProto),
4444
offChainUpdate,
45+
{
46+
message_received_timestamp: this.messageReceivedTimestamp,
47+
event_type: 'StatefulOrderRemoval',
48+
},
4549
),
4650
];
4751
}

indexer/services/ender/src/lib/block-processor.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,16 @@ export class BlockProcessor {
7777
txId: number;
7878
batchedHandlers: BatchedHandlers;
7979
syncHandlers: SyncHandlers;
80+
messageReceivedTimestamp: string;
8081

8182
constructor(
8283
block: IndexerTendermintBlock,
8384
txId: number,
85+
messageReceivedTimestamp: string,
8486
) {
8587
this.block = block;
8688
this.txId = txId;
89+
this.messageReceivedTimestamp = messageReceivedTimestamp;
8790
this.sqlBlock = {
8891
...this.block,
8992
events: new Array(this.block.events.length),
@@ -205,6 +208,7 @@ export class BlockProcessor {
205208
const handlers: Handler<EventMessage>[] = validator.createHandlers(
206209
eventProto.indexerTendermintEvent,
207210
this.txId,
211+
this.messageReceivedTimestamp,
208212
);
209213

210214
_.map(handlers, (handler: Handler<EventMessage>) => {

indexer/services/ender/src/lib/kafka-publisher.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,7 @@ export class KafkaPublisher {
247247
return {
248248
key: message.key,
249249
value: Buffer.from(Uint8Array.from(OffChainUpdateV1.encode(message.value).finish())),
250+
headers: message.headers,
250251
};
251252
}),
252253
});

indexer/services/ender/src/lib/on-message.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ export async function onMessage(message: KafkaMessage): Promise<void> {
8383
const blockProcessor: BlockProcessor = new BlockProcessor(
8484
indexerTendermintBlock,
8585
txId,
86+
message.timestamp,
8687
);
8788
const kafkaPublisher: KafkaPublisher = await blockProcessor.process();
8889

indexer/services/ender/src/lib/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import {
3333
DeleveragingEventV1,
3434
TradingRewardsEventV1,
3535
} from '@dydxprotocol-indexer/v4-protos';
36+
import { IHeaders } from 'kafkajs';
3637
import Long from 'long';
3738

3839
// Type sourced from protocol:
@@ -217,6 +218,7 @@ export interface AnnotatedSubaccountMessage extends SubaccountMessage {
217218
export interface VulcanMessage {
218219
key: Buffer,
219220
value: OffChainUpdateV1,
221+
headers?: IHeaders,
220222
}
221223

222224
export type ConsolidatedKafkaEvent = {

indexer/services/ender/src/validators/asset-validator.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export class AssetValidator extends Validator<AssetCreateEventV1> {
1010
public createHandlers(
1111
indexerTendermintEvent: IndexerTendermintEvent,
1212
txId: number,
13+
_: string,
1314
): Handler<AssetCreateEventV1>[] {
1415
const handler: Handler<AssetCreateEventV1> = new AssetCreationHandler(
1516
this.block,

indexer/services/ender/src/validators/deleveraging-validator.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ export class DeleveragingValidator extends Validator<DeleveragingEventV1> {
3838
public createHandlers(
3939
indexerTendermintEvent: IndexerTendermintEvent,
4040
txId: number,
41+
_: string,
4142
): Handler<DeleveragingEventV1>[] {
4243
return [
4344
new DeleveragingHandler(

indexer/services/ender/src/validators/funding-validator.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ export class FundingValidator extends Validator<FundingEventV1> {
4242
public createHandlers(
4343
indexerTendermintEvent: IndexerTendermintEvent,
4444
txId: number,
45+
_: string,
4546
): Handler<FundingEventMessage>[] {
4647
const handler: Handler<FundingEventMessage> = new FundingHandler(
4748
this.block,

indexer/services/ender/src/validators/liquidity-tier-validator.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ export class LiquidityTierValidator extends Validator<LiquidityTierUpsertEventV1
3434
public createHandlers(
3535
indexerTendermintEvent: IndexerTendermintEvent,
3636
txId: number,
37+
_: string,
3738
): Handler<LiquidityTierUpsertEventV1>[] {
3839
const handler: Handler<LiquidityTierUpsertEventV1> = new LiquidityTierHandler(
3940
this.block,

indexer/services/ender/src/validators/market-validator.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ export class MarketValidator extends Validator<MarketEventV1> {
104104
public createHandlers(
105105
indexerTendermintEvent: IndexerTendermintEvent,
106106
txId: number,
107+
__: string,
107108
): Handler<MarketEventV1>[] {
108109
const Initializer:
109110
HandlerInitializer | undefined = this.getHandlerInitializer();

indexer/services/ender/src/validators/order-fill-validator.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ export class OrderFillValidator extends Validator<OrderFillEventV1> {
9393
public createHandlers(
9494
indexerTendermintEvent: IndexerTendermintEvent,
9595
txId: number,
96+
__: string,
9697
): Handler<OrderFillWithLiquidity>[] {
9798
const orderFillEventsWithLiquidity: OrderFillEventWithLiquidity[] = [
9899
{

indexer/services/ender/src/validators/perpetual-market-validator.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ export class PerpetualMarketValidator extends Validator<PerpetualMarketCreateEve
3838
public createHandlers(
3939
indexerTendermintEvent: IndexerTendermintEvent,
4040
txId: number,
41+
_: string,
4142
): Handler<PerpetualMarketCreateEventV1>[] {
4243
const handler: Handler<PerpetualMarketCreateEventV1> = new PerpetualMarketCreationHandler(
4344
this.block,

0 commit comments

Comments
 (0)