-
Notifications
You must be signed in to change notification settings - Fork 10
Fix EMFILE error when running on Android #1036
Conversation
definitions/mobile.d.ts
Outdated
@@ -673,7 +673,7 @@ declare module Mobile { | |||
/** | |||
* Computes the shasums of localToDevicePaths and changes the content of hash file on device |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
these docs are no longer correct
helpers.ts
Outdated
if (_.isArray(initialData)) { | ||
const chunks = _.chunk(initialData, chunkSize); | ||
for (const chunk of chunks) { | ||
await Promise.all(_.map(chunk, element => elementAction(element))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe pass the index of the element as second argument?
@@ -53,26 +54,26 @@ export class AndroidDeviceFileSystem implements Mobile.IDeviceFileSystem { | |||
public async transferFiles(deviceAppData: Mobile.IDeviceAppData, localToDevicePaths: Mobile.ILocalToDevicePathData[]): Promise<void> { | |||
// TODO: Do not start all promises simultaneously as this leads to error EMFILE on Windows for too many opened files. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this TODO is implemented with current changes, so remove it
await executeActionByChunks<Mobile.ILocalToDevicePathData>(localToDevicePaths, 100, action); | ||
|
||
const dirsChmodAction = async (directoryToChmod: string) => { | ||
await this.adb.executeShellCommand(["chmod", "0777", directoryToChmod]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this can be safely returned instead of awaited:
const dirsChmodAction = (directoryToChmod: string) => this.adb.executeShellCommand(["chmod", "0777", directoryToChmod]);
await this.adb.executeShellCommand(["chmod", "0777", directoryToChmod]); | ||
}; | ||
|
||
await executeActionByChunks<string>(_.uniq(directoriesToChmod), 100, dirsChmodAction); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
extract 100 in a constant at least in this file
test/unit-tests/helpers.ts
Outdated
@@ -15,6 +15,60 @@ describe("helpers", () => { | |||
assert.deepEqual(actualResult, testData.expectedResult, `For input ${testData.input}, the expected result is: ${testData.expectedResult}, but actual result is: ${actualResult}.`); | |||
}; | |||
|
|||
describe("executeActionByChunks", () => { | |||
const verify = (initialDataValues: any[], handledElements: any[], element: any, chunkSize: number) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
verify
should be renamed
test/unit-tests/helpers.ts
Outdated
|
||
const initialDataValues = _.values(initialData); | ||
const handledElements: number[] = []; | ||
const chunkSize = 2; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
move chunkSize outside of the it
and reuse it in the two tests
const action = async (localToDevicePathData: Mobile.ILocalToDevicePathData) => { | ||
const localPath = localToDevicePathData.getLocalPath(); | ||
const stats = this.$fs.getFsStats(localPath); | ||
if (stats.isFile()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this code seems like a duplicate of part of the code from updateHashes
in android-device-hash-service. Consider extracting a new method that executes the common part.
test/unit-tests/helpers.ts
Outdated
|
||
const handledElements: number[] = []; | ||
const chunkSize = 2; | ||
return helpers.executeActionByChunks(initialData, chunkSize, async element => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no need to mark this as async
test/unit-tests/helpers.ts
Outdated
const initialDataValues = _.values(initialData); | ||
const handledElements: number[] = []; | ||
const chunkSize = 2; | ||
return helpers.executeActionByChunks(initialData, chunkSize, async (element, key) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no need to mark this as async
During running on Android, CLI tries to take smart decision which files to upload. This is done by checking the shasum of all project files and comparing it with the latest one uploaded to device. However, in huge projects, this leads to error with code EMFILE as the OS have limits for opened file handles. This happens as CLI executes the operation simultaneously for all files. In order to fix this behavior, execute the actions by chunks (currently set to 100). Introduce new method in helpers to execute this action and add tests for it.
e490f05
to
0d1a466
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems legit
During running on Android, CLI tries to take smart decision which files to upload. This is done by checking the shasum of all project files and comparing it with the latest one uploaded to device. However, in huge projects, this leads to error with code EMFILE as the OS have limits for opened file handles.
This happens as CLI executes the operation simultaneously for all files. In order to fix this behavior, execute the actions by chunks (currently set to 100).
Introduce new method in helpers to execute this action and add tests for it.
Fixes NativeScript/nativescript-angular#1079 and NativeScript/nativescript-cli#3268