diff --git a/lib/common/mobile/ios/ios-device-base.ts b/lib/common/mobile/ios/ios-device-base.ts index eedfa06e4f..a91458745b 100644 --- a/lib/common/mobile/ios/ios-device-base.ts +++ b/lib/common/mobile/ios/ios-device-base.ts @@ -1,5 +1,6 @@ import * as net from "net"; import { performanceLog } from "../../decorators"; +import { APPLICATION_RESPONSE_TIMEOUT_SECONDS } from "../../../constants"; export abstract class IOSDeviceBase implements Mobile.IiOSDevice { private cachedSockets: IDictionary = {}; @@ -16,23 +17,31 @@ export abstract class IOSDeviceBase implements Mobile.IiOSDevice { @performanceLog() public async getDebugSocket(appId: string, projectName: string): Promise { - return this.$lockService.executeActionWithLock(async () => { - if (this.cachedSockets[appId]) { - return this.cachedSockets[appId]; - } + return this.$lockService.executeActionWithLock( + async () => { + if (this.cachedSockets[appId]) { + return this.cachedSockets[appId]; + } - this.cachedSockets[appId] = await this.getDebugSocketCore(appId, projectName); + this.cachedSockets[appId] = await this.getDebugSocketCore(appId, projectName); - if (this.cachedSockets[appId]) { - this.cachedSockets[appId].on("close", async () => { - await this.destroyDebugSocket(appId); - }); + if (this.cachedSockets[appId]) { + this.cachedSockets[appId].on("close", async () => { + await this.destroyDebugSocket(appId); + }); - this.$processService.attachToProcessExitSignals(this, () => this.destroyDebugSocket(appId)); - } + this.$processService.attachToProcessExitSignals(this, () => this.destroyDebugSocket(appId)); + } - return this.cachedSockets[appId]; - }, "ios-debug-socket.lock"); + return this.cachedSockets[appId]; + }, + `ios-debug-socket-${this.deviceInfo.identifier}-${appId}.lock`, + { + // increase the timeout with `APPLICATION_RESPONSE_TIMEOUT_SECONDS` as a workaround + // till startApplication is resolved before the application is really started + stale: (APPLICATION_RESPONSE_TIMEOUT_SECONDS + 30) * 1000, + } + ); } protected abstract async getDebugSocketCore(appId: string, projectName: string): Promise; diff --git a/lib/common/services/lock-service.ts b/lib/common/services/lock-service.ts index 64e0db0176..866596b894 100644 --- a/lib/common/services/lock-service.ts +++ b/lib/common/services/lock-service.ts @@ -74,7 +74,7 @@ export class LockService implements ILockService { } filePath = filePath || this.defaultLockFilePath; - fileOpts = fileOpts || this.defaultLockParams; + fileOpts = fileOpts ? _.assign({}, this.defaultLockParams, fileOpts) : this.defaultLockParams; return { filePath, diff --git a/lib/constants.ts b/lib/constants.ts index ffc869fcba..3be5679121 100644 --- a/lib/constants.ts +++ b/lib/constants.ts @@ -46,6 +46,7 @@ export const AAB_EXTENSION_NAME = ".aab"; export const HASHES_FILE_NAME = ".nshashes"; export const TNS_NATIVE_SOURCE_GROUP_NAME = "TNSNativeSource"; export const NATIVE_SOURCE_FOLDER = "src"; +export const APPLICATION_RESPONSE_TIMEOUT_SECONDS = 60; export class PackageVersion { static NEXT = "next"; diff --git a/lib/device-sockets/ios/app-debug-socket-proxy-factory.ts b/lib/device-sockets/ios/app-debug-socket-proxy-factory.ts index f68f00f6a0..85f7e5bfe0 100644 --- a/lib/device-sockets/ios/app-debug-socket-proxy-factory.ts +++ b/lib/device-sockets/ios/app-debug-socket-proxy-factory.ts @@ -1,5 +1,5 @@ import { EventEmitter } from "events"; -import { CONNECTION_ERROR_EVENT_NAME } from "../../constants"; +import { CONNECTION_ERROR_EVENT_NAME, APPLICATION_RESPONSE_TIMEOUT_SECONDS } from "../../constants"; import * as net from "net"; import * as ws from "ws"; import temp = require("temp"); @@ -115,7 +115,15 @@ export class AppDebugSocketProxyFactory extends EventEmitter implements IAppDebu port: localPort, host: "localhost", verifyClient: async (info: any, callback: (res: boolean, code?: number, message?: string) => void) => { - await this.$lockService.lock(clientConnectionLockFile); + await this.$lockService.lock( + clientConnectionLockFile, + { + // increase the timeout with `APPLICATION_RESPONSE_TIMEOUT_SECONDS` as a workaround + // till startApplication is resolved before the application is really started + stale: (APPLICATION_RESPONSE_TIMEOUT_SECONDS + 30) * 1000, + } + ); + let acceptHandshake = true; this.$logger.info("Frontend client connected."); let appDebugSocket; diff --git a/lib/services/ios-debugger-port-service.ts b/lib/services/ios-debugger-port-service.ts index 8dd0463617..1f411d00c5 100644 --- a/lib/services/ios-debugger-port-service.ts +++ b/lib/services/ios-debugger-port-service.ts @@ -1,10 +1,10 @@ import { DEBUGGER_PORT_FOUND_EVENT_NAME, ATTACH_REQUEST_EVENT_NAME } from "../common/constants"; import { cache } from "../common/decorators"; +import { APPLICATION_RESPONSE_TIMEOUT_SECONDS } from "../constants"; export class IOSDebuggerPortService implements IIOSDebuggerPortService { public static DEBUG_PORT_LOG_REGEX = /NativeScript debugger has opened inspector socket on port (\d+?) for (.*)[.]/; private mapDebuggerPortData: IDictionary = {}; - private static DEFAULT_TIMEOUT_IN_SECONDS = 10; constructor(private $logParserService: ILogParserService, private $iOSNotification: IiOSNotification, @@ -14,7 +14,8 @@ export class IOSDebuggerPortService implements IIOSDebuggerPortService { public getPort(data: IIOSDebuggerPortInputData): Promise { return new Promise((resolve, reject) => { const key = `${data.deviceId}${data.appId}`; - let retryCount = Math.max(IOSDebuggerPortService.DEFAULT_TIMEOUT_IN_SECONDS * 1000 / 500, 10); + const retryInterval = 500; + let retryCount = Math.max(APPLICATION_RESPONSE_TIMEOUT_SECONDS * 1000 / retryInterval, 10); const interval = setInterval(() => { let port = this.getPortByKey(key); @@ -25,7 +26,7 @@ export class IOSDebuggerPortService implements IIOSDebuggerPortService { port = this.getPortByKey(key); retryCount--; } - }, 500); + }, retryInterval); }); } @@ -65,7 +66,7 @@ export class IOSDebuggerPortService implements IIOSDebuggerPortService { if (!this.getPortByKey(`${data.deviceId}${data.appId}`)) { this.$logger.warn(`NativeScript debugger was not able to get inspector socket port on device ${data.deviceId} for application ${data.appId}.`); } - }, IOSDebuggerPortService.DEFAULT_TIMEOUT_IN_SECONDS * 1000); + }, APPLICATION_RESPONSE_TIMEOUT_SECONDS * 1000); this.setData(data, { port: null, timer }); }); diff --git a/test/services/ios-debugger-port-service.ts b/test/services/ios-debugger-port-service.ts index abbbf43602..9e3b0335f3 100644 --- a/test/services/ios-debugger-port-service.ts +++ b/test/services/ios-debugger-port-service.ts @@ -156,7 +156,7 @@ describe("iOSDebuggerPortService", () => { } const promise = iOSDebuggerPortService.getPort({ deviceId: deviceId, appId: appId }); - clock.tick(20000); + clock.tick(70000); const port = await promise; assert.deepEqual(port, testCase.emittedPort); }); @@ -170,7 +170,7 @@ describe("iOSDebuggerPortService", () => { } const promise = iOSDebuggerPortService.getPort({ deviceId: deviceId, appId: appId }); - clock.tick(20000); + clock.tick(70000); const port = await promise; assert.deepEqual(port, testCase.emittedPort); });