Artificial Latency: A How To

Jun 29, 2014

So you have a client side app written in javascript and you are worried about latency. This latency is inevitable and can arise in loading assets as well as in AJAX calls. Now you have taken care of those situations and have written your app to behave gracefully in those waiting periods.

The problem

However, how do you test the behavior of your app in these cases when all you have is blazing fast access to the Internet?

We would want the test to be easy to turn on an off.

Ideally, it would be as simple as changing only the source code of the app (the HTML or the apiPrefix) and reloading the browser.

The setup

Your development setup probably looks like this:

In the normal no-artificial-delay situation, your app is served by a Local Webserver:

The Local Backend might be merged with the Local WebServer (like in Rails or Jetty) or it could be running separately (as depicted). The backend may be running locally or the web-server may be proxying requests to a sandbox backend hosted on the Internet. Optionally, your app may load some assets from the internet directly.

The remote assets

Loading of those assets is relatively easy to delay and test.

You can use a delay proxy by replacing the URL of your resource http://remote.com/asset.png by http://deelay.me/5000/http://remote.com/asset.png

* Note the double ee in deelay.

Deelay.me is an delay proxy which will redirect the browser to the original URL after sufficient delay.

However, Deelay.me has some short-comings. You cannot access resources over https and it does not set the correct CORS headers. I am working on a project receive-in to address these issues.

Update: It turns out that what I was trying to do via CORS header is explicitly not allowed in the spec. However, the spec may allow this behavior if a compelling use-case comes up.

The local assets

You can take a similar approach here.

I would recommend running OpenResty (configured --with-luajit). Then you can configure your nginx to delay all paths with the prefix /delay/([0-9]+)/ with the following location block:

Now, you will be able to introduce a 5 sec delay by replacing an API call to /api/user/1 by /delay/5000/api/user/1.

Hack: You can make this work for remote servers too if you edit the hosts file and redirect request to the Internet to your local machine.

Other solutions

If you do not want to go through the trouble of installing OpenResty and running a local webserver, then one of the following solutions may work for you.

The backend

If you are running your backend locally, then you can delay individual requests on your backend itself:

If you are developing an integrated web-server + backend application, then this might be the easiest option for you. However, the server may not allow you to easily add latency while serving files from the HDD.

The network interface

If you are on linux then you can slow down your lo connection. However, but this slows down everything, which may be too much if you want to test how delay affects one request.

On Mac OSX, there is a Network Link Conditioner tool which can slow down the connection for you. It can simulate 3G, WiFi, high latency DNS, etc. connections as well, which can be great to assess the behavior of your app on those networks. However, this too slows all the connections, which is not what we want while testing for the slow response for certain requests.

Delay in the local-webserver

Often the Local WebServer will allow usage of some middleware to delay the requests:

Grunt

If you are using grunt as part of your workflow and using grunt-contrib-connect or grunt-express to serve your app, then you can use grunt-connect-delay to delay your requests by 5 secs by prefixing them with /delay/5000/. I have written an example app while using it.

For an example of how the plugin can be of use, have you ever thought what would happen if your fonts loaded very slowly?

Other resources

If there are delays, then you should always give users a sense of progress. These resources will help you do that: