Uploaded image for project: 'Python Driver'
  1. Python Driver
  2. PYTHON-3291

[csot] Implement timeout error transformation

    • Type: Icon: Task Task
    • Resolution: Fixed
    • Priority: Icon: Unknown Unknown
    • 4.2
    • Affects Version/s: None
    • Component/s: None
    • Labels:
      None

      The CSOT spec requires timeout errors to be distinguished from other errors:

      If the timeoutMS option is set and the timeout expires, drivers MUST abort all blocking work and return control to the user with an error. This error MUST be distinguished in some way (e.g. custom exception type) to make it easier for users to detect when an operation fails due to a timeout. If the timeout expires during a blocking task, drivers MUST expose the underlying error returned from the task from this new error type. The stringified version of the new error type MUST include the stringified version of the underlying error as a substring. For example, if server selection expires and returns a ServerSelectionTimeoutException, drivers must allow users to access that exception from this new error type. If there is no underlying error, drivers MUST add information about when the timeout expiration was detected to the stringified version of the timeout error.

      One way to accomplish this would be via a new property on pymongo exceptions, eg (exc.is_timeout = True/False). Apps would need to catch all pymongo errors and check for a timeout like this:

      try:
          with pymongo.timeout(5):
              client.db.coll.insert_one({})
              time.sleep(5)
              # The deadline has now expired, the next operation will raise
              # a timeout exception.
              # Could raise ServerSelectionTimeoutError, ExecutionTimeout, WTimeoutError, NetworkTimeout, or ConnectionFailure.
              client.db.coll2.insert_one({})
      except PyMongoError as exc:
          if exc.is_timeout:
              print(f"block timed out: {exc!r}")
          else:
              print(f"non-timeout error occurred: {exc!r}")
      

      Another way would be to introduce a new error class TimeoutError which wraps the original error:

      try:
          with pymongo.timeout(5):
              client.db.coll.insert_one({})
              time.sleep(5)
              # The deadline has now expired, the next operation will raise
              # a timeout exception.
              client.db.coll2.insert_one({})
      except TimeoutError as exc:
          # Cause could be ServerSelectionTimeoutError, ExecutionTimeout, WTimeoutError, NetworkTimeout, or ConnectionFailure.
          orig_exc = exc.__cause__
          print(f"block timed out: {exc!r}")
      except PyMongoError as exc:
          print(f"non-timeout error occurred: {exc!r}")
      

            Assignee:
            shane.harvey@mongodb.com Shane Harvey
            Reporter:
            shane.harvey@mongodb.com Shane Harvey
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: