Improve connection retry logic and error handling

Refactored APC, Line, and Switch connection services to reset retry counters after max retries and added retry logic on disconnect events. Enhanced LineConnection to accept a clear line handler and implemented a reconnect method. Wrapped the 'run_all_dpelp' event in socket_io_provider with error handling to prevent crashes during wiki post operations.
This commit is contained in:
nguyentrungthat 2025-12-02 16:12:23 +07:00
parent 46ac79b94f
commit b9fbb3f7b7
4 changed files with 66 additions and 21 deletions

View File

@ -54,6 +54,7 @@ class APCController {
return new Promise((resolve, reject) => {
this.socket.connect(this.apc_port, this.apc_ip, () => {
this.status = 'CONNECTED'
// this.retryConnect = 0
this.socket.setEncoding('utf8')
resolve()
})
@ -120,6 +121,8 @@ class APCController {
console.log('Retry connect times', this.retryConnect)
this.retryConnect += 1
await this.reconnect()
} else {
this.retryConnect = 0
}
}

View File

@ -105,10 +105,12 @@ export default class LineConnection {
private waitingScenario: boolean
private outputInventory: string
private outputScenario: string
private bufferCommand: string
// private bufferCommand: string
public dataDPELP: DataDPELP | string
private retryConnect: number
public handleClearLine: () => void
constructor(config: LineConfig, socketIO: any) {
constructor(config: LineConfig, socketIO: any, handleClearLine: () => void) {
this.config = config
this.socketIO = socketIO
this.client = new net.Socket()
@ -118,8 +120,10 @@ export default class LineConnection {
this.waitingScenario = false
this.outputInventory = ''
this.outputScenario = ''
this.bufferCommand = ''
// this.bufferCommand = ''
this.dataDPELP = 'No data'
this.retryConnect = 0
this.handleClearLine = handleClearLine
}
connect(timeoutMs = 5000) {
@ -137,6 +141,7 @@ export default class LineConnection {
this.connecting = true
setTimeout(() => {
this.config.status = 'connected'
// this.retryConnect = 0
this.connecting = false
this.socketIO.emit('line_connected', {
stationId,
@ -206,7 +211,9 @@ export default class LineConnection {
resolve()
})
this.client.on('close', () => {
this.client.on('close', async () => {
if (resolvedOrRejected) return
resolvedOrRejected = true
console.log(`[${Date.now()}] 🔌 Line ${lineNumber} disconnected`)
this.config.status = 'disconnected'
// this.config.inventory = undefined
@ -216,6 +223,14 @@ export default class LineConnection {
lineNumber,
status: 'disconnected',
})
if (this.retryConnect <= 5) {
await this.sleep(5000)
console.log(`Retry connect line [${this.config.lineNumber}] times`, this.retryConnect)
this.retryConnect += 1
await this.reconnect()
} else {
this.retryConnect = 0
}
})
this.client.on('timeout', () => {
@ -243,6 +258,10 @@ export default class LineConnection {
})
}
private sleep(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms))
}
async writeCommand(cmd: string | Buffer<ArrayBuffer>, userName = '') {
if (this.client.destroyed) {
console.log(`⚠️ Cannot send, line ${this.config.lineNumber} is closed`)
@ -280,8 +299,9 @@ export default class LineConnection {
}
}
disconnect() {
async disconnect() {
try {
this.handleClearLine()
this.client.destroy()
this.config.status = 'disconnected'
this.socketIO.emit('line_disconnected', {
@ -489,6 +509,18 @@ export default class LineConnection {
})
}
public async reconnect(): Promise<boolean> {
try {
this.disconnect()
this.client = new net.Socket()
await this.sleep(1000)
await this.connect()
return true
} catch (err: any) {
return false
}
}
userOpenCLI(user: User) {
this.config.openCLI = true
this.config.userEmailOpenCLI = user.userEmail

View File

@ -77,6 +77,8 @@ export default class SwitchController {
console.log('Retry connect times', this.retryConnect)
this.retryConnect += 1
await this.reconnect()
} else {
this.retryConnect = 0
}
}
@ -116,6 +118,7 @@ export default class SwitchController {
try {
this.socket.connect(this.port, this.host, () => {
this.status = 'CONNECTED'
// this.retryConnect = 0
this.isEnable = false
this.socket.setEncoding('utf8')
this.checkStatusAllPorts()

View File

@ -534,24 +534,27 @@ export class WebSocketIo {
})
socket.on('run_all_dpelp', async (data) => {
const lineIds = data.lineIds
console.log('[DPELP] Received run all dpelp')
try {
const lineIds = data.lineIds
console.log('[DPELP] Received run all dpelp')
const results = await this.waitUntilAllReady(lineIds)
const tableHTML = this.generateTable(results)
const results = await this.waitUntilAllReady(lineIds)
const tableHTML = this.generateTable(results)
const d = new Date(Date.now())
const pad = (n: number) => String(n).padStart(2, '0')
const d = new Date(Date.now())
const dataFormat =
`${d.getFullYear()}/${pad(d.getMonth() + 1)}/${pad(d.getDate())}, ` +
`${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`
const linkWiki =
process.env.LINK_WIKI || 'https://logs.danielvu.com/api/wiki/page/insert?title=Dev_test'
await axios.post(linkWiki, {
data: tableHTML,
titleAuto: 'AUTO - ' + dataFormat,
})
const dataFormat =
`${d.getFullYear()}/${d.getMonth() + 1}/${d.getDate()}, ` +
`${d.getHours()}:${d.getMinutes()}:${d.getSeconds()}`
const linkWiki =
process.env.LINK_WIKI || 'https://logs.danielvu.com/api/wiki/page/insert?title=Dev_test'
await axios.post(linkWiki, {
data: tableHTML,
titleAuto: 'AUTO - ' + dataFormat,
})
} catch (error) {
console.log(error)
}
})
})
@ -595,7 +598,11 @@ export class WebSocketIo {
commands: [],
inventory: inventory,
},
socket
socket,
async () => {
if (line.lineClear && line.lineClear > 0)
await this.clearLineBeforeConnect(station.id, line.lineClear)
}
)
// 👉 Bước 1: clear line trước khi connect
if (line.lineClear && line.lineClear > 0)