Appium Load Balancer
Table of Contents
Appium Load Balancer, also known as AppiumLB, is HeadSpin’s solution to more efficient device management when testing with Appium and Selenium tests. Identifying and tracking each individual test target, particularly when you want your tests to cover a variety of geographical regions and device SKUs, can be time-consuming and frustrating. AppiumLB does not function like a traditional load balancer program handling incoming network traffic; rather, it simulates that same balancing logic to API commands and device UDIDs or WebDriver URLs to cut down on time and effort spent on device or host management.
AppiumLB is a single, generic Web Driver URL granting access to any HeadSpin devices available to you. It functions somewhat like a proxy server in that all API commands will touch AppiumLB before touching your device hosts, and AppiumLB will select devices at random that meet your test criteria. Test devices are specified through the new <code class="dcode">headspin:selector</code> capability, using the selector syntax as described in the Selectors DSL docs. AppiumLB automatically picks the proper devices and start a new Appium session with that device's <code class="dcode">udid</code>, <code class="dcode">headspin:appiumVersion</code> and the original <code class="dcode">headspin:selector</code> capabilities. AppiumLB also automatically picks a proper browser device with <code class="dcode">browserName</code>, <code class="dcode">browserVersion</code> and the original <code class="dcode">headspin:selector</code> capabilities for a Selenium session. Using AppiumLB, your testing experience will have minimal incidents of tests failing due to offline or unresponsive devices, reserved devices that are unavailable, or user error in identifying devices. Every request, barring user error in its design, will gain some kind of response and cut down on test troubleshooting. Please note that, as described in the Capabilities section below, you can specify a particular device using the <code class="dcode">udid</code> capability.
To use AppiumLB, set your Web Driver URL as <code class="dcode">https://appium-dev.headspin.io/v0/your-api-token/wd/hub</code> and make sure that the <code class="dcode">headspin:selector</code> capability reflects target devices for your test. The Web Driver URL is available as Load Balanced Driver URL in the automation configuration.
AppiumLB will look for a device or devices matching the selectors, lock the device for automation and start an Appium or a Selenium session against the device's host server. It then returns a response containing the <code class="dcode">sessionId</code> of the newly created session, where you can send Appium or Selenium commands.
Retry and avoid previously failed devices
AppiumLB will retry establishing a new session against available devices in the device pool up to the value of <code class="dcode">headspin:waitForDeviceOnlineTimeout</code>, <code class="dcode">newCommandTimeout</code> or <code class="dcode">headspin:newCommandTimeout</code> before responding to the client. Each retry will avoid previously failed devices if the cause is a device-side issue to make the session creation reliable. For instance, if a device fails due to an unexpected disconnection in the new session request, AppiumLB will avoid the device for selection for the next 10 minutes. AppiumLB can be configured to skip this avoidance behavior with the capability <code class="dcode">headspin:ignoreFailedDevice</code>.
If Appium fails to find an available device in your device pool with the given <code class="dcode">appium:udid</code> or <code class="dcode">headspin:selector</code>, it will respond with an error message that starts with No matched devices were found. It indicates the given udid or selector syntax was wrong or the syntax was correct but no matched devices existed in your device pool.
If AppiumLB fails to find an available device in your device pool, it will respond with an error message that starts with No available good condition devices ... "No available devices" indicates devices are offline, are already locked by a user, must be reserved by you, or failed against a new session request. AppiumLB will respond with an error message if the last retry fails in a new session request. <code class="dcode">headspin:retryNewSessionFailure</code> and <code class="dcode">headspin:waitForDeviceOnlineTimeout</code> help you to control the retry rule.
If no devices are available in the device pool after excluding previously failed devices then AppiumLB will select a device from the device pool without considering the previously failed devices. This behavior helps reduce obstacles in the case of your device pool containing few devices for the given selector(s). The selected device may manifest an error due to its previously failed state.
The error previously failed devices only indicates devices for which AppiumLB failed to create a new session due to a problem on the device. Errors due to other causes (such as invalid Appium capabilities) do not cause devices to be marked as "previously failed".
<code class="dcode">message</code> key in the error response could include past error messages up to 10 latest cases to help error investigation.
AppiumLB will restrict target devices if the given capabilities includes <code class="dcode">platformName</code>. If the capability specifies <code class="dcode">Android</code>, AppiumLB will choose a device from Android devices. The capability is necessary for Appium, but not for Selenium. <code class="dcode">browserName</code> and <code class="dcode">browserVersion</code> capabilities will be part of selector for Selenium to detect a browser device.
- Ruby Core
AppiumLB returns standard errors by Appium instances on proxy servers, and also the following:
Increasing Network Efficiency With directConnect Capabilities
With AppiumLB, a request goes through an additional AppiumLB server and therefore takes a small amount of additional network time, usually of about 5-10 seconds but potentially up to a minute (see this issue Pro for more details). If this presents a problem, the <code class="dcode">directConnect</code> capabilities can be used to speed up network time. To use this, your Appium client must support the <code class="dcode">directConnect</code> capabilities and the <code class="dcode">directConnect</code> capability must be set to <code class="dcode">true</code>. Currently only limited clients support this capbility. Please work with your internal IT departments and HeadSpin contacts to determine whether directConnect is a possibility for your testing environment.
A successful request with <code class="dcode">directConnect</code> made to AppiumLB will receive a <code class="dcode">create session</code> response, with information about the session through the <code class="dcode">directConnect</code> capabilities. The capabilities contain hostname, port and path to the actual Appium server with the devices selected for the tests. They are:
With this information, your Appium client can be configured to communicate with the test device directly.
Below are example requests sent with <code class="dcode">directConnect</code>.
● Python client <code class="dcode">0.39+</code>
- <code class="dcode">direct_connection</code> is enabled by default.
● ruby_lib_core <code class="dcode">3.0.1+</code>
- <code class="dcode">direct_connect</code> is enabled by default.
● Java client <code class="dcode">8.2.1+</code>
- Disabled by default
● webdriverio <code class="dcode">v7.16.14+</code>
- enableDirectConnect option configures the availability.
- <code class="dcode">enableDirectConnect</code> is enabled by default.
Below are some example responses as W3C or MJOSNWP with a session creation command.
W3C create session response
MJSONWP create session response
Selenium Grid and AppiumLB
Selenium Grid (hub) and AppiumLB behave similarly.
Selenium Grid has a hub and nodes. A node is a Selenium driver or an Appium server hosting a device. The hub handles a new session request to a proper node in order to establish a session following the capabilities. The node responds to the new session request with a session ID. Then, the hub proxies requests that have the same session ID to the proper node. This helps clients handle various nodes behind the hub since they need to know only one WebDriver URL through the hub. Clients do not need to know each WebDriver URL behind the hub for each separate Selenium driver and Appium server.
The Selenium Grid hub and node behavior and relationships are similar to AppiumLB and available devices in your device pool. AppiumLB picks a device up from your device pool in a new session request. It has the ability to wait for a device to be available using the <code class="dcode">waitForDeviceOnlineTimeout</code> capability. Once the new session request succeeds, commands for the same session ID can reach the device until the session is expired. One unique feature in AppiumLB is its directConnect capabilities to reduce network latency between the client and the device after a new session request. This feature allows clients to communicate with each PBox directly after a new session request. With direct connect, only the first new session request may have additional network latency due to routing through the load balancer.
A client needs to keep the HTTP connection to get a response by Selenium Grid or AppiumLB. A new session request tends to have a longer timeout than other commands since it includes some device setup processes. Client read timeouts before getting the response for a new session request can cause a new session creation failure. <code class="dcode">newSessionWaitTimeout</code> in Selenium Grid is similar to <code class="dcode">waitForDeviceOnlineTimeout</code> in AppiumLB to attempt to find an available node or device to coordinate the new session request.