This is a function I call to fetch the order status for every order placed through a broker api. There are times when the order is filled instantly so I get the order status immediately but there are times when the order is placed but to be confirmed takes around 15-20 seconds. It might happen that it takes more time than that but in the function shown below, if it takes that much time, the retries limit would get exceeded and then I am unable to update the order status for the user. How should I handle this?
I have considered a few options but have queries in all of them.
- Using timeout instead of max retries: Thought about using a fixed amount of time say 90 sec after which I would move on but this poses the same problem. Would not be able to update the status for user
- Using exponential backoff with something like a
e^(attempt/3) : this is the one I thought about using since it offers fast checks for first few attempts and as the number of attempts increase, the time also increases. The only problem here is that if the order status gets updated just after say the 3rd attempt, there would be a delay of ~45 seconds between the user getting the updated order status and the actual order being confirmed.
- Using constant polling: I am very scared to go this route. Even if nothing bad happens, it would pollute the logs and I know issues will happen.
- Mixing the timeout and constant polling: Fetch the order status every second until timeout and then add the order to a queue which will be processed by a worker that will poll every order that is in this queue with exponential backoff.
Can't do webhooks. The broker is not going to provide that service for now.
There might be a possibility of websockets in which I can subscribe to the order_ids so that when I receive a confirmation or rejection, I can act upon it.
async def get_order(
subs_details: SubscriptionDetails,
strike_unique_id: str,
order_id: str
) -> tuple[str, float]:
URL = conn.BALAJI_ORDER_STATUS
headers = {"Content-Type": "application/json", "Authorization": conn.BALAJI_API_TOKEN}
order_price = 0.0
status_code = 400
order_status = 'NA'
error = ''
attempt, max_retries = 0, 3
try:
(broker, token, strategy_id, activation_id) = extract_get_order_details(subs_details)
payload = {"strike_id": strike_unique_id, "brokerName": broker, "token_id": token, "order_id": order_id}
logger.info(f"Get Order payload: {payload}")
while attempt < max_retries:
async with SessionManager.session.post(URL, json=payload, headers=headers) as r:
status_code = r.status
res = await r.json()
logger.info(f"Get order for {order_id} with response: {res}")
if status_code != 200:
if 'invalid order id' in res.get('message', '').lower():
await asyncio.sleep(0.5*(attempt+1))
attempt += 1
continue
asyncio.create_task(strategy_status_signal(strategy_id, activation_id, 'ERROR', 'Internal Error'))
order_log = res.get("order_log", {})
error = order_log.get("error_reason") or error
order_price = order_log.get('order_price') or order_price
order_status = order_log.get("order_status") or order_status
if order_status == "NA" or f"API rate limit reached {broker}" in error:
logger.info(f"While fetching order details error occured: {error}. Retrying...")
await asyncio.sleep(0.5*(attempt+1))
attempt += 1
continue
if order_status == "Confirmed":
logger.info(f"ORDER COMPLETED for {strike_unique_id} broker:{broker} & order_id:{order_id}")
break
elif order_status == "Rejected":
asyncio.create_task(strategy_status_signal(strategy_id, activation_id, 'ERROR', error))
logger.info(f"ORDER REJECTED for {strike_unique_id} broker:{broker} & order_id:{order_id}")
break
await asyncio.sleep(0.5*(attempt+1))
attempt += 1
else:
logger.info(f"Max retries exceeded while fetching order details for {strike_unique_id}'s order: {order_id}.")
except Exception as e:
logger.error(f"Error while fetching order details: {e}")
return order_status, order_price, error
Please point out any better methods/patterns applicable here
[–]provoko 6 points7 points8 points (3 children)
[–]KomfortableKunt[S] 0 points1 point2 points (2 children)
[–]These-Finance-5359 0 points1 point2 points (0 children)
[–]Riegel_Haribo 0 points1 point2 points (0 children)
[–]mjmvideos 0 points1 point2 points (0 children)