- edited description
Handle concurrent requests correctly
We have been postponing this for long now, but it is time today I crack down on it. We have one Global TradeInterface object, and multiple threads access to it. with GUI number of threads increased, so we are ending up with a lot of situation where
[main] ERROR - ApiError [5 : Nonce must be greater than 1430207994618. You provided 1430207994390.] [c.n.n.t.WrapperTestUtils:238]
because another thread completed the request...
This is what can happen (and it is happning) currently , two threads A and B, unaware of each other existance :
A creates a nonce=1
B creates a nonce=2
Server receives B first and sets the upper limit to 2
B succeeds
, A fails
I am looking for a solid solution to the problem above. There are many possible ways but each one is delicate
The solution requires an external object, global, that is aware of all requests that are being submitted. So let's call this object 'oracle'
oracle has a method requestNonce() and a boolean flag :isSomeoneElseDoingAnAPIRequest so now we could leverage the method that all wrappers uses to make calls :
getQuery()
the question is : how?
Comments (5)
-
reporter -
reporter new query() method
public String query(String base, String method, AbstractMap<String, String> args, boolean needAuth, boolean isGet) { String queryResult = TOKEN_BAD_RETURN; //Will return this string in case it fails if (exchange.getLiveData().isConnected()) { if (exchange.isFree()) { exchange.setBusy(); queryResult = service.executeQuery(base, method, args, needAuth, isGet); exchange.setFree(); } else { //Another thread is probably executing a query. Init the retry procedure long sleeptime = Settings.RETRY_SLEEP_INCREMENT * 1; int counter = 0; long startTimeStamp = System.currentTimeMillis(); LOG.debug(method + " blocked, another call is being processed "); boolean exit = false; do { counter++; sleeptime = counter * Settings.RETRY_SLEEP_INCREMENT; //Increase sleep time sleeptime += (int) (Math.random() * 200) - 100;// Add +- 100 ms random to facilitate competition LOG.debug("Retrying for the " + counter + " time. Sleep for " + sleeptime + "; Method=" + method); try { Thread.sleep(sleeptime); } catch (InterruptedException e) { LOG.error(e.toString()); } //Try executing the call if (exchange.isFree()) { LOG.debug("Finally the exchange is free, executing query after " + counter + " attempt. Method=" + method); exchange.setBusy(); queryResult = service.executeQuery(base, method, args, needAuth, isGet); exchange.setFree(); break; //Exit loop } else { LOG.debug("Exchange still busy : " + counter + " .Will retry soon; Method=" + method); exit = false; } if (System.currentTimeMillis() - startTimeStamp >= Settings.TIMEOUT_QUERY_RETRY) { exit = true; LOG.error("Method=" + method + " failed too many times and timed out. attempts = " + counter); } } while (!exit); } } else { LOG.error("The bot will not execute the query, there is no connection to BitcoinCoId"); queryResult = TOKEN_BAD_RETURN; } return queryResult; }
-
reporter - changed status to resolved
-
reporter see it in action with two calls on wait : https://docs.google.com/document/d/12Sym1TaSWTsac4HiBZ3ceXxSW1Lo_GnK_8leO8lyVws/edit
-
reporter - changed milestone to 0.3.0 - UI
- Log in to comment