erdewit / ib_insync

Python sync/async framework for Interactive Brokers API
BSD 2-Clause "Simplified" License
2.8k stars 743 forks source link

KeyboardInterrupt kills IBGW/TWS via IBC #225

Closed 3rock618 closed 4 years ago

3rock618 commented 4 years ago
from ib_insync import IBC
ibc = IBC(978, True, 'paper', userid='userid', password='pass')
ibc.start()

from time import sleep
try:
    print('program stuck...')
    sleep(1000)
except KeyboardInterrupt:
    print('KbI caught')

if you hit ctrl+c now, the proc that was launched in IBC is killed because it gets sent SIGINT.

I would like to suppress this because I often exit my program loop and debug in REPL. I did some research and looks like the accepted solution is to re-route SIGINT using subprocess.Popen.preexec_fn. Or in asyncio it would be:

import asyncio
import signal
preexec = lambda : signal.signal(signal.SIGINT, signal.SIG_IGN)
proc = await asyncio.create_subprocess_exec('shellscript.sh', preexec_fn=preexec)

However, with the current api there's no way to do this. I would like to propose adding one of the following changes Solution 1: in ibcontroller.py:

class IBC():
    def start(self, preexec_fn=None):
        util.run(self.startAsync(preexec_fn))
    async def startAsync(self, preexec_fn=None):
        self._proc = await asyncio.create_subprocess_exec(
            *cmd, stdout=asyncio.subprocess.PIPE, preexec_fn=preexec_fn)

then I can call ibc.start(lambda:signal.signal(signal.SIGINT, signal.SIG_IGN)) or alternatively solution 2, this can be baked in:

class IBC():
    suppressSIGINT = False
    async def startAsync(self):
        preexec_fn = lambda : signal.signal(signal.SIGINT, signal.SIG_IGN) if self.suppressSIGINT else None
        self._proc = await asyncio.create_subprocess_exec(
            *cmd, stdout=asyncio.subprocess.PIPE, preexec_fn = preexec_fn)

and then I can set this up with ibc.suppressSIGINT=True

erdewit commented 4 years ago

It's much easier to keep the gateway script running in it's own process and develop the rest in another script. That way there's no startup time when testing.

if you hit ctrl+c now, the proc that was launched in IBC is killed because it gets sent SIGINT.

Yes, and I rather keep it that way.