Manteniendo una conexión ib_insync siempre activa con Sanic.
Estoy desarrollando una API (usando Sanic) que es una puerta de enlace a IB, utilizando ib insync. Esta API expone puntos finales para realizar un nuevo pedido y obtener las posiciones en tiempo real, pero también se encarga de actualizar los estados de los pedidos en una base de datos utilizando los eventos de ib insync.
Mi pregunta es: ¿es posible que la API se conecte solo una vez a IB cuando se inicia, y reutilice la misma conexión para todas las solicitudes?
Actualmente me estoy conectando a IB utilizando connectAsync en cada solicitud. Y aunque esto funciona, la API no recibirá eventos si no está manejando actualmente una solicitud.
Este es el código de un punto final, como referencia
@app.post(“/order/
async def post_order(request, symbol):
order = jsonpickle.decode(request.body)
with await IB().connectAsync(“127.0.0.1”, 7496, clientId=100) as ib:
ib.orderStatusEvent += onOrderStatus
ib.errorEvent += onTWSError
ib.newOrderEvent += onNewOrderEvent
contract = await ib.qualifyContractsAsync(contract)
trade = ib.placeOrder(contract[0], order)
return text(trade.order.orderId)
Entonces, deseo no usar la instrucción “with” y simplemente usar una conexión global de IB.
Cuando me conecto en la inicialización del módulo (usando connectAsync), cualquier llamada posterior que sea asíncrona, como qualifyContractsAsync, simplemente se bloquea. La depuración me mostró que se bloquea en asyncio.gather, lo que significa que algo está mal con los bucles de eventos.
davy.ai
Sí, es posible tener la API conectada solo una vez a IB cuando se inicia, y reutilizar la misma conexión para todas las solicitudes.
En lugar de conectarse a IB utilizando
connectAsync
en cada solicitud, puede mover el código de conexión a la inicialización del módulo, de modo que la conexión se establezca solo una vez cuando se cargue el módulo. Puede crear una variable globalib
para este propósito e inicializarla en el método__init__
del módulo.Luego, puedes usar este objeto
ib
global en tus controladores de solicitud, sin el uso de la declaraciónwith
.Ten en cuenta que aún necesitas asegurarte de que cualquier código asíncrono en tus controladores de solicitud no bloquee el bucle de eventos, de lo contrario, las solicitudes posteriores pueden quedarse bloqueadas. Si encuentras bloqueos en
asyncio.gather
, asegúrate de usar declaracionesasync with
con cualquier administrador de contexto asíncrono y evitar operaciones de bloqueo.“`python
async def some_async_operation():
async with ib_insync.IB().connectAsync(‘127.0.0.1’, 7496, clientId=100) as ib:
# usar instancia ib
@app.post(“/async_operation”)
async def async_operation(request):
await some_async_operation() # usar async with para asegurar que el contexto se cierre rápidamente
return text(“Operación asíncrona completada.”)
“`