Undefined behavior for using WAMP features not agreed during feature negotiation
See original GitHub issueI have a client talking to a WAMP Basic Profile server (ran by a third party). This doesn’t support call cancellation so I think a call made like this:
# ...
async def call_endpoint(self, endpoint):
try:
resp = await self.call(endpoint, timeout=ENDPOINT_CALL_TIMEOUT_SECONDS * 1000)
except Exception as e: # TODO: Tighten this exception
print(f"Error calling {endpoint}: {e}")
raise
would ignore the timeout option and carry on running past the timeout?
I didn’t actually notice the timeout option on the call method on my first pass so just wrapped it in asyncio.wait_for
with a timeout like this:
# ...
async def call_endpoint(self, endpoint):
try:
resp = await asyncio.wait_for(self.call(endpoint), timeout=ENDPOINT_CALL_TIMEOUT_SECONDS)
except (asyncio.TimeoutError) as e:
print(f"Timeout calling {endpoint}: {e}")
except Exception as e: # TODO: Tighten this exception
print(f"Error calling {endpoint}: {e}")
raise
But that’s throwing the occasional bad_protocol error. I didn’t know what the exact issue is but our third party gave me access to the server logs which showed a 49 error code relating to the cancel call and it does always align with being thrown on the call after a 20s timed out call.
What’s the best way to handle timeouts in this situation? I don’t want to catch the bad_protocol exception as is in case the client or server changes in a way that this hides another issue. Can I at least see why the bad_protocol exception is being thrown in the exception somehow? I also don’t want to allow the client to block indefinitely on the server because we previously saw consistent failures where the client just hangs forever waiting for a response from the server that never arrives.
Should Autobahn be detecting this lack of support for call cancellation and just silently dropping the task if cancelled in this way? Or throw another exception in some way that can be handled?
I noticed https://github.com/crossbario/autobahn-python/issues/1127 but while I think there’s maybe some similarity in the reply in that issue I don’t really see the similarity in the opening post.
Issue Analytics
- State:
- Created 9 months ago
- Comments:9 (5 by maintainers)
O, thanks for description how it works under the hood
Well, I think both points are legitimate and just complement each other.
The client wants to cancel the call. It just issues
cancel()
. Maybe just wrapping it in try-catch. But what mean if cancel fails for client code? I think not much. After issuingcancel()
client just doesn’t care about results anymore. And that should work transparently for the client independently of what router is in use, do other peers supports call canceling or not. That’s the nature of WAMP: one peer doesn’t know much and actually doesn’t care much about other peers: where they are running and how. And call canceling is one of those features that can be implemented in aprogressive degradation
manner. So even if other peers do not support it we should handle that on our side. So for client, the logic remains the same for feature-rich router or basic one.What if the client issues call canceling, and we return an error as a feature not supported — okay. What’s then? Client still need to wait for the results? Or we will receive results sometime in the future and fail the whole connection because there is no related call? I think that’s not so convenient for end user and there is no reason to fail the whole connection.
I don’t know enough about WAMP/Autobahn to really weigh in here on your design discussion but I was curious about why I receive the error on the follow up call and not when the previous call is cancelled?
I’d expect to have something like this:
but it feels more like this: