diff --git a/packages/nx/src/daemon/client/client.ts b/packages/nx/src/daemon/client/client.ts index af3a6fc62fa0e..4eb0eb310c6ee 100644 --- a/packages/nx/src/daemon/client/client.ts +++ b/packages/nx/src/daemon/client/client.ts @@ -37,6 +37,12 @@ export type ChangedFile = { type: 'create' | 'update' | 'delete'; }; +enum DaemonStatus { + CONNECTING, + DISCONNECTED, + CONNECTED, +} + export class DaemonClient { constructor(private readonly nxJson: NxJsonConfiguration) { this.reset(); @@ -50,7 +56,9 @@ export class DaemonClient { private currentReject; private _enabled: boolean | undefined; - private _connected: boolean; + private _daemonStatus: DaemonStatus = DaemonStatus.DISCONNECTED; + private _waitForDaemonReady: Promise | null = null; + private _daemonReady: () => void | null = null; private _out: FileHandle = null; private _err: FileHandle = null; @@ -104,7 +112,10 @@ export class DaemonClient { this._out = null; this._err = null; - this._connected = false; + this._daemonStatus = DaemonStatus.DISCONNECTED; + this._waitForDaemonReady = new Promise( + (resolve) => (this._daemonReady = resolve) + ); } async requestShutdown(): Promise { @@ -149,27 +160,28 @@ export class DaemonClient { ) => void ): Promise { await this.getProjectGraph(); - const messenger = new SocketMessenger(connect(FULL_OS_SOCKET_PATH)).listen( - (message) => { - try { - const parsedMessage = JSON.parse(message); - callback(null, parsedMessage); - } catch (e) { - callback(e, null); - } - }, - () => { - callback('closed', null); - }, - (err) => callback(err, null) - ); - - await this.queue.sendToQueue(() => - messenger.sendMessage({ type: 'REGISTER_FILE_WATCHER', config }) - ); + let messenger: SocketMessenger | undefined; + + await this.queue.sendToQueue(() => { + messenger = new SocketMessenger(connect(FULL_OS_SOCKET_PATH)).listen( + (message) => { + try { + const parsedMessage = JSON.parse(message); + callback(null, parsedMessage); + } catch (e) { + callback(e, null); + } + }, + () => { + callback('closed', null); + }, + (err) => callback(err, null) + ); + return messenger.sendMessage({ type: 'REGISTER_FILE_WATCHER', config }); + }); return () => { - messenger.close(); + messenger?.close(); }; } @@ -232,7 +244,7 @@ export class DaemonClient { // it's ok for the daemon to terminate if the client doesn't wait on // any messages from the daemon if (this.queue.isEmpty()) { - this._connected = false; + this.reset(); } else { output.error({ title: 'Daemon process terminated and closed the connection', @@ -280,12 +292,17 @@ export class DaemonClient { } private async sendMessageToDaemon(message: Message): Promise { - if (!this._connected) { - this._connected = true; + if (this._daemonStatus == DaemonStatus.DISCONNECTED) { + this._daemonStatus = DaemonStatus.CONNECTING; + if (!(await this.isServerAvailable())) { await this.startInBackground(); } this.setUpConnection(); + this._daemonStatus = DaemonStatus.CONNECTED; + this._daemonReady(); + } else if (this._daemonStatus == DaemonStatus.CONNECTING) { + await this._waitForDaemonReady; } return new Promise((resolve, reject) => {