Add retries around android device watching

Summary: Retry up to 5 times with exponential backoff.

Reviewed By: passy

Differential Revision: D13138244

fbshipit-source-id: 94c68b87aa281cfc3239b0bb8bdd75a2e0d7edc7
This commit is contained in:
John Knox
2018-11-22 06:38:09 -08:00
committed by Facebook Github Bot
parent 9e6a86923a
commit ca1f0202d7
4 changed files with 122 additions and 58 deletions

View File

@@ -7,6 +7,7 @@
import AndroidDevice from '../devices/AndroidDevice';
import child_process from 'child_process';
import promiseRetry from 'promise-retry';
import type {Store} from '../reducers/index.js';
import type BaseDevice from '../devices/BaseDevice';
import type Logger from '../fb-stubs/Logger.js';
@@ -57,10 +58,28 @@ export default (store: Store, logger: Logger) => {
// Using this client before adb server is started up will cause failures.
// this gets around this by waiting for listDevices first, which ensures
// the server is up and running before allowing any other operations.
const clientPromise = (() => {
function createClient() {
const unsafeClient = adb.createClient();
return unsafeClient.listDevices().then(() => unsafeClient);
})();
return promiseRetry(
(retry, number) => {
return unsafeClient
.listDevices()
.then(() => {
return unsafeClient;
})
.catch(e => {
console.warn(`Failed to start adb client. Retrying. ${e.message}`);
retry(e);
});
},
{
minTimeout: 200,
retries: 5,
},
);
}
const clientPromise = createClient();
const watchAndroidDevices = () => {
// get emulators
@@ -79,71 +98,77 @@ export default (store: Store, logger: Logger) => {
},
);
clientPromise.then(client => {
client
.trackDevices()
.then(tracker => {
tracker.on('error', err => {
if (err.message === 'Connection closed') {
// adb server has shutdown, remove all android devices
const {connections} = store.getState();
const deviceIDsToRemove: Array<
string,
> = connections.devices
.filter((device: BaseDevice) => device instanceof AndroidDevice)
.map((device: BaseDevice) => device.serial);
clientPromise
.then(client => {
client
.trackDevices()
.then(tracker => {
tracker.on('error', err => {
if (err.message === 'Connection closed') {
// adb server has shutdown, remove all android devices
const {connections} = store.getState();
const deviceIDsToRemove: Array<
string,
> = connections.devices
.filter(
(device: BaseDevice) => device instanceof AndroidDevice,
)
.map((device: BaseDevice) => device.serial);
store.dispatch({
type: 'UNREGISTER_DEVICES',
payload: new Set(deviceIDsToRemove),
});
console.error('adb server was shutdown');
setTimeout(watchAndroidDevices, 500);
} else {
throw err;
}
});
store.dispatch({
type: 'UNREGISTER_DEVICES',
payload: new Set(deviceIDsToRemove),
});
console.error('adb server was shutdown');
setTimeout(watchAndroidDevices, 500);
} else {
throw err;
}
});
tracker.on('add', async device => {
if (device.type !== 'offline') {
const androidDevice = await createDevice(client, device);
store.dispatch({
type: 'REGISTER_DEVICE',
payload: androidDevice,
});
}
});
tracker.on('add', async device => {
if (device.type !== 'offline') {
const androidDevice = await createDevice(client, device);
store.dispatch({
type: 'REGISTER_DEVICE',
payload: androidDevice,
});
}
});
tracker.on('change', async device => {
if (device.type === 'offline') {
tracker.on('change', async device => {
if (device.type === 'offline') {
store.dispatch({
type: 'UNREGISTER_DEVICES',
payload: new Set([device.id]),
});
} else {
const androidDevice = await createDevice(client, device);
store.dispatch({
type: 'REGISTER_DEVICE',
payload: androidDevice,
});
}
});
tracker.on('remove', device => {
store.dispatch({
type: 'UNREGISTER_DEVICES',
payload: new Set([device.id]),
});
});
})
.catch(err => {
if (err.code === 'ECONNREFUSED') {
// adb server isn't running
} else {
const androidDevice = await createDevice(client, device);
store.dispatch({
type: 'REGISTER_DEVICE',
payload: androidDevice,
});
throw err;
}
});
tracker.on('remove', device => {
store.dispatch({
type: 'UNREGISTER_DEVICES',
payload: new Set([device.id]),
});
});
})
.catch(err => {
if (err.code === 'ECONNREFUSED') {
// adb server isn't running
} else {
throw err;
}
});
});
})
.catch(e => {
console.error(`Failed to watch for android devices: ${e.message}`);
});
};
watchAndroidDevices();