@powersync/service-module-mysql 0.6.5 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/dist/api/MySQLRouteAPIAdapter.d.ts +1 -1
  3. package/dist/api/MySQLRouteAPIAdapter.js +1 -1
  4. package/dist/api/MySQLRouteAPIAdapter.js.map +1 -1
  5. package/dist/replication/BinLogReplicationJob.d.ts +2 -0
  6. package/dist/replication/BinLogReplicationJob.js +10 -3
  7. package/dist/replication/BinLogReplicationJob.js.map +1 -1
  8. package/dist/replication/BinLogReplicator.d.ts +1 -0
  9. package/dist/replication/BinLogReplicator.js +22 -0
  10. package/dist/replication/BinLogReplicator.js.map +1 -1
  11. package/dist/replication/BinLogStream.d.ts +17 -1
  12. package/dist/replication/BinLogStream.js +126 -174
  13. package/dist/replication/BinLogStream.js.map +1 -1
  14. package/dist/replication/MySQLConnectionManager.d.ts +1 -1
  15. package/dist/replication/MySQLConnectionManager.js +2 -1
  16. package/dist/replication/MySQLConnectionManager.js.map +1 -1
  17. package/dist/replication/zongji/BinLogListener.d.ts +54 -0
  18. package/dist/replication/zongji/BinLogListener.js +192 -0
  19. package/dist/replication/zongji/BinLogListener.js.map +1 -0
  20. package/dist/replication/zongji/zongji-utils.d.ts +5 -4
  21. package/dist/replication/zongji/zongji-utils.js +3 -0
  22. package/dist/replication/zongji/zongji-utils.js.map +1 -1
  23. package/dist/types/types.d.ts +2 -0
  24. package/dist/types/types.js +5 -1
  25. package/dist/types/types.js.map +1 -1
  26. package/dist/utils/mysql-utils.js +1 -0
  27. package/dist/utils/mysql-utils.js.map +1 -1
  28. package/package.json +9 -9
  29. package/src/api/MySQLRouteAPIAdapter.ts +1 -1
  30. package/src/replication/BinLogReplicationJob.ts +11 -3
  31. package/src/replication/BinLogReplicator.ts +25 -0
  32. package/src/replication/BinLogStream.ts +151 -201
  33. package/src/replication/MySQLConnectionManager.ts +2 -1
  34. package/src/replication/zongji/BinLogListener.ts +243 -0
  35. package/src/replication/zongji/zongji-utils.ts +10 -5
  36. package/src/types/types.ts +8 -1
  37. package/src/utils/mysql-utils.ts +1 -0
  38. package/test/src/BinLogListener.test.ts +161 -0
  39. package/test/src/BinLogStream.test.ts +4 -9
  40. package/test/src/mysql-to-sqlite.test.ts +1 -1
  41. package/test/src/util.ts +12 -0
  42. package/test/tsconfig.json +1 -1
  43. package/tsconfig.tsbuildinfo +1 -1
  44. package/src/replication/zongji/zongji.d.ts +0 -129
@@ -0,0 +1,192 @@
1
+ import * as common from '../../common/common-index.js';
2
+ import async from 'async';
3
+ import * as zongji_utils from './zongji-utils.js';
4
+ import { logger as defaultLogger } from '@powersync/lib-services-framework';
5
+ // Maximum time the processing queue can be paused before resuming automatically
6
+ // MySQL server will automatically terminate replication connections after 60 seconds of inactivity, so this guards against that.
7
+ const MAX_QUEUE_PAUSE_TIME_MS = 45_000;
8
+ /**
9
+ * Wrapper class for the Zongji BinLog listener. Internally handles the creation and management of the listener and posts
10
+ * events on the provided BinLogEventHandler.
11
+ */
12
+ export class BinLogListener {
13
+ options;
14
+ connectionManager;
15
+ eventHandler;
16
+ binLogPosition;
17
+ currentGTID;
18
+ logger;
19
+ zongji;
20
+ processingQueue;
21
+ /**
22
+ * The combined size in bytes of all the binlog events currently in the processing queue.
23
+ */
24
+ queueMemoryUsage;
25
+ constructor(options) {
26
+ this.options = options;
27
+ this.logger = options.logger ?? defaultLogger;
28
+ this.connectionManager = options.connectionManager;
29
+ this.eventHandler = options.eventHandler;
30
+ this.binLogPosition = options.startPosition;
31
+ this.currentGTID = null;
32
+ this.processingQueue = async.queue(this.createQueueWorker(), 1);
33
+ this.queueMemoryUsage = 0;
34
+ this.zongji = this.createZongjiListener();
35
+ }
36
+ /**
37
+ * The queue memory limit in bytes as defined in the connection options.
38
+ * @private
39
+ */
40
+ get queueMemoryLimit() {
41
+ return this.connectionManager.options.binlog_queue_memory_limit * 1024 * 1024;
42
+ }
43
+ async start() {
44
+ if (this.isStopped) {
45
+ return;
46
+ }
47
+ this.logger.info(`Starting replication. Created replica client with serverId:${this.options.serverId}`);
48
+ this.zongji.start({
49
+ // We ignore the unknown/heartbeat event since it currently serves no purpose other than to keep the connection alive
50
+ // tablemap events always need to be included for the other row events to work
51
+ includeEvents: ['tablemap', 'writerows', 'updaterows', 'deleterows', 'xid', 'rotate', 'gtidlog'],
52
+ includeSchema: { [this.connectionManager.databaseName]: this.options.includedTables },
53
+ filename: this.binLogPosition.filename,
54
+ position: this.binLogPosition.offset,
55
+ serverId: this.options.serverId
56
+ });
57
+ return new Promise((resolve, reject) => {
58
+ // Handle an edge case where the listener has already been stopped before completing startup
59
+ if (this.isStopped) {
60
+ this.logger.info('BinLog listener was stopped before startup completed.');
61
+ resolve();
62
+ }
63
+ this.zongji.on('error', (error) => {
64
+ if (!this.isStopped) {
65
+ this.logger.error('Binlog listener error:', error);
66
+ this.stop();
67
+ reject(error);
68
+ }
69
+ else {
70
+ this.logger.warn('Binlog listener error during shutdown:', error);
71
+ }
72
+ });
73
+ this.processingQueue.error((error) => {
74
+ if (!this.isStopped) {
75
+ this.logger.error('BinlogEvent processing error:', error);
76
+ this.stop();
77
+ reject(error);
78
+ }
79
+ else {
80
+ this.logger.warn('BinlogEvent processing error during shutdown:', error);
81
+ }
82
+ });
83
+ this.zongji.on('stopped', () => {
84
+ resolve();
85
+ this.logger.info('BinLog listener stopped. Replication ended.');
86
+ });
87
+ });
88
+ }
89
+ stop() {
90
+ if (!this.isStopped) {
91
+ this.zongji.stop();
92
+ this.processingQueue.kill();
93
+ }
94
+ }
95
+ get isStopped() {
96
+ return this.zongji.stopped;
97
+ }
98
+ createZongjiListener() {
99
+ const zongji = this.connectionManager.createBinlogListener();
100
+ zongji.on('binlog', async (evt) => {
101
+ this.logger.info(`Received Binlog event:${evt.getEventName()}`);
102
+ this.processingQueue.push(evt);
103
+ this.queueMemoryUsage += evt.size;
104
+ // When the processing queue grows past the threshold, we pause the binlog listener
105
+ if (this.isQueueOverCapacity()) {
106
+ this.logger.info(`Binlog processing queue has reached its memory limit of [${this.connectionManager.options.binlog_queue_memory_limit}MB]. Pausing Binlog listener.`);
107
+ zongji.pause();
108
+ const resumeTimeoutPromise = new Promise((resolve) => {
109
+ setTimeout(() => resolve('timeout'), MAX_QUEUE_PAUSE_TIME_MS);
110
+ });
111
+ await Promise.race([this.processingQueue.empty(), resumeTimeoutPromise]);
112
+ this.logger.info(`Binlog processing queue backlog cleared. Resuming Binlog listener.`);
113
+ zongji.resume();
114
+ }
115
+ });
116
+ zongji.on('ready', async () => {
117
+ // Set a heartbeat interval for the Zongji replication connection
118
+ // Zongji does not explicitly handle the heartbeat events - they are categorized as event:unknown
119
+ // The heartbeat events are enough to keep the connection alive for setTimeout to work on the socket.
120
+ await new Promise((resolve, reject) => {
121
+ this.zongji.connection.query(
122
+ // In nanoseconds, 10^9 = 1s
123
+ 'set @master_heartbeat_period=28*1000000000', (error, results, fields) => {
124
+ if (error) {
125
+ reject(error);
126
+ }
127
+ else {
128
+ this.logger.info('Successfully set up replication connection heartbeat...');
129
+ resolve(results);
130
+ }
131
+ });
132
+ });
133
+ // The _socket member is only set after a query is run on the connection, so we set the timeout after setting the heartbeat.
134
+ // The timeout here must be greater than the master_heartbeat_period.
135
+ const socket = this.zongji.connection._socket;
136
+ socket.setTimeout(60_000, () => {
137
+ this.logger.info('Destroying socket due to replication connection timeout.');
138
+ socket.destroy(new Error('Replication connection timeout.'));
139
+ });
140
+ this.logger.info(`BinLog listener setup complete. Reading binlog from: ${this.binLogPosition.filename}:${this.binLogPosition.offset}`);
141
+ });
142
+ return zongji;
143
+ }
144
+ createQueueWorker() {
145
+ return async (evt) => {
146
+ switch (true) {
147
+ case zongji_utils.eventIsGTIDLog(evt):
148
+ this.currentGTID = common.ReplicatedGTID.fromBinLogEvent({
149
+ raw_gtid: {
150
+ server_id: evt.serverId,
151
+ transaction_range: evt.transactionRange
152
+ },
153
+ position: {
154
+ filename: this.binLogPosition.filename,
155
+ offset: evt.nextPosition
156
+ }
157
+ });
158
+ await this.eventHandler.onTransactionStart({ timestamp: new Date(evt.timestamp) });
159
+ break;
160
+ case zongji_utils.eventIsRotation(evt):
161
+ this.binLogPosition.filename = evt.binlogName;
162
+ this.binLogPosition.offset = evt.position;
163
+ await this.eventHandler.onRotate();
164
+ break;
165
+ case zongji_utils.eventIsWriteMutation(evt):
166
+ await this.eventHandler.onWrite(evt.rows, evt.tableMap[evt.tableId]);
167
+ break;
168
+ case zongji_utils.eventIsUpdateMutation(evt):
169
+ await this.eventHandler.onUpdate(evt.rows.map((row) => row.after), evt.rows.map((row) => row.before), evt.tableMap[evt.tableId]);
170
+ break;
171
+ case zongji_utils.eventIsDeleteMutation(evt):
172
+ await this.eventHandler.onDelete(evt.rows, evt.tableMap[evt.tableId]);
173
+ break;
174
+ case zongji_utils.eventIsXid(evt):
175
+ const LSN = new common.ReplicatedGTID({
176
+ raw_gtid: this.currentGTID.raw,
177
+ position: {
178
+ filename: this.binLogPosition.filename,
179
+ offset: evt.nextPosition
180
+ }
181
+ }).comparable;
182
+ await this.eventHandler.onCommit(LSN);
183
+ break;
184
+ }
185
+ this.queueMemoryUsage -= evt.size;
186
+ };
187
+ }
188
+ isQueueOverCapacity() {
189
+ return this.queueMemoryUsage >= this.queueMemoryLimit;
190
+ }
191
+ }
192
+ //# sourceMappingURL=BinLogListener.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BinLogListener.js","sourceRoot":"","sources":["../../../src/replication/zongji/BinLogListener.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,8 @@
1
- import { BinLogEvent, BinLogGTIDLogEvent, BinLogMutationEvent, BinLogRotationEvent, BinLogUpdateEvent, BinLogXidEvent } from '@powersync/mysql-zongji';
1
+ import { BinLogEvent, BinLogGTIDLogEvent, BinLogRowEvent, BinLogRotationEvent, BinLogTableMapEvent, BinLogRowUpdateEvent, BinLogXidEvent } from '@powersync/mysql-zongji';
2
2
  export declare function eventIsGTIDLog(event: BinLogEvent): event is BinLogGTIDLogEvent;
3
+ export declare function eventIsTableMap(event: BinLogEvent): event is BinLogTableMapEvent;
3
4
  export declare function eventIsXid(event: BinLogEvent): event is BinLogXidEvent;
4
5
  export declare function eventIsRotation(event: BinLogEvent): event is BinLogRotationEvent;
5
- export declare function eventIsWriteMutation(event: BinLogEvent): event is BinLogMutationEvent;
6
- export declare function eventIsDeleteMutation(event: BinLogEvent): event is BinLogMutationEvent;
7
- export declare function eventIsUpdateMutation(event: BinLogEvent): event is BinLogUpdateEvent;
6
+ export declare function eventIsWriteMutation(event: BinLogEvent): event is BinLogRowEvent;
7
+ export declare function eventIsDeleteMutation(event: BinLogEvent): event is BinLogRowEvent;
8
+ export declare function eventIsUpdateMutation(event: BinLogEvent): event is BinLogRowUpdateEvent;
@@ -1,6 +1,9 @@
1
1
  export function eventIsGTIDLog(event) {
2
2
  return event.getEventName() == 'gtidlog';
3
3
  }
4
+ export function eventIsTableMap(event) {
5
+ return event.getEventName() == 'tablemap';
6
+ }
4
7
  export function eventIsXid(event) {
5
8
  return event.getEventName() == 'xid';
6
9
  }
@@ -1 +1 @@
1
- {"version":3,"file":"zongji-utils.js","sourceRoot":"","sources":["../../../src/replication/zongji/zongji-utils.ts"],"names":[],"mappings":"AASA,MAAM,UAAU,cAAc,CAAC,KAAkB;IAC/C,OAAO,KAAK,CAAC,YAAY,EAAE,IAAI,SAAS,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,KAAkB;IAC3C,OAAO,KAAK,CAAC,YAAY,EAAE,IAAI,KAAK,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAAkB;IAChD,OAAO,KAAK,CAAC,YAAY,EAAE,IAAI,QAAQ,CAAC;AAC1C,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,KAAkB;IACrD,OAAO,KAAK,CAAC,YAAY,EAAE,IAAI,WAAW,CAAC;AAC7C,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,KAAkB;IACtD,OAAO,KAAK,CAAC,YAAY,EAAE,IAAI,YAAY,CAAC;AAC9C,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,KAAkB;IACtD,OAAO,KAAK,CAAC,YAAY,EAAE,IAAI,YAAY,CAAC;AAC9C,CAAC"}
1
+ {"version":3,"file":"zongji-utils.js","sourceRoot":"","sources":["../../../src/replication/zongji/zongji-utils.ts"],"names":[],"mappings":"AAUA,MAAM,UAAU,cAAc,CAAC,KAAkB;IAC/C,OAAO,KAAK,CAAC,YAAY,EAAE,IAAI,SAAS,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAAkB;IAChD,OAAO,KAAK,CAAC,YAAY,EAAE,IAAI,UAAU,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,KAAkB;IAC3C,OAAO,KAAK,CAAC,YAAY,EAAE,IAAI,KAAK,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAAkB;IAChD,OAAO,KAAK,CAAC,YAAY,EAAE,IAAI,QAAQ,CAAC;AAC1C,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,KAAkB;IACrD,OAAO,KAAK,CAAC,YAAY,EAAE,IAAI,WAAW,CAAC;AAC7C,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,KAAkB;IACtD,OAAO,KAAK,CAAC,YAAY,EAAE,IAAI,YAAY,CAAC;AAC9C,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,KAAkB;IACtD,OAAO,KAAK,CAAC,YAAY,EAAE,IAAI,YAAY,CAAC;AAC9C,CAAC"}
@@ -14,6 +14,7 @@ export interface NormalizedMySQLConnectionConfig {
14
14
  client_certificate?: string;
15
15
  client_private_key?: string;
16
16
  lookup?: LookupFunction;
17
+ binlog_queue_memory_limit: number;
17
18
  }
18
19
  export declare const MySQLConnectionConfig: t.Intersection<t.Codec<{
19
20
  type: string;
@@ -38,6 +39,7 @@ export declare const MySQLConnectionConfig: t.Intersection<t.Codec<{
38
39
  client_certificate: t.OptionalCodec<t.Codec<string, string, string, t.CodecProps>>;
39
40
  client_private_key: t.OptionalCodec<t.Codec<string, string, string, t.CodecProps>>;
40
41
  reject_ip_ranges: t.OptionalCodec<t.Codec<string[], string[], string, t.CodecProps>>;
42
+ binlog_queue_memory_limit: t.OptionalCodec<t.Codec<number, number, string, t.CodecProps>>;
41
43
  }>>;
42
44
  /**
43
45
  * Config input specified when starting services
@@ -15,7 +15,9 @@ export const MySQLConnectionConfig = service_types.configFile.DataSourceConfig.a
15
15
  cacert: t.string.optional(),
16
16
  client_certificate: t.string.optional(),
17
17
  client_private_key: t.string.optional(),
18
- reject_ip_ranges: t.array(t.string).optional()
18
+ reject_ip_ranges: t.array(t.string).optional(),
19
+ // The combined size of binlog events that can be queued in memory before throttling is applied.
20
+ binlog_queue_memory_limit: t.number.optional()
19
21
  }));
20
22
  /**
21
23
  * Validate and normalize connection options.
@@ -61,6 +63,8 @@ export function normalizeConnectionConfig(options) {
61
63
  username,
62
64
  password,
63
65
  server_id: options.server_id ?? 1,
66
+ // Binlog processing queue memory limit before throttling is applied.
67
+ binlog_queue_memory_limit: options.binlog_queue_memory_limit ?? 50,
64
68
  lookup
65
69
  };
66
70
  }
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types/types.ts"],"names":[],"mappings":"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"}
@@ -30,6 +30,7 @@ export function createPool(config, options) {
30
30
  return mysql.createPool({
31
31
  host: config.hostname,
32
32
  user: config.username,
33
+ port: config.port,
33
34
  password: config.password,
34
35
  database: config.database,
35
36
  ssl: hasSSLOptions ? sslOptions : undefined,
@@ -1 +1 @@
1
- {"version":3,"file":"mysql-utils.js","sourceRoot":"","sources":["../../src/utils/mysql-utils.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"mysql-utils.js","sourceRoot":"","sources":["../../src/utils/mysql-utils.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@powersync/service-module-mysql",
3
3
  "repository": "https://github.com/powersync-ja/powersync-service",
4
4
  "types": "dist/index.d.ts",
5
- "version": "0.6.5",
5
+ "version": "0.7.0",
6
6
  "license": "FSL-1.1-Apache-2.0",
7
7
  "main": "dist/index.js",
8
8
  "type": "module",
@@ -22,25 +22,25 @@
22
22
  }
23
23
  },
24
24
  "dependencies": {
25
- "@powersync/mysql-zongji": "^0.1.0",
25
+ "@powersync/mysql-zongji": "0.2.0",
26
26
  "async": "^3.2.4",
27
27
  "mysql2": "^3.11.0",
28
28
  "semver": "^7.5.4",
29
29
  "ts-codec": "^1.3.0",
30
30
  "uri-js": "^4.4.1",
31
31
  "uuid": "^11.1.0",
32
- "@powersync/lib-services-framework": "0.6.0",
33
- "@powersync/service-core": "1.12.1",
34
- "@powersync/service-jsonbig": "0.17.10",
32
+ "@powersync/lib-services-framework": "0.7.0",
33
+ "@powersync/service-core": "1.13.0",
35
34
  "@powersync/service-sync-rules": "0.27.0",
36
- "@powersync/service-types": "0.11.0"
35
+ "@powersync/service-types": "0.12.0",
36
+ "@powersync/service-jsonbig": "0.17.10"
37
37
  },
38
38
  "devDependencies": {
39
39
  "@types/async": "^3.2.24",
40
40
  "@types/semver": "^7.5.4",
41
- "@powersync/service-core-tests": "0.9.5",
42
- "@powersync/service-module-mongodb-storage": "0.9.5",
43
- "@powersync/service-module-postgres-storage": "0.7.5"
41
+ "@powersync/service-core-tests": "0.10.0",
42
+ "@powersync/service-module-mongodb-storage": "0.10.0",
43
+ "@powersync/service-module-postgres-storage": "0.8.0"
44
44
  },
45
45
  "scripts": {
46
46
  "build": "tsc -b",
@@ -249,7 +249,7 @@ export class MySQLRouteAPIAdapter implements api.RouteAPI {
249
249
  };
250
250
  }
251
251
 
252
- async getReplicationLag(options: api.ReplicationLagOptions): Promise<number | undefined> {
252
+ async getReplicationLagBytes(options: api.ReplicationLagOptions): Promise<number | undefined> {
253
253
  const { bucketStorage } = options;
254
254
  const lastCheckpoint = await bucketStorage.getCheckpoint();
255
255
 
@@ -1,4 +1,4 @@
1
- import { container } from '@powersync/lib-services-framework';
1
+ import { container, logger as defaultLogger } from '@powersync/lib-services-framework';
2
2
  import { replication } from '@powersync/service-core';
3
3
  import { BinlogConfigurationError, BinLogStream } from './BinLogStream.js';
4
4
  import { MySQLConnectionManagerFactory } from './MySQLConnectionManagerFactory.js';
@@ -9,9 +9,11 @@ export interface BinLogReplicationJobOptions extends replication.AbstractReplica
9
9
 
10
10
  export class BinLogReplicationJob extends replication.AbstractReplicationJob {
11
11
  private connectionFactory: MySQLConnectionManagerFactory;
12
+ private lastStream: BinLogStream | null = null;
12
13
 
13
14
  constructor(options: BinLogReplicationJobOptions) {
14
15
  super(options);
16
+ this.logger = defaultLogger.child({ prefix: `[powersync_${this.options.storage.group_id}] ` });
15
17
  this.connectionFactory = options.connectionFactory;
16
18
  }
17
19
 
@@ -31,7 +33,7 @@ export class BinLogReplicationJob extends replication.AbstractReplicationJob {
31
33
  replication_slot: this.slot_name
32
34
  }
33
35
  });
34
- this.logger.error(`Replication failed on ${this.slot_name}`, e);
36
+ this.logger.error(`Replication failed`, e);
35
37
  } finally {
36
38
  this.abortController.abort();
37
39
  }
@@ -61,17 +63,19 @@ export class BinLogReplicationJob extends replication.AbstractReplicationJob {
61
63
  return;
62
64
  }
63
65
  const stream = new BinLogStream({
66
+ logger: this.logger,
64
67
  abortSignal: this.abortController.signal,
65
68
  storage: this.options.storage,
66
69
  metrics: this.options.metrics,
67
70
  connections: connectionManager
68
71
  });
72
+ this.lastStream = stream;
69
73
  await stream.replicate();
70
74
  } catch (e) {
71
75
  if (this.abortController.signal.aborted) {
72
76
  return;
73
77
  }
74
- this.logger.error(`Sync rules ${this.id} Replication error`, e);
78
+ this.logger.error(`Replication error`, e);
75
79
  if (e.cause != null) {
76
80
  this.logger.error(`cause`, e.cause);
77
81
  }
@@ -92,4 +96,8 @@ export class BinLogReplicationJob extends replication.AbstractReplicationJob {
92
96
  await connectionManager.end();
93
97
  }
94
98
  }
99
+
100
+ async getReplicationLagMillis(): Promise<number | undefined> {
101
+ return this.lastStream?.getReplicationLagMillis();
102
+ }
95
103
  }
@@ -38,4 +38,29 @@ export class BinLogReplicator extends replication.AbstractReplicator<BinLogRepli
38
38
  async testConnection() {
39
39
  return await MySQLModule.testConnection(this.connectionFactory.connectionConfig);
40
40
  }
41
+
42
+ async getReplicationLagMillis(): Promise<number | undefined> {
43
+ const lag = await super.getReplicationLagMillis();
44
+ if (lag != null) {
45
+ return lag;
46
+ }
47
+
48
+ // Booting or in an error loop. Check last active replication status.
49
+ // This includes sync rules in an ERROR state.
50
+ const content = await this.storage.getActiveSyncRulesContent();
51
+ if (content == null) {
52
+ return undefined;
53
+ }
54
+ // Measure the lag from the last commit or keepalive timestamp.
55
+ // This is not 100% accurate since it is the commit time in the storage db rather than
56
+ // the source db, but it's the best we currently have for mysql.
57
+ const checkpointTs = content.last_checkpoint_ts?.getTime() ?? 0;
58
+ const keepaliveTs = content.last_keepalive_ts?.getTime() ?? 0;
59
+ const latestTs = Math.max(checkpointTs, keepaliveTs);
60
+ if (latestTs != 0) {
61
+ return Date.now() - latestTs;
62
+ }
63
+
64
+ return undefined;
65
+ }
41
66
  }