Skip to content

cannot connect to IB using 2 threads with 2 different clientId #159

@damonYuan

Description

@damonYuan

As you can see in the following logs, when I start 2 threads (I want different threads to manage different underlying as you can tell by the thread name in the log)

    def run(self):
        startLoop()

        async def my_loop():
            while not self.__stop_event.is_set():
                if not self.ib_client.is_connected():
                    await self.ib_client.connect_async() # it just calls `async def connectAsync(...)`
                else:
                    sleep(1)
                    logging.info("sleep 1")
            self._clean_up()

        run(my_loop())

it throws errors as below,

[2025-07-02 23:50:43,201][INFO][runner-TLT] Connecting to IB Gateway...
[2025-07-02 23:50:43,201][INFO][runner-QQQ] Connecting to IB Gateway...
[2025-07-02 23:50:43,201][INFO][runner-TLT] Connecting to 127.0.0.1:4002 with clientId 20...
[2025-07-02 23:50:43,201][INFO][runner-QQQ] Connecting to 127.0.0.1:4002 with clientId 23...
[2025-07-02 23:50:43,202][INFO][runner-TLT] Disconnecting
[2025-07-02 23:50:43,202][ERROR][runner-TLT] API connection failed: RuntimeError("Task <Task pending name='Task-1' coro=<StratRunner.run.<locals>.my_loop() running at /Users/damon/Desktop/workspace/IronCondor/src/ironcondor/service/strat_runner.py:45>> got Future <Future pending cb=[BaseSelectorEventLoop._sock_write_done()()]> attached to a different loop")
[2025-07-02 23:50:43,202][INFO][runner-QQQ] Connected
[2025-07-02 23:50:43,202][ERROR][runner-TLT] Uncaught thread exception
Traceback (most recent call last):
  File "/Users/damon/Library/Application Support/hatch/env/virtual/.pythons/3.13/python/lib/python3.13/threading.py", line 1041, in _bootstrap_inner
    self.run()
    ~~~~~~~~^^
  File "/Users/damon/Desktop/workspace/IronCondor/src/ironcondor/service/strat_runner.py", line 51, in run
    run(my_loop())
    ~~~^^^^^^^^^^^
  File "/Users/damon/Library/Application Support/hatch/env/virtual/ironcondor/EhF6heFF/ironcondor/lib/python3.13/site-packages/ib_async/util.py", line 374, in run
    result = loop.run_until_complete(task)
  File "/Users/damon/Library/Application Support/hatch/env/virtual/ironcondor/EhF6heFF/ironcondor/lib/python3.13/site-packages/nest_asyncio.py", line 98, in run_until_complete
    return f.result()
           ~~~~~~~~^^
  File "/Users/damon/Library/Application Support/hatch/env/virtual/.pythons/3.13/python/lib/python3.13/asyncio/futures.py", line 199, in result
    raise self._exception.with_traceback(self._exception_tb)
  File "/Users/damon/Library/Application Support/hatch/env/virtual/.pythons/3.13/python/lib/python3.13/asyncio/tasks.py", line 306, in __step_run_and_handle_result
    result = coro.throw(exc)
  File "/Users/damon/Desktop/workspace/IronCondor/src/ironcondor/service/strat_runner.py", line 45, in my_loop
    await self.ib_client.connect_async()
  File "/Users/damon/Desktop/workspace/IronCondor/src/ironcondor/util/ib_client.py", line 48, in connect_async
    await self.ib.connectAsync(self.host, self.port, clientId=self.client_id)
  File "/Users/damon/Library/Application Support/hatch/env/virtual/ironcondor/EhF6heFF/ironcondor/lib/python3.13/site-packages/ib_async/ib.py", line 2043, in connectAsync
    await self.client.connectAsync(host, port, clientId, timeout)
  File "/Users/damon/Library/Application Support/hatch/env/virtual/ironcondor/EhF6heFF/ironcondor/lib/python3.13/site-packages/ib_async/client.py", line 217, in connectAsync
    await asyncio.wait_for(self.conn.connectAsync(host, port), timeout)
  File "/Users/damon/Library/Application Support/hatch/env/virtual/.pythons/3.13/python/lib/python3.13/asyncio/tasks.py", line 507, in wait_for
    return await fut
           ^^^^^^^^^
  File "/Users/damon/Library/Application Support/hatch/env/virtual/ironcondor/EhF6heFF/ironcondor/lib/python3.13/site-packages/ib_async/connection.py", line 39, in connectAsync
    self.transport, _ = await loop.create_connection(lambda: self, host, port)
                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/damon/Library/Application Support/hatch/env/virtual/.pythons/3.13/python/lib/python3.13/asyncio/base_events.py", line 1136, in create_connection
    sock = await self._connect_sock(
           ^^^^^^^^^^^^^^^^^^^^^^^^^
        exceptions, addrinfo, laddr_infos)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/damon/Library/Application Support/hatch/env/virtual/.pythons/3.13/python/lib/python3.13/asyncio/base_events.py", line 1039, in _connect_sock
    await self.sock_connect(sock, address)
  File "/Users/damon/Library/Application Support/hatch/env/virtual/.pythons/3.13/python/lib/python3.13/asyncio/selector_events.py", line 641, in sock_connect
    return await fut
           ^^^^^^^^^
  File "/Users/damon/Library/Application Support/hatch/env/virtual/.pythons/3.13/python/lib/python3.13/asyncio/futures.py", line 286, in __await__
    yield self  # This tells Task to wait for completion.
    ^^^^^^^^^^
RuntimeError: Task <Task pending name='Task-1' coro=<StratRunner.run.<locals>.my_loop() running at /Users/damon/Desktop/workspace/IronCondor/src/ironcondor/service/strat_runner.py:45>> got Future <Future pending cb=[BaseSelectorEventLoop._sock_write_done()()]> attached to a different loop
[2025-07-02 23:50:47,203][INFO][runner-QQQ] Disconnecting
[2025-07-02 23:50:47,203][ERROR][runner-QQQ] API connection failed: TimeoutError()
[2025-07-02 23:50:47,203][ERROR][runner-QQQ] Uncaught thread exception
Traceback (most recent call last):
  File "/Users/damon/Library/Application Support/hatch/env/virtual/.pythons/3.13/python/lib/python3.13/asyncio/tasks.py", line 507, in wait_for
    return await fut
           ^^^^^^^^^
  File "/Users/damon/Library/Application Support/hatch/env/virtual/.pythons/3.13/python/lib/python3.13/asyncio/futures.py", line 286, in __await__
    yield self  # This tells Task to wait for completion.
    ^^^^^^^^^^
  File "/Users/damon/Library/Application Support/hatch/env/virtual/.pythons/3.13/python/lib/python3.13/asyncio/tasks.py", line 375, in __wakeup
    future.result()
    ~~~~~~~~~~~~~^^
  File "/Users/damon/Library/Application Support/hatch/env/virtual/.pythons/3.13/python/lib/python3.13/asyncio/futures.py", line 194, in result
    raise self._make_cancelled_error()
asyncio.exceptions.CancelledError

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/Users/damon/Library/Application Support/hatch/env/virtual/.pythons/3.13/python/lib/python3.13/threading.py", line 1041, in _bootstrap_inner
    self.run()
    ~~~~~~~~^^
  File "/Users/damon/Desktop/workspace/IronCondor/src/ironcondor/service/strat_runner.py", line 51, in run
    run(my_loop())
    ~~~^^^^^^^^^^^
  File "/Users/damon/Library/Application Support/hatch/env/virtual/ironcondor/EhF6heFF/ironcondor/lib/python3.13/site-packages/ib_async/util.py", line 374, in run
    result = loop.run_until_complete(task)
  File "/Users/damon/Library/Application Support/hatch/env/virtual/ironcondor/EhF6heFF/ironcondor/lib/python3.13/site-packages/nest_asyncio.py", line 98, in run_until_complete
    return f.result()
           ~~~~~~~~^^
  File "/Users/damon/Library/Application Support/hatch/env/virtual/.pythons/3.13/python/lib/python3.13/asyncio/futures.py", line 199, in result
    raise self._exception.with_traceback(self._exception_tb)
  File "/Users/damon/Library/Application Support/hatch/env/virtual/.pythons/3.13/python/lib/python3.13/asyncio/tasks.py", line 306, in __step_run_and_handle_result
    result = coro.throw(exc)
  File "/Users/damon/Desktop/workspace/IronCondor/src/ironcondor/service/strat_runner.py", line 45, in my_loop
    await self.ib_client.connect_async()
  File "/Users/damon/Desktop/workspace/IronCondor/src/ironcondor/util/ib_client.py", line 48, in connect_async
    await self.ib.connectAsync(self.host, self.port, clientId=self.client_id)
  File "/Users/damon/Library/Application Support/hatch/env/virtual/ironcondor/EhF6heFF/ironcondor/lib/python3.13/site-packages/ib_async/ib.py", line 2043, in connectAsync
    await self.client.connectAsync(host, port, clientId, timeout)
  File "/Users/damon/Library/Application Support/hatch/env/virtual/ironcondor/EhF6heFF/ironcondor/lib/python3.13/site-packages/ib_async/client.py", line 228, in connectAsync
    await asyncio.wait_for(self.apiStart, timeout)
  File "/Users/damon/Library/Application Support/hatch/env/virtual/.pythons/3.13/python/lib/python3.13/asyncio/tasks.py", line 506, in wait_for
    async with timeouts.timeout(timeout):
               ~~~~~~~~~~~~~~~~^^^^^^^^^
  File "/Users/damon/Library/Application Support/hatch/env/virtual/.pythons/3.13/python/lib/python3.13/asyncio/timeouts.py", line 116, in __aexit__
    raise TimeoutError from exc_val
TimeoutError

Process finished with exit code 0

But it works well with only 1 thread.

It worked fine with multiple threads in 1.0.3 but errors happen in 2.0.1. I have also encountered similar issue as #103 if I try to set the loop to the asyncio explicitly.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions