feat: bump version to 1.2.7 and enhance connection handling in SMTPOverWSClient to prevent race conditions
This commit is contained in:
parent
ad1424a79a
commit
3526902a72
2 changed files with 32 additions and 6 deletions
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@siwats/mxrelay-consumer",
|
||||
"version": "1.2.5",
|
||||
"version": "1.2.7",
|
||||
"description": "An internal TypeScript client library for transporting SMTP messages",
|
||||
"main": "lib/index.js",
|
||||
"module": "lib/index.esm.js",
|
||||
|
|
|
@ -82,10 +82,12 @@ export class SMTPOverWSClient extends EventEmitter {
|
|||
private reconnectTimer: NodeJS.Timeout | null = null;
|
||||
private authTimer: NodeJS.Timeout | null = null;
|
||||
private channelTimer: NodeJS.Timeout | null = null;
|
||||
private channelCloseTimer: NodeJS.Timeout | null = null;
|
||||
private heartbeatTimer: NodeJS.Timeout | null = null;
|
||||
private sessionTimer: NodeJS.Timeout | null = null;
|
||||
private isProcessingQueue = false;
|
||||
private isShuttingDown = false;
|
||||
private connectionPromise: Promise<void> | null = null;
|
||||
private logger: Logger;
|
||||
private stats: ClientStats;
|
||||
private connectionStartTime: number = 0;
|
||||
|
@ -314,9 +316,17 @@ export class SMTPOverWSClient extends EventEmitter {
|
|||
let failed = 0;
|
||||
|
||||
try {
|
||||
// Connect if not connected
|
||||
if (this.state === ConnectionState.DISCONNECTED) {
|
||||
await this.connect();
|
||||
// Connect if not connected - use connection promise to prevent race conditions
|
||||
if (this.state === ConnectionState.DISCONNECTED || this.state === ConnectionState.FAILED) {
|
||||
if (!this.connectionPromise) {
|
||||
this.connectionPromise = this.connect().finally(() => {
|
||||
this.connectionPromise = null;
|
||||
});
|
||||
}
|
||||
await this.connectionPromise;
|
||||
} else if (this.connectionPromise) {
|
||||
// Wait for ongoing connection attempt to complete
|
||||
await this.connectionPromise;
|
||||
}
|
||||
|
||||
// Process sessions sequentially one at a time (SMTP sessions are mutex)
|
||||
|
@ -789,6 +799,11 @@ export class SMTPOverWSClient extends EventEmitter {
|
|||
return new Promise((resolve) => {
|
||||
if (this.state === ConnectionState.CHANNEL_READY) {
|
||||
const onChannelClosed = () => {
|
||||
// Clear the fallback timer since channel closed properly
|
||||
if (this.channelCloseTimer) {
|
||||
clearTimeout(this.channelCloseTimer);
|
||||
this.channelCloseTimer = null;
|
||||
}
|
||||
this.setState(ConnectionState.AUTHENTICATED);
|
||||
this.emit('channelClosed');
|
||||
this.logger.debug('SMTP channel closed');
|
||||
|
@ -798,9 +813,14 @@ export class SMTPOverWSClient extends EventEmitter {
|
|||
this.once('smtp_channel_closed', onChannelClosed);
|
||||
|
||||
// Fallback timeout
|
||||
setTimeout(() => {
|
||||
this.channelCloseTimer = setTimeout(() => {
|
||||
this.removeListener('smtp_channel_closed', onChannelClosed);
|
||||
// Only set to authenticated if we're still connected
|
||||
if (this.ws && this.ws.readyState === WebSocket.OPEN &&
|
||||
this.state !== ConnectionState.DISCONNECTED) {
|
||||
this.setState(ConnectionState.AUTHENTICATED);
|
||||
}
|
||||
this.channelCloseTimer = null;
|
||||
resolve();
|
||||
}, 5000);
|
||||
} else {
|
||||
|
@ -883,6 +903,7 @@ export class SMTPOverWSClient extends EventEmitter {
|
|||
this.emit('disconnected', reason);
|
||||
this.stopHeartbeat();
|
||||
this.clearTimers();
|
||||
this.connectionPromise = null;
|
||||
|
||||
// Always try to reconnect if we have queued sessions and not shutting down
|
||||
// NEVER reject emails - keep trying with periodic retries
|
||||
|
@ -1010,6 +1031,11 @@ export class SMTPOverWSClient extends EventEmitter {
|
|||
this.channelTimer = null;
|
||||
}
|
||||
|
||||
if (this.channelCloseTimer) {
|
||||
clearTimeout(this.channelCloseTimer);
|
||||
this.channelCloseTimer = null;
|
||||
}
|
||||
|
||||
if (this.sessionTimer) {
|
||||
clearTimeout(this.sessionTimer);
|
||||
this.sessionTimer = null;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue