Skip to content
This repository has been archived by the owner on Apr 25, 2023. It is now read-only.

Get source, screenshot and windowSize concurrently #916

Merged
merged 2 commits into from
Apr 2, 2019

Conversation

dpgraham
Copy link
Contributor

  • The current way of getting source, screenshot and windowSize is calling each one-after-the-other
  • This PR makes it so that they all get called at once and then the promise resolve once we have a result for all three (whether it's successful or an error). Should give a pretty noticeable performance bump.
  • Pardon the Promises abomination. Promise.all doesn't support waiting for all promises to resolve. I needed a solution that completes all three of the promises and then sends the result back.
  • Also note, I wanted to use finally to call checkShouldResolve, but there's a race condition that causes finally to sometimes be called before then or catch.

@jlipps
Copy link
Member

jlipps commented Mar 29, 2019

I've used Bluebird.all (http://bluebirdjs.com/docs/api/promise.all.html) in the past and it does wait for all promises to resolve in my experience. Did you experience something else?

@dpgraham
Copy link
Contributor Author

@jlipps I need the promises to complete even if they don't resolve. I need either the result or the error for all 3 calls.

@mykola-mokhnach
Copy link
Contributor

Does it really work faster? base driver queues all commands by default, so they cannot run simultaneously

@mykola-mokhnach
Copy link
Contributor

I need the promises to complete even if they don't resolve. I need either the result or the error for all 3 calls.

Bluebird has .timeout for that

@dpgraham
Copy link
Contributor Author

@mykola-mokhnach in a cloud environment it definitely will:

Currently, we do it sequentially which does this:

request /source -> <build source> -> response source/ -> request /screenshot -> <take screenshot > -> response screenshot/ -> request /window/size -> <calculate window size> -> response /window/size/

After this PR it will be:

request /source /screenshot and /window/size concurrently -> <build source> -> <take screenshot> -> <calculate window size> -> response /source /screenshot and /window/size concurrently

tl:dr; in cloud environment, we don't have to wait for response to download before starting next request

@dpgraham
Copy link
Contributor Author

.timeout puts a time limit on a promise, so not sure if that would help.

@imurchie
Copy link
Contributor

If you want to stay bluebird, you can do something like:

  const a = new B((resolve, reject) => {
    setTimeout(function () {
      resolve('done with a');
    }, 5000);
  });
  const b = new B((resolve, reject) => {
    setTimeout(function () {
      reject(new Error('problem with b'));
    }, 4000);
  });
  const c = new B((resolve, reject) => {
    setTimeout(function () {
      resolve('done with c');
    }, 3000);
  });

  const res = await B.all([a, b, c].map((p) => {
    return p.reflect();
  })).map((pi) => {
    if (pi.isFulfilled()) {
      return pi.value();
    } else {
      return pi.reason();
    }
  });
  console.log('res:', res);

The output of which would be:

[ 'done with a',
  Error: problem with b
    at Timeout._onTimeout (/Users/isaac/code/appium-xcuitest-driver/index.js:30:14)
    at ontimeout (timers.js:498:11)
    at tryOnTimeout (timers.js:323:5)
    at Timer.listOnTimeout (timers.js:290:5),
  'done with c' ]

@imurchie
Copy link
Contributor

Sitting around bored at home and came up with this:

  const source = new B((resolve, reject) => {
    resolve('got source');
  });
  const screenshot = new B((resolve, reject) => {
    reject(new Error('error getting screenshot'));
  });
  const windowSize = new B((resolve, reject) => {
    resolve('got window size');
  });

  const names = ['source', 'screenshot', 'windowSize'];
  const res = await B.all([source, screenshot, windowSize].map((p) => {
    return p.reflect();
  })).map((pi) => {
    return pi.isFulfilled()
      ? [pi.value(), undefined]
      : [undefined, pi.reason()];
  }).reduce((acc, val, i) => {
    acc[`${names[i]}`] = val[0];
    acc[`${names[i]}Error`] = val[1];
    return acc;
  }, {});

  console.log(res);

Gets:

{ source: 'got source',
  sourceError: undefined,
  screenshot: undefined,
  screenshotError: Error: error getting screenshot
    at _bluebird.default (/Users/isaac/code/appium-xcuitest-driver/index.js:27:12)
    at Promise._execute (/Users/isaac/code/appium-xcuitest-driver/node_modules/bluebird/js/release/debuggability.js:313:9)
    at Promise._resolveFromExecutor (/Users/isaac/code/appium-xcuitest-driver/node_modules/bluebird/js/release/promise.js:483:18)
    at new Promise (/Users/isaac/code/appium-xcuitest-driver/node_modules/bluebird/js/release/promise.js:79:10)
    at main (/Users/isaac/code/appium-xcuitest-driver/index.js:26:22)
    at fn (/Users/isaac/code/appium-xcuitest-driver/node_modules/asyncbox/lib/asyncbox.js:70:13)
    at Object.<anonymous> (/Users/isaac/code/appium-xcuitest-driver/index.js:50:3)
    at Module._compile (module.js:653:30)
    at Object.Module._extensions..js (module.js:664:10)
    at Module.load (module.js:566:32)
    at tryModuleLoad (module.js:506:12)
    at Function.Module._load (module.js:498:3)
    at Function.Module.runMain (module.js:694:10)
    at startup (bootstrap_node.js:204:16)
    at bootstrap_node.js:625:3,
  windowSize: 'got window size',
  windowSizeError: undefined }

@dpgraham
Copy link
Contributor Author

dpgraham commented Apr 1, 2019

I just tried @imurchie 's way and it is throwing an exception....

Should I troubleshoot this some more and find a bluebird/promise way of doing this or is this okay how it is?

@imurchie
Copy link
Contributor

imurchie commented Apr 1, 2019

What is the exception?

@dpgraham
Copy link
Contributor Author

dpgraham commented Apr 1, 2019

[0] 15:23:14.275  Retrieving session for window with id: 5
[0] Handling client method request with method 'source' and args []
[0] Caught an exception:  TypeError: e.reflect is not a function
[0]     at e.default.all.map.e (/Users/danielgraham/appium-desktop/dist/main.js:80:2854)
[0]     at Array.map (<anonymous>)
[0]     at u._getSourceAndScreenshot (/Users/danielgraham/appium-desktop/dist/main.js:80:2845)
[0]     at u._execute (/Users/danielgraham/appium-desktop/dist/main.js:80:2380)

@imurchie
Copy link
Contributor

imurchie commented Apr 2, 2019

Weird. Must not be a Bluebird promise.

Anyway, more trouble than it's worth, I say.

@dpgraham dpgraham merged commit dd2fb93 into master Apr 2, 2019
@dpgraham dpgraham deleted the dpgraham-concurrent-source-and-screenshot branch April 2, 2019 17:56
@vijayqeguy
Copy link

I believe this change is failing Perfecto cloud provider. Screenshot keeps spinning and source keeps loading. Let me know if you more information is needed.

@KazuCocoa
Copy link
Member

Can you get any logs launching from source?
It might be helpful to observe the behaviour.
(And create a new issue is also helpful)

@dpgraham
Copy link
Contributor Author

dpgraham commented Jul 4, 2019

@vijayqaguy I think you're right. I'm seeing this on Sauce Labs too. May need to revert this.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants