@powersync/service-module-mysql 0.9.10 → 0.9.12

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # @powersync/service-module-mysql
2
2
 
3
+ ## 0.9.12
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [fff0024]
8
+ - @powersync/service-sync-rules@0.29.7
9
+ - @powersync/service-core@1.16.3
10
+ - @powersync/lib-services-framework@0.7.10
11
+
12
+ ## 0.9.11
13
+
14
+ ### Patch Changes
15
+
16
+ - d889219: Fix memory leaks when retrying replication after errors.
17
+ - Updated dependencies [b364581]
18
+ - Updated dependencies [d889219]
19
+ - Updated dependencies [0ace0d3]
20
+ - Updated dependencies [7eb7957]
21
+ - Updated dependencies [b364581]
22
+ - @powersync/service-core@1.16.2
23
+
3
24
  ## 0.9.10
4
25
 
5
26
  ### Patch Changes
@@ -10,7 +10,6 @@ export declare class BinLogReplicationJob extends replication.AbstractReplicatio
10
10
  get slot_name(): string;
11
11
  keepAlive(): Promise<void>;
12
12
  replicate(): Promise<void>;
13
- replicateLoop(): Promise<void>;
14
13
  replicateOnce(): Promise<void>;
15
14
  getReplicationLagMillis(): Promise<number | undefined>;
16
15
  }
@@ -1,6 +1,6 @@
1
1
  import { container, logger as defaultLogger } from '@powersync/lib-services-framework';
2
2
  import { POWERSYNC_VERSION, replication } from '@powersync/service-core';
3
- import { BinlogConfigurationError, BinLogStream } from './BinLogStream.js';
3
+ import { BinLogStream } from './BinLogStream.js';
4
4
  export class BinLogReplicationJob extends replication.AbstractReplicationJob {
5
5
  connectionFactory;
6
6
  lastStream = null;
@@ -17,29 +17,29 @@ export class BinLogReplicationJob extends replication.AbstractReplicationJob {
17
17
  }
18
18
  async replicate() {
19
19
  try {
20
- await this.replicateLoop();
20
+ await this.replicateOnce();
21
21
  }
22
22
  catch (e) {
23
- // Fatal exception
24
- container.reporter.captureException(e, {
25
- metadata: {
26
- replication_slot: this.slot_name
23
+ if (!this.abortController.signal.aborted) {
24
+ this.logger.error(`Replication error`, e);
25
+ if (e.cause != null) {
26
+ this.logger.error(`cause`, e.cause);
27
27
  }
28
- });
29
- this.logger.error(`Replication failed`, e);
28
+ // Report the error if relevant, before retrying
29
+ container.reporter.captureException(e, {
30
+ metadata: {
31
+ replication_slot: this.slot_name
32
+ }
33
+ });
34
+ // This sets the retry delay
35
+ this.rateLimiter.reportError(e);
36
+ }
37
+ // No need to rethrow - the error is already logged, and retry behavior is the same on error
30
38
  }
31
39
  finally {
32
40
  this.abortController.abort();
33
41
  }
34
42
  }
35
- async replicateLoop() {
36
- while (!this.isStopped) {
37
- await this.replicateOnce();
38
- if (!this.isStopped) {
39
- await new Promise((resolve) => setTimeout(resolve, 5000));
40
- }
41
- }
42
- }
43
43
  async replicateOnce() {
44
44
  // New connections on every iteration (every error with retry),
45
45
  // otherwise we risk repeating errors related to the connection,
@@ -72,28 +72,6 @@ export class BinLogReplicationJob extends replication.AbstractReplicationJob {
72
72
  this.lastStream = stream;
73
73
  await stream.replicate();
74
74
  }
75
- catch (e) {
76
- if (this.abortController.signal.aborted) {
77
- return;
78
- }
79
- this.logger.error(`Replication error`, e);
80
- if (e.cause != null) {
81
- this.logger.error(`cause`, e.cause);
82
- }
83
- if (e instanceof BinlogConfigurationError) {
84
- throw e;
85
- }
86
- else {
87
- // Report the error if relevant, before retrying
88
- container.reporter.captureException(e, {
89
- metadata: {
90
- replication_slot: this.slot_name
91
- }
92
- });
93
- // This sets the retry delay
94
- this.rateLimiter?.reportError(e);
95
- }
96
- }
97
75
  finally {
98
76
  await connectionManager.end();
99
77
  }
@@ -1 +1 @@
1
- {"version":3,"file":"BinLogReplicationJob.js","sourceRoot":"","sources":["../../src/replication/BinLogReplicationJob.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"BinLogReplicationJob.js","sourceRoot":"","sources":["../../src/replication/BinLogReplicationJob.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,IAAI,aAAa,EAAE,MAAM,mCAAmC,CAAC;AACvF,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACzE,OAAO,EAA4B,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAO3E,MAAM,OAAO,oBAAqB,SAAQ,WAAW,CAAC,sBAAsB;IAClE,iBAAiB,CAAgC;IACjD,UAAU,GAAwB,IAAI,CAAC;IAE/C,YAAY,OAAoC;QAC9C,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,MAAM,GAAG,aAAa,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,cAAc,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;QAC/F,IAAI,CAAC,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IACrD,CAAC;IAED,IAAI,SAAS;QACX,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC;IACxC,CAAC;IAED,KAAK,CAAC,SAAS;QACb,2DAA2D;IAC7D,CAAC;IAED,KAAK,CAAC,SAAS;QACb,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;QAC7B,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;gBACzC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,mBAAmB,EAAE,CAAC,CAAC,CAAC;gBAC1C,IAAI,CAAC,CAAC,KAAK,IAAI,IAAI,EAAE,CAAC;oBACpB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC;gBACtC,CAAC;gBACD,gDAAgD;gBAChD,SAAS,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC,EAAE;oBACrC,QAAQ,EAAE;wBACR,gBAAgB,EAAE,IAAI,CAAC,SAAS;qBACjC;iBACF,CAAC,CAAC;gBACH,4BAA4B;gBAC5B,IAAI,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;YAClC,CAAC;YAED,4FAA4F;QAC9F,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,CAAC;QAC/B,CAAC;IACH,CAAC;IAED,KAAK,CAAC,aAAa;QACjB,+DAA+D;QAC/D,gEAAgE;QAChE,uCAAuC;QACvC,MAAM,iBAAiB,GAAG,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC;YACtD,iDAAiD;YACjD,WAAW,EAAE,MAAM;YACnB,eAAe,EAAE,CAAC;YAElB,iBAAiB,EAAE;gBACjB,8FAA8F;gBAC9F,iFAAiF;gBACjF,wEAAwE;gBACxE,YAAY,EAAE,WAAW;gBACzB,eAAe,EAAE,iBAAiB;gBAElC,8DAA8D;aAC/D;SACF,CAAC,CAAC;QACH,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,WAAW,EAAE,gBAAgB,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,CAAC,CAAC;YAClF,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;gBACnB,OAAO;YACT,CAAC;YACD,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC;gBAC9B,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,WAAW,EAAE,IAAI,CAAC,eAAe,CAAC,MAAM;gBACxC,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO;gBAC7B,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO;gBAC7B,WAAW,EAAE,iBAAiB;aAC/B,CAAC,CAAC;YACH,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC;YACzB,MAAM,MAAM,CAAC,SAAS,EAAE,CAAC;QAC3B,CAAC;gBAAS,CAAC;YACT,MAAM,iBAAiB,CAAC,GAAG,EAAE,CAAC;QAChC,CAAC;IACH,CAAC;IAED,KAAK,CAAC,uBAAuB;QAC3B,OAAO,IAAI,CAAC,UAAU,EAAE,uBAAuB,EAAE,CAAC;IACpD,CAAC;CACF"}
@@ -1,8 +1,12 @@
1
1
  import { NormalizedMySQLConnectionConfig } from '../types/types.js';
2
2
  import mysqlPromise from 'mysql2/promise';
3
3
  import mysql, { FieldPacket, RowDataPacket } from 'mysql2';
4
+ import { BaseObserver } from '@powersync/lib-services-framework';
4
5
  import { ZongJi } from '@powersync/mysql-zongji';
5
- export declare class MySQLConnectionManager {
6
+ export interface MySQLConnectionManagerListener {
7
+ onEnded(): void;
8
+ }
9
+ export declare class MySQLConnectionManager extends BaseObserver<MySQLConnectionManagerListener> {
6
10
  options: NormalizedMySQLConnectionConfig;
7
11
  poolOptions: mysqlPromise.PoolOptions;
8
12
  /**
@@ -1,7 +1,7 @@
1
1
  import * as mysql_utils from '../utils/mysql-utils.js';
2
- import { logger } from '@powersync/lib-services-framework';
2
+ import { BaseObserver, logger } from '@powersync/lib-services-framework';
3
3
  import { ZongJi } from '@powersync/mysql-zongji';
4
- export class MySQLConnectionManager {
4
+ export class MySQLConnectionManager extends BaseObserver {
5
5
  options;
6
6
  poolOptions;
7
7
  /**
@@ -15,6 +15,7 @@ export class MySQLConnectionManager {
15
15
  binlogListeners = [];
16
16
  isClosed = false;
17
17
  constructor(options, poolOptions) {
18
+ super();
18
19
  this.options = options;
19
20
  this.poolOptions = poolOptions;
20
21
  // The pool is lazy - no connections are opened until a query is performed.
@@ -84,18 +85,24 @@ export class MySQLConnectionManager {
84
85
  return this.promisePool.getConnection();
85
86
  }
86
87
  async end() {
87
- if (!this.isClosed) {
88
- for (const listener of this.binlogListeners) {
89
- listener.stop();
90
- }
91
- try {
92
- await this.promisePool.end();
93
- this.isClosed = true;
94
- }
95
- catch (error) {
96
- // We don't particularly care if any errors are thrown when shutting down the pool
97
- logger.warn('Error shutting down MySQL connection pool', error);
98
- }
88
+ if (this.isClosed) {
89
+ return;
90
+ }
91
+ for (const listener of this.binlogListeners) {
92
+ listener.stop();
93
+ }
94
+ try {
95
+ await this.promisePool.end();
96
+ }
97
+ catch (error) {
98
+ // We don't particularly care if any errors are thrown when shutting down the pool
99
+ logger.warn('Error shutting down MySQL connection pool', error);
100
+ }
101
+ finally {
102
+ this.isClosed = true;
103
+ this.iterateListeners((listener) => {
104
+ listener.onEnded?.();
105
+ });
99
106
  }
100
107
  }
101
108
  }
@@ -1 +1 @@
1
- {"version":3,"file":"MySQLConnectionManager.js","sourceRoot":"","sources":["../../src/replication/MySQLConnectionManager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"MySQLConnectionManager.js","sourceRoot":"","sources":["../../src/replication/MySQLConnectionManager.ts"],"names":[],"mappings":"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"}
@@ -1,20 +1,24 @@
1
1
  import { logger } from '@powersync/lib-services-framework';
2
2
  import { MySQLConnectionManager } from './MySQLConnectionManager.js';
3
3
  export class MySQLConnectionManagerFactory {
4
- connectionManagers;
4
+ connectionManagers = new Set();
5
5
  connectionConfig;
6
6
  constructor(connectionConfig) {
7
7
  this.connectionConfig = connectionConfig;
8
- this.connectionManagers = [];
9
8
  }
10
9
  create(poolOptions) {
11
10
  const manager = new MySQLConnectionManager(this.connectionConfig, poolOptions);
12
- this.connectionManagers.push(manager);
11
+ this.connectionManagers.add(manager);
12
+ manager.registerListener({
13
+ onEnded: () => {
14
+ this.connectionManagers.delete(manager);
15
+ }
16
+ });
13
17
  return manager;
14
18
  }
15
19
  async shutdown() {
16
20
  logger.info('Shutting down MySQL connection Managers...');
17
- for (const manager of this.connectionManagers) {
21
+ for (const manager of [...this.connectionManagers]) {
18
22
  await manager.end();
19
23
  }
20
24
  logger.info('MySQL connection Managers shutdown completed.');
@@ -1 +1 @@
1
- {"version":3,"file":"MySQLConnectionManagerFactory.js","sourceRoot":"","sources":["../../src/replication/MySQLConnectionManagerFactory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,mCAAmC,CAAC;AAE3D,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAGrE,MAAM,OAAO,6BAA6B;IACvB,kBAAkB,CAA2B;IAC9C,gBAAgB,CAA2B;IAE3D,YAAY,gBAA0C;QACpD,IAAI,CAAC,gBAAgB,GAAG,gBAAgB,CAAC;QACzC,IAAI,CAAC,kBAAkB,GAAG,EAAE,CAAC;IAC/B,CAAC;IAED,MAAM,CAAC,WAA8B;QACnC,MAAM,OAAO,GAAG,IAAI,sBAAsB,CAAC,IAAI,CAAC,gBAAgB,EAAE,WAAW,CAAC,CAAC;QAC/E,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACtC,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,KAAK,CAAC,QAAQ;QACZ,MAAM,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAC;QAC1D,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,kBAAkB,EAAE,CAAC;YAC9C,MAAM,OAAO,CAAC,GAAG,EAAE,CAAC;QACtB,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,+CAA+C,CAAC,CAAC;IAC/D,CAAC;CACF"}
1
+ {"version":3,"file":"MySQLConnectionManagerFactory.js","sourceRoot":"","sources":["../../src/replication/MySQLConnectionManagerFactory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,mCAAmC,CAAC;AAE3D,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAGrE,MAAM,OAAO,6BAA6B;IACvB,kBAAkB,GAAG,IAAI,GAAG,EAA0B,CAAC;IACxD,gBAAgB,CAA2B;IAE3D,YAAY,gBAA0C;QACpD,IAAI,CAAC,gBAAgB,GAAG,gBAAgB,CAAC;IAC3C,CAAC;IAED,MAAM,CAAC,WAA8B;QACnC,MAAM,OAAO,GAAG,IAAI,sBAAsB,CAAC,IAAI,CAAC,gBAAgB,EAAE,WAAW,CAAC,CAAC;QAC/E,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAErC,OAAO,CAAC,gBAAgB,CAAC;YACvB,OAAO,EAAE,GAAG,EAAE;gBACZ,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YAC1C,CAAC;SACF,CAAC,CAAC;QACH,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,KAAK,CAAC,QAAQ;QACZ,MAAM,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAC;QAC1D,KAAK,MAAM,OAAO,IAAI,CAAC,GAAG,IAAI,CAAC,kBAAkB,CAAC,EAAE,CAAC;YACnD,MAAM,OAAO,CAAC,GAAG,EAAE,CAAC;QACtB,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,+CAA+C,CAAC,CAAC;IAC/D,CAAC;CACF"}
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.9.10",
5
+ "version": "0.9.12",
6
6
  "license": "FSL-1.1-ALv2",
7
7
  "main": "dist/index.js",
8
8
  "type": "module",
@@ -30,18 +30,18 @@
30
30
  "ts-codec": "^1.3.0",
31
31
  "uri-js": "^4.4.1",
32
32
  "uuid": "^11.1.0",
33
- "@powersync/lib-services-framework": "0.7.9",
34
- "@powersync/service-core": "1.16.1",
35
- "@powersync/service-sync-rules": "0.29.6",
33
+ "@powersync/lib-services-framework": "0.7.10",
34
+ "@powersync/service-core": "1.16.3",
35
+ "@powersync/service-sync-rules": "0.29.7",
36
36
  "@powersync/service-types": "0.13.1",
37
37
  "@powersync/service-jsonbig": "0.17.12"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@types/async": "^3.2.24",
41
41
  "@types/semver": "^7.5.4",
42
- "@powersync/service-core-tests": "0.12.10",
43
- "@powersync/service-module-mongodb-storage": "0.12.10",
44
- "@powersync/service-module-postgres-storage": "0.10.10"
42
+ "@powersync/service-core-tests": "0.12.12",
43
+ "@powersync/service-module-mongodb-storage": "0.12.12",
44
+ "@powersync/service-module-postgres-storage": "0.10.12"
45
45
  },
46
46
  "scripts": {
47
47
  "build": "tsc -b",
@@ -27,30 +27,29 @@ export class BinLogReplicationJob extends replication.AbstractReplicationJob {
27
27
 
28
28
  async replicate() {
29
29
  try {
30
- await this.replicateLoop();
30
+ await this.replicateOnce();
31
31
  } catch (e) {
32
- // Fatal exception
33
- container.reporter.captureException(e, {
34
- metadata: {
35
- replication_slot: this.slot_name
32
+ if (!this.abortController.signal.aborted) {
33
+ this.logger.error(`Replication error`, e);
34
+ if (e.cause != null) {
35
+ this.logger.error(`cause`, e.cause);
36
36
  }
37
- });
38
- this.logger.error(`Replication failed`, e);
37
+ // Report the error if relevant, before retrying
38
+ container.reporter.captureException(e, {
39
+ metadata: {
40
+ replication_slot: this.slot_name
41
+ }
42
+ });
43
+ // This sets the retry delay
44
+ this.rateLimiter.reportError(e);
45
+ }
46
+
47
+ // No need to rethrow - the error is already logged, and retry behavior is the same on error
39
48
  } finally {
40
49
  this.abortController.abort();
41
50
  }
42
51
  }
43
52
 
44
- async replicateLoop() {
45
- while (!this.isStopped) {
46
- await this.replicateOnce();
47
-
48
- if (!this.isStopped) {
49
- await new Promise((resolve) => setTimeout(resolve, 5000));
50
- }
51
- }
52
- }
53
-
54
53
  async replicateOnce() {
55
54
  // New connections on every iteration (every error with retry),
56
55
  // otherwise we risk repeating errors related to the connection,
@@ -84,27 +83,6 @@ export class BinLogReplicationJob extends replication.AbstractReplicationJob {
84
83
  });
85
84
  this.lastStream = stream;
86
85
  await stream.replicate();
87
- } catch (e) {
88
- if (this.abortController.signal.aborted) {
89
- return;
90
- }
91
- this.logger.error(`Replication error`, e);
92
- if (e.cause != null) {
93
- this.logger.error(`cause`, e.cause);
94
- }
95
-
96
- if (e instanceof BinlogConfigurationError) {
97
- throw e;
98
- } else {
99
- // Report the error if relevant, before retrying
100
- container.reporter.captureException(e, {
101
- metadata: {
102
- replication_slot: this.slot_name
103
- }
104
- });
105
- // This sets the retry delay
106
- this.rateLimiter?.reportError(e);
107
- }
108
86
  } finally {
109
87
  await connectionManager.end();
110
88
  }
@@ -2,10 +2,14 @@ import { NormalizedMySQLConnectionConfig } from '../types/types.js';
2
2
  import mysqlPromise from 'mysql2/promise';
3
3
  import mysql, { FieldPacket, RowDataPacket } from 'mysql2';
4
4
  import * as mysql_utils from '../utils/mysql-utils.js';
5
- import { logger } from '@powersync/lib-services-framework';
5
+ import { BaseObserver, logger } from '@powersync/lib-services-framework';
6
6
  import { ZongJi } from '@powersync/mysql-zongji';
7
7
 
8
- export class MySQLConnectionManager {
8
+ export interface MySQLConnectionManagerListener {
9
+ onEnded(): void;
10
+ }
11
+
12
+ export class MySQLConnectionManager extends BaseObserver<MySQLConnectionManagerListener> {
9
13
  /**
10
14
  * Pool that can create streamable connections
11
15
  */
@@ -23,6 +27,7 @@ export class MySQLConnectionManager {
23
27
  public options: NormalizedMySQLConnectionConfig,
24
28
  public poolOptions: mysqlPromise.PoolOptions
25
29
  ) {
30
+ super();
26
31
  // The pool is lazy - no connections are opened until a query is performed.
27
32
  this.pool = mysql_utils.createPool(options, poolOptions);
28
33
  this.promisePool = this.pool.promise();
@@ -98,18 +103,24 @@ export class MySQLConnectionManager {
98
103
  }
99
104
 
100
105
  async end(): Promise<void> {
101
- if (!this.isClosed) {
102
- for (const listener of this.binlogListeners) {
103
- listener.stop();
104
- }
105
-
106
- try {
107
- await this.promisePool.end();
108
- this.isClosed = true;
109
- } catch (error) {
110
- // We don't particularly care if any errors are thrown when shutting down the pool
111
- logger.warn('Error shutting down MySQL connection pool', error);
112
- }
106
+ if (this.isClosed) {
107
+ return;
108
+ }
109
+
110
+ for (const listener of this.binlogListeners) {
111
+ listener.stop();
112
+ }
113
+
114
+ try {
115
+ await this.promisePool.end();
116
+ } catch (error) {
117
+ // We don't particularly care if any errors are thrown when shutting down the pool
118
+ logger.warn('Error shutting down MySQL connection pool', error);
119
+ } finally {
120
+ this.isClosed = true;
121
+ this.iterateListeners((listener) => {
122
+ listener.onEnded?.();
123
+ });
113
124
  }
114
125
  }
115
126
  }
@@ -4,23 +4,28 @@ import { MySQLConnectionManager } from './MySQLConnectionManager.js';
4
4
  import { ResolvedConnectionConfig } from '../types/types.js';
5
5
 
6
6
  export class MySQLConnectionManagerFactory {
7
- private readonly connectionManagers: MySQLConnectionManager[];
7
+ private readonly connectionManagers = new Set<MySQLConnectionManager>();
8
8
  public readonly connectionConfig: ResolvedConnectionConfig;
9
9
 
10
10
  constructor(connectionConfig: ResolvedConnectionConfig) {
11
11
  this.connectionConfig = connectionConfig;
12
- this.connectionManagers = [];
13
12
  }
14
13
 
15
14
  create(poolOptions: mysql.PoolOptions) {
16
15
  const manager = new MySQLConnectionManager(this.connectionConfig, poolOptions);
17
- this.connectionManagers.push(manager);
16
+ this.connectionManagers.add(manager);
17
+
18
+ manager.registerListener({
19
+ onEnded: () => {
20
+ this.connectionManagers.delete(manager);
21
+ }
22
+ });
18
23
  return manager;
19
24
  }
20
25
 
21
26
  async shutdown() {
22
27
  logger.info('Shutting down MySQL connection Managers...');
23
- for (const manager of this.connectionManagers) {
28
+ for (const manager of [...this.connectionManagers]) {
24
29
  await manager.end();
25
30
  }
26
31
  logger.info('MySQL connection Managers shutdown completed.');