Skip to content

Commit 6f1be8f

Browse files
fix port retry not working when MySQL X can't bind to a port
1 parent a104598 commit 6f1be8f

File tree

1 file changed

+25
-17
lines changed

1 file changed

+25
-17
lines changed

src/libraries/Executor.ts

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ class Executor {
2020
version: string;
2121
versionInstalledOnSystem: boolean;
2222
databasePath: string
23+
killedFromPortIssue: boolean;
2324

2425
constructor(logger: Logger) {
2526
this.logger = logger;
@@ -75,6 +76,7 @@ class Executor {
7576

7677
const mysqlArguments = [
7778
'--no-defaults',
79+
'--mysqlx=FORCE',
7880
`--port=${port}`,
7981
`--datadir=${datadir}`,
8082
`--mysqlx-port=${mySQLXPort}`,
@@ -85,7 +87,6 @@ class Executor {
8587
`--init-file=${dbPath}/init.sql`,
8688
'--bind-address=127.0.0.1',
8789
'--innodb-doublewrite=OFF',
88-
'--mysqlx=FORCE',
8990
`--log-error=${errorLogFile}`,
9091
`--user=${os.userInfo().username}`
9192
]
@@ -106,7 +107,7 @@ class Executor {
106107
} else {
107108
throw 'Could not install MySQL X as the path to the plugin cannot be found.'
108109
}
109-
mysqlArguments.splice(1, 0, `--plugin-dir=${pluginPath}`, `--plugin-load-add=mysqlx=mysqlx.${pluginExtension}`)
110+
mysqlArguments.splice(1, 0, `--plugin-dir=${pluginPath}`, `--early-plugin-load=mysqlx=mysqlx.${pluginExtension};`)
110111
}
111112

112113
const process = spawn(binaryFilepath, mysqlArguments, {signal: this.DBDestroySignal.signal, killSignal: 'SIGKILL'})
@@ -130,11 +131,15 @@ class Executor {
130131
errorLog = `ERROR WHILE READING LOG: ${e}`
131132
}
132133

133-
const portIssue = errorLog.includes("Do you already have another mysqld server running")
134-
const xPortIssue = errorLog.includes("Do you already have another mysqld server running with Mysqlx")
135-
this.logger.log('Exiting because of a port issue:', portIssue, '. MySQL X Plugin failed to bind:', xPortIssue)
134+
if (!this.killedFromPortIssue) {
135+
//A check is done after the error log file says that the server is ready for connections.
136+
//When MySQL X cannot bind to a port, the server still says it is ready for connections so killedFromPortIssue gets set to true
137+
//This if statement will be ran if the server did not encounter a port issue or if the MySQL server could not bind to its port
138+
this.killedFromPortIssue = errorLog.includes("Do you already have another mysqld server running")
139+
this.logger.log('Did a port issue occur between server start and server close:', this.killedFromPortIssue)
140+
}
136141

137-
if (portIssue || xPortIssue) {
142+
if (this.killedFromPortIssue) {
138143
this.logger.log('Error log when exiting for port in use error:', errorLog)
139144
try {
140145
this.logger.log('Deleting database path after port issue...')
@@ -196,17 +201,20 @@ class Executor {
196201
if (curr.dev !== 0) {
197202
//File exists
198203
const file = await fsPromises.readFile(errorLogFile, {encoding: 'utf8'})
199-
if (file.includes("X Plugin can't bind to it")) {
200-
//As stated in the MySQL X Plugin documentation at https://dev.mysql.com/doc/refman/8.4/en/x-plugin-options-system-variables.html#sysvar_mysqlx_bind_address
201-
//when the MySQL X Plugin fails to bind to an address, it does not prevent the MySQL server startup because MySQL X is not a mandatory plugin.
202-
//It doesn't seem like there is a way to prevent server startup when that happens. The workaround to that is to shutdown the MySQL server ourselves when the X plugin
203-
//cannot bind to an address. If there is a way to prevent server startup when binding fails, this workaround can be removed.
204-
const killed = await this.#killProcess(process)
205-
if (!killed) {
206-
reject('Failed to kill MySQL process to retry listening on a free port.')
207-
}
208-
} else if (file.includes('ready for connections. Version:') || file.includes('Server starts handling incoming connections')) {
204+
if (file.includes('ready for connections') || file.includes('Server starts handling incoming connections')) {
209205
fs.unwatchFile(errorLogFile)
206+
207+
this.killedFromPortIssue = file.includes("Do you already have another mysqld server running")
208+
this.logger.log('Did a port issue occur after watching errorLogFile:', this.killedFromPortIssue)
209+
if (this.killedFromPortIssue) {
210+
const killed = await this.#killProcess(process)
211+
if (!killed) {
212+
return reject('Failed to kill process after port error.')
213+
}
214+
return //Promise rejection will be handled in the process.on('close') section because this.killedFromPortIssue is being set to true
215+
}
216+
217+
210218
resolve({
211219
port,
212220
xPort: mySQLXPort,
@@ -227,7 +235,7 @@ class Executor {
227235
const killed = await this.#killProcess(process)
228236

229237
if (!killed) {
230-
reject()
238+
reject('Failed to kill process.')
231239
}
232240
})
233241
}

0 commit comments

Comments
 (0)