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

Serious Issues with Login if Deepstream Host is Down #120

Open
knocknarea opened this issue Dec 5, 2017 · 2 comments
Open

Serious Issues with Login if Deepstream Host is Down #120

knocknarea opened this issue Dec 5, 2017 · 2 comments

Comments

@knocknarea
Copy link

If you attempt to connect to deepstream when the host is down (or not running, for whatever reason)

The DeepStreamClient.login(...) method hangs indefinitely.

There is a countdown latch that needs to be pulled to ZERO before this method can proceed. In the case where you have a connection refused (because the host is unavailable). The code ends up in this deadend and does not call whatever code brings the latch to ZERO.

The LoginCallback is never called. It appears that all the methods depend on a response from the server to invoke the callback.

As an aside the error handlers that you can set into the DeepStreamClient are of little use as the method signature does not contain any reference to the DeepStreamClient that caused the error to happen in the first place.

I don't know if anyone is developing this code anymore but it's a big problem for us. It should be easy to recreate on your side, just try to connect to a host location that is unavailable.

@knocknarea
Copy link
Author

Anyone interested in a workaround for this while waiting, I put this together:

public class FastFailDeepstreamClient extends DeepstreamClient implements DeepstreamRuntimeErrorHandler {
	
	private static final Logger logger = LoggerFactory.getLogger(FastFailDeepstreamClient.class);

	private volatile Thread callingThread;
	
	/**
	 * @param url
	 * @throws URISyntaxException
	 */
	public FastFailDeepstreamClient(String url) throws URISyntaxException {
		super(url);
		this.setRuntimeErrorHandler(this);
	}

	/**
	 * @param url
	 * @param options
	 * @throws URISyntaxException
	 * @throws InvalidDeepstreamConfig
	 */
	public FastFailDeepstreamClient(String url, Map<ConfigOptions, Object> options) throws URISyntaxException, InvalidDeepstreamConfig {
		super(url, options);
		this.setRuntimeErrorHandler(this);
	}

	@Override
	public LoginResult login(JsonElement data) {
		
		//
		// Internal to the login method of DeepstreamClient is a countdown latch that does not get
		// set to ZERO if the deepstream host is unavailable. The login method performs an indefinite
		// await() on this latch leading to a thread hang.
		// We capture the calling thread on the way into the login method. We also have a runtime handler installed
		// if we receive a CONNECTION_ERROR and the calling thread is not null, then we interrupt it so the login method continues
		// to failure.
		//
		this.callingThread = Thread.currentThread();
		
		LoginResult result = null;
		
		try {
			result = super.login(data);
			logger.debug("Login to Deepstream was a {}", result != null ? (result.loggedIn() ? "SUCCESS" : "FAILURE") : "FAILURE" );
		}
		finally {
			try {
				Thread.interrupted();
			}
			catch(Exception e) {}
			finally {
				this.callingThread = null;	
			}
		}
		return result;
	}

	/* (non-Javadoc)
	 * @see io.deepstream.DeepstreamRuntimeErrorHandler#onException(io.deepstream.Topic, io.deepstream.Event, java.lang.String)
	 */
	@Override
	public void onException(Topic topic, Event event, String arg) {
		switch(event) {
		case CONNECTION_ERROR:
			logger.warn("Received Connection Error on Deepstream");
			//
			// This is to get around a bug in DS client 
			// https://github.com/deepstreamIO/deepstream.io-client-java/issues/120
			// 
			if(this.callingThread != null) {
				//
				// Interrupt the code that will lock if there is no connection to deepstream at all (connection refused)
				//
				this.callingThread.interrupt();
			}
			break;
		default:
			break;
		}
	}
}

@StephanSchuster
Copy link

Same problem here! Any plans on fixing this (critical) issue?

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

No branches or pull requests

2 participants