I don't understand your comment, Dmitry, why centralizing the ID generation still can get duplicate IDs.
I presented a pseudo language example but every language has concepts that make nextRequestId() a strictly monotonically increasing function. In other words, each call returns a number this is higher than all other numbers returned before and no number will ever be returned again. And that is guaranteed regardless of how many threads and loops execute in parallel.
In Java, for example, you can simply declare the function as public synchronized or use an AtomicInteger instead of simply int. For many years we run applications with many parallel threads on systems with several processors and have never seen error 322.
Now, the real solution here is an application architecture that completely removes request Ids (and other API details) from the business logic. Such as wrapping a thin controller layer around TWS API calls so that these implementation details are completely hidden from client code. A good example is the ApiController class that is part of the TWS API Java version. So, instead of calling the TWS API method
reqMktData( int tickerId, Contract contract, String genericTickList, boolean snapshot, boolean regulatorySnapshot, List<TagValue> mktDataOptions )
and having to manage request ids and having to implement routing code for returned data by requestId to your appropriate logic you simply call
reqTopMktData( Contract contract, String genericTickList, boolean snapshot, boolean regulatorySnapshot, ITopMktDataHandler handler )
and the controller automatically routes the data stream directly to your handler function.
Or look at Ewald de Wit's very well architected ib_insync Python library, and you receive the subscribed data streams via asynchronous events whenever they arrive.
´³¨¹°ù²µ±ð²Ô
On Sun, Jan 29, 2023 at 10:49 AM, Dmitry Shevkoplyas wrote:
toggle quoted message
Show quoted text
Hi Liu,
?
The "foreach" execute nested code block concurrently.
Your code has "counter" incremented in one line and then used in another line.
The "counter" variable is shared across all you (many) code blocks expected in parallel, which means that between incrementing and later using your 'counter" another similar block (working in parallel) might sometimes be lucky to increment the same shared "counter" one more time, thus both blocks of code will send the request with the same Id.
?
When you're trying to debug this with breakpoints?and step-by-stem?execution it is millions time slower and it is completely different run-mode, thus you have close to zero chances?to witness that particular behaviour.
?
Unfortunately ´³¨¹°ù²µ±ð²Ô's suggestion to move counter increment into the separate f-n won't change anything - you'll still get duplicates from time to?time.
?
Cheers,
Dmitry
On Fri, Jan 27, 2023 at 8:40 PM ´³¨¹°ù²µ±ð²Ô Reinold via <TwsApiOnGroupsIo=
[email protected]> wrote:
Well, somewhere in your program an API request is made with a duplicate requestId or tickerId. The error callback should give you the exact id at fault.
"reqId + counter" is a bad idea. You should have a function, such as nextRequestId(), that provides a new and unique Id every time the function is called. It is sufficient that the function simply returns the value of an incremented variable such as (pseudo language):
private integer _nextRestId = 10000000;
funtion integer nextRequestId()
{
??? return _nextRequestId++;
}
We found it helpful to start request Ids at a high number so that they cannot be confused with orderIds.? But "_nextRestId? = 1" will work just fine.
Now, every API request (not just reqMktData) gets a unique Id by a call to nextRequestId().
´³¨¹°ù²µ±ð²Ô
?
?