|
94 | 94 | from time import sleep |
95 | 95 | from argparse import ArgumentParser |
96 | 96 | from importlib.metadata import version |
97 | | -from multiprocessing import cpu_count, Lock |
| 97 | +from multiprocessing import cpu_count |
98 | 98 |
|
99 | 99 | # Third-party library imports: |
100 | 100 | import numpy as np |
@@ -193,8 +193,6 @@ def __init__(self, token: str, accountId: str = None, useCache: bool = True, def |
193 | 193 | self._tag = "" |
194 | 194 | """Identification TKSBrokerAPI tag in log messages to simplify debugging when platform instances runs in parallel mode. Default: `""` (empty string).""" |
195 | 195 |
|
196 | | - self.__lock = Lock() # initialize multiprocessing mutex lock |
197 | | - |
198 | 196 | self._precision = 4 # precision, signs after comma, e.g. 2 for instruments like PLZL, 4 for instruments like USDRUB, if -1 then auto detect it when load data-file |
199 | 197 |
|
200 | 198 | self.aliases = TKS_TICKER_ALIASES |
@@ -567,119 +565,118 @@ def SendAPIRequest(self, url: str, reqType: str = "GET") -> dict: |
567 | 565 | break |
568 | 566 |
|
569 | 567 | if oK: |
570 | | - with self.__lock: # acquire the mutex lock |
571 | | - counter = 0 |
572 | | - response = None |
573 | | - errMsg = "" |
574 | | - currentPause = self.pause # initial pause |
| 568 | + counter = 0 |
| 569 | + response = None |
| 570 | + errMsg = "" |
| 571 | + currentPause = self.pause # initial pause |
575 | 572 |
|
576 | | - while not response and counter <= self.retry: |
577 | | - try: |
578 | | - # try to send REST-request: |
579 | | - if reqType == "GET": |
580 | | - response = requests.get(url, headers=self.headers, data=self.body, timeout=self.timeout) |
| 573 | + while not response and counter <= self.retry: |
| 574 | + try: |
| 575 | + # try to send REST-request: |
| 576 | + if reqType == "GET": |
| 577 | + response = requests.get(url, headers=self.headers, data=self.body, timeout=self.timeout) |
581 | 578 |
|
582 | | - if reqType == "POST": |
583 | | - response = requests.post(url, headers=self.headers, data=self.body, timeout=self.timeout) |
| 579 | + if reqType == "POST": |
| 580 | + response = requests.post(url, headers=self.headers, data=self.body, timeout=self.timeout) |
584 | 581 |
|
585 | | - except requests.exceptions.RequestException as e: |
586 | | - # catch expected connection/request exceptions: |
587 | | - uLogger.debug("Request exception occurred: {}.".format(e)) |
| 582 | + except requests.exceptions.RequestException as e: |
| 583 | + # catch expected connection/request exceptions: |
| 584 | + uLogger.debug("Request exception occurred: {}.".format(e)) |
588 | 585 |
|
589 | | - except Exception as e: |
590 | | - # catch any unexpected exception (safety net): |
591 | | - uLogger.debug("Unexpected exception occurred during request: {}.".format(e)) |
| 586 | + except Exception as e: |
| 587 | + # catch any unexpected exception (safety net): |
| 588 | + uLogger.debug("Unexpected exception occurred during request: {}.".format(e)) |
592 | 589 |
|
593 | | - finally: |
594 | | - # always check: if no valid response received, increment counter and retry after a pause |
595 | | - if not response: |
596 | | - counter += 1 # increase retry counter |
| 590 | + finally: |
| 591 | + # always check: if no valid response received, increment counter and retry after a pause |
| 592 | + if not response: |
| 593 | + counter += 1 # increase retry counter |
597 | 594 |
|
598 | | - if counter > self.retry: |
599 | | - uLogger.debug("Maximum retry limit ({}) exceeded without success.".format(self.retry)) |
| 595 | + if counter > self.retry: |
| 596 | + uLogger.debug("Maximum retry limit ({}) exceeded without success.".format(self.retry)) |
600 | 597 |
|
601 | | - return responseJSON # explicitly exit the method |
| 598 | + return responseJSON # explicitly exit the method |
602 | 599 |
|
603 | | - uLogger.debug("Retry {}/{} after {} sec...".format(counter, self.retry, currentPause)) |
| 600 | + uLogger.debug("Retry {}/{} after {} sec...".format(counter, self.retry, currentPause)) |
604 | 601 |
|
605 | | - sleep(currentPause) # wait before the next retry |
| 602 | + sleep(currentPause) # wait before the next retry |
606 | 603 |
|
607 | | - currentPause = min(currentPause * 2, 30) # exponentially increase wait time but limit maximum pause |
| 604 | + currentPause = min(currentPause * 2, 30) # exponentially increase wait time but limit maximum pause |
608 | 605 |
|
609 | | - continue # next retry attempt |
| 606 | + continue # next retry attempt |
610 | 607 |
|
611 | | - if self.moreDebug and response: |
612 | | - uLogger.debug("Response:") |
613 | | - uLogger.debug(" - status code: {}".format(response.status_code)) |
614 | | - uLogger.debug(" - reason: {}".format(response.reason)) |
615 | | - uLogger.debug(" - body length: {}".format(len(response.text))) |
616 | | - uLogger.debug(" - headers:\n{}".format(response.headers)) |
| 608 | + if self.moreDebug and response: |
| 609 | + uLogger.debug("Response:") |
| 610 | + uLogger.debug(" - status code: {}".format(response.status_code)) |
| 611 | + uLogger.debug(" - reason: {}".format(response.reason)) |
| 612 | + uLogger.debug(" - body length: {}".format(len(response.text))) |
| 613 | + uLogger.debug(" - headers:\n{}".format(response.headers)) |
617 | 614 |
|
618 | | - # check rate limit headers: https://tinkoff.github.io/investAPI/grpc/#kreya |
619 | | - if response and response.headers and response.headers.get("x-ratelimit-remaining") == "0": |
620 | | - rateLimitWait = int(response.headers["x-ratelimit-reset"]) |
| 615 | + # check rate limit headers: https://tinkoff.github.io/investAPI/grpc/#kreya |
| 616 | + if response and response.headers and response.headers.get("x-ratelimit-remaining") == "0": |
| 617 | + rateLimitWait = int(response.headers["x-ratelimit-reset"]) |
621 | 618 |
|
622 | | - uLogger.debug("Rate limit exceeded. Waiting {} sec. for reset rate limit and then repeat again...".format(rateLimitWait)) |
| 619 | + uLogger.debug("Rate limit exceeded. Waiting {} sec. for reset rate limit and then repeat again...".format(rateLimitWait)) |
623 | 620 |
|
624 | | - sleep(rateLimitWait) |
| 621 | + sleep(rateLimitWait) |
625 | 622 |
|
626 | | - # handling 4xx client errors: https://en.wikipedia.org/wiki/List_of_HTTP_status_codes |
627 | | - if response and 400 <= response.status_code < 500: |
628 | | - bodyPreview = response.text[:256] + ("..." if len(response.text) > 256 else "") |
629 | | - msg = "status code: [{}], response body: {}".format(response.status_code, bodyPreview) |
| 623 | + # handling 4xx client errors: https://en.wikipedia.org/wiki/List_of_HTTP_status_codes |
| 624 | + if response and 400 <= response.status_code < 500: |
| 625 | + bodyPreview = response.text[:256] + ("..." if len(response.text) > 256 else "") |
| 626 | + msg = "status code: [{}], response body: {}".format(response.status_code, bodyPreview) |
630 | 627 |
|
631 | | - uLogger.debug(" - not oK, but do not retry for 4xx errors, {}".format(msg)) |
| 628 | + uLogger.debug(" - not oK, but do not retry for 4xx errors, {}".format(msg)) |
632 | 629 |
|
633 | | - if "code" in response.text and "message" in response.text: |
634 | | - if "Authentication token is missing or invalid" in response.text: |
635 | | - uLogger.warning("Authentication token is missing or invalid! Generate a new token, please.") |
| 630 | + if "code" in response.text and "message" in response.text: |
| 631 | + if "Authentication token is missing or invalid" in response.text: |
| 632 | + uLogger.warning("Authentication token is missing or invalid! Generate a new token, please.") |
636 | 633 |
|
637 | | - elif "Insufficient privileges" in response.text: |
638 | | - uLogger.warning("Insufficient privileges to perform this operation! Please verify that the token matches the user's account.") |
| 634 | + elif "Insufficient privileges" in response.text: |
| 635 | + uLogger.warning("Insufficient privileges to perform this operation! Please verify that the token matches the user's account.") |
639 | 636 |
|
640 | | - else: |
641 | | - msgDict = self._ParseJSON(rawData=response.text) |
| 637 | + else: |
| 638 | + msgDict = self._ParseJSON(rawData=response.text) |
642 | 639 |
|
643 | | - uLogger.debug("HTTP-status code [{}], server message: {}".format(response.status_code, msgDict.get("message", ""))) |
| 640 | + uLogger.debug("HTTP-status code [{}], server message: {}".format(response.status_code, msgDict.get("message", ""))) |
644 | 641 |
|
645 | | - else: |
646 | | - uLogger.debug("HTTP-status code [{}], raw server response: {}".format(response.status_code, response.text)) |
| 642 | + else: |
| 643 | + uLogger.debug("HTTP-status code [{}], raw server response: {}".format(response.status_code, response.text)) |
647 | 644 |
|
648 | | - responseJSON = self._ParseJSON(rawData=response.text) # parse response for errors |
649 | | - counter = self.retry + 1 # do not retry for 4xx errors |
| 645 | + responseJSON = self._ParseJSON(rawData=response.text) # parse response for errors |
| 646 | + counter = self.retry + 1 # do not retry for 4xx errors |
650 | 647 |
|
651 | | - # handling 5xx server errors: |
652 | | - if response and 500 <= response.status_code < 600: |
653 | | - bodyPreview = response.text[:256] + ("..." if len(response.text) > 256 else "") |
654 | | - errMsg = "status code: [{}], response body: {}".format(response.status_code, bodyPreview) |
| 648 | + # handling 5xx server errors: |
| 649 | + if response and 500 <= response.status_code < 600: |
| 650 | + bodyPreview = response.text[:256] + ("..." if len(response.text) > 256 else "") |
| 651 | + errMsg = "status code: [{}], response body: {}".format(response.status_code, bodyPreview) |
655 | 652 |
|
656 | | - uLogger.debug(" - not oK, {}".format(errMsg)) |
| 653 | + uLogger.debug(" - not oK, {}".format(errMsg)) |
657 | 654 |
|
658 | | - if "code" in response.text and "message" in response.text: |
659 | | - errMsgDict = self._ParseJSON(rawData=response.text) |
| 655 | + if "code" in response.text and "message" in response.text: |
| 656 | + errMsgDict = self._ParseJSON(rawData=response.text) |
660 | 657 |
|
661 | | - uLogger.debug("HTTP-status code [{}], error message: {}".format(response.status_code, errMsgDict.get("message", ""))) |
| 658 | + uLogger.debug("HTTP-status code [{}], error message: {}".format(response.status_code, errMsgDict.get("message", ""))) |
662 | 659 |
|
663 | | - else: |
664 | | - uLogger.debug("HTTP-status code [{}], raw server response: {}".format(response.status_code, response.text)) |
| 660 | + else: |
| 661 | + uLogger.debug("HTTP-status code [{}], raw server response: {}".format(response.status_code, response.text)) |
665 | 662 |
|
666 | | - responseJSON = self._ParseJSON(rawData=response.text) # parse response for errors |
667 | | - counter += 1 |
668 | | - response = None # clear response to allow retry |
| 663 | + responseJSON = self._ParseJSON(rawData=response.text) # parse response for errors |
| 664 | + counter += 1 |
| 665 | + response = None # clear response to allow retry |
669 | 666 |
|
670 | | - if counter <= self.retry: |
671 | | - uLogger.debug("Retry: [{}]. Wait {} sec. and try again...".format(counter, currentPause)) |
| 667 | + if counter <= self.retry: |
| 668 | + uLogger.debug("Retry: [{}]. Wait {} sec. and try again...".format(counter, currentPause)) |
672 | 669 |
|
673 | | - sleep(currentPause) |
| 670 | + sleep(currentPause) |
674 | 671 |
|
675 | | - currentPause = min(currentPause * 2, 60) # limit the maximum backoff to 60 seconds |
| 672 | + currentPause = min(currentPause * 2, 60) # limit the maximum backoff to 60 seconds |
676 | 673 |
|
677 | | - if response: |
678 | | - responseJSON = self._ParseJSON(rawData=response.text) |
| 674 | + if response: |
| 675 | + responseJSON = self._ParseJSON(rawData=response.text) |
679 | 676 |
|
680 | | - if errMsg: |
681 | | - uLogger.error("Server returns not `oK` status! See full debug log. Errors messages: https://tinkoff.github.io/investAPI/errors/") |
682 | | - uLogger.error(" - not oK, {}".format(errMsg)) |
| 677 | + if errMsg: |
| 678 | + uLogger.error("Server returns not `oK` status! See full debug log. Errors messages: https://tinkoff.github.io/investAPI/errors/") |
| 679 | + uLogger.error(" - not oK, {}".format(errMsg)) |
683 | 680 |
|
684 | 681 | return responseJSON |
685 | 682 |
|
|
0 commit comments