This has come up quite a lot lately and can probably improved significantly.
Currently, synchronous operations get a "lifetime" which contains the time created; the "lifetime" or duration of the operation is checked periodically and if it exceeds its timeout, the operation is cancelled. The first check happens after attempting to send the operation to the server and get a response. The problem is that this check can come much later than its timeout because the connection has a seperate SendTimeout, causing confusion (and overall slowness) if the connection is closed remotely (hung). This will make a timeout for an operation exceed its value and instead be tied to the greater SendTimeout value.
A way to handle this is by using a Timer object per operation and handling/removing the operation from the pending queue via callback when op times out. This should improve how timeouts work and improve perf when things go bad on the other end. A concern is the amount of overhead the timer per operation causes, so we'll have to do some profiling.