Prepare Your Application for Slow Network Connection

Some time ago I started to play with AngularJS to create a simple side-project app.

During this work I realized that I don’t like the differences between how the application works depending on the environment where I deploy it (localhost - faster and Docker on VPS - slower).

The UX was quite poor for slower network connection and I decided to do something about that.

The user experience was increased by applying some simple rules like:

There are plenty of resources on the web about how to design UX.

I started to reproduce the slow network connection on my local machine very naively by putting some TimeUnit.SECONDS.sleep(3) or alike into the REST boundary code on the server-side. You know - quick and dirty solution.

However, I thought it would be nice to have some more generic solution and I came up with trivial Servlet Filter implementation that simulates server-side operations taking a bit longer than you expect.

You can see the code here:

package com.piotrnowicki.utils.slowdownfilter;

import javax.servlet.*;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Filter which only aim is to slow down execution of the filtered 
 * resources. It is useful in cases you want to test how your 
 * application behaves in slow-network environment.
 *
 * @author Piotr Nowicki
 */
public class SlowDownFilter implements Filter {
    private static final Logger LOGGER = 
                         Logger.getLogger(SlowDownFilter.class.getName());

    static final String DELAY_PARAM_NAME = "delay";
    static final long DEFAULT_DELAY_IN_MS = 5000L;

    long delayInMs;

    @Override
    public void init(FilterConfig config) throws ServletException {
        delayInMs = fetchDelay(config.getInitParameter(DELAY_PARAM_NAME));
    }

    private long fetchDelay(String delayParam) {
        try {
            return Long.valueOf(delayParam);
        } catch (NumberFormatException ex) {
            String msg = String.format("Invalid value for delay [%s] ms. Running with default [%s] ms", 
                                             delayParam, 
                                             DEFAULT_DELAY_IN_MS);
            LOGGER.log(Level.WARN, msg, ex);
                
            return DEFAULT_DELAY_IN_MS;
        }
    }

    @Override
    public void doFilter(ServletRequest request, 
                         ServletResponse response, 
                         FilterChain chain) 
                                   throws IOException, ServletException {
        try {
            TimeUnit.MILLISECONDS.sleep(delayInMs);
        } catch (InterruptedException e) {
            LOGGER.log(Level.INFO, "Thread interrupted", e);
        }

        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {
        // Do nothing
    }
}

It’s so naively simple that it actually does the job ;-)

You just plug it into your web.xml and (optionally) define the delay in milliseconds as a init-param:

    <filter>
        <filter-name>Slow Down Filter</filter-name>
        <filter-class>com.piotrnowicki.slowdownfilter.SlowDownFilter</filter-class>
        <init-param>
            <param-name>delay</param-name>
            <param-value>2000</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>Slow Down Filter</filter-name>
        <url-pattern>/resources/*</url-pattern>
    </filter-mapping>

Simple, useful and forces you to correctly prepare your user interface for network slowdowns.