C
C#•5mo ago
Pannekoekje

Async await in minimal API

Hey guys, I have a minimal API app which also hosts a client which has a websocket connection. The websocket gets in a disconnect state a lot so I reconnect if I can't get the data I want. However, it seems like the await for the reconnect isn't properly awaited, is there some special async/await mechanics in these minimal API routed calls? Code:
app.MapGet("/account", async Task<Results<Ok<AccountOverview>, NoContent>>
() =>
{
try
{
await _client.GetAccount();
}
catch
{
_client.Reconnect().Wait();
await _client.Authenticate();
await _client.GetAccount();
}
...
}
);
app.MapGet("/account", async Task<Results<Ok<AccountOverview>, NoContent>>
() =>
{
try
{
await _client.GetAccount();
}
catch
{
_client.Reconnect().Wait();
await _client.Authenticate();
await _client.GetAccount();
}
...
}
);
I've tried with both .Wait and await for the reconnect call.
31 Replies
Pannekoekje
Pannekoekje•5mo ago
Traceback:
mtreit
mtreit•5mo ago
I don't know anything about web sockets but you definitely should not be putting a synchronous Wait in there. What is the type of _client ?
Pannekoekje
Pannekoekje•5mo ago
I've tried both await and .Wait() 🙂 The _client is a client which I wrote myself, the reconnect logic for the websocket is as such:
public async Task Reconnect()
{
while (_websocket.State != WebSocketState.Open)
{
await Task.Delay(_reconnectDelay);
try
{
await OpenSocket();
}
catch
{
// Error opening socket, double delay and try again.
_reconnectDelay *= 2;
}
}

_reconnectDelay = 100;
}

private async Task OpenSocket()
{
try
{
_websocket = new ClientWebSocket();
await _websocket.ConnectAsync(new Uri(_WSUrl), _cancelToken);
}
catch (Exception exception)
{
throw new Exception($"Issue connecting to websocket, error {exception}");
}
}
public async Task Reconnect()
{
while (_websocket.State != WebSocketState.Open)
{
await Task.Delay(_reconnectDelay);
try
{
await OpenSocket();
}
catch
{
// Error opening socket, double delay and try again.
_reconnectDelay *= 2;
}
}

_reconnectDelay = 100;
}

private async Task OpenSocket()
{
try
{
_websocket = new ClientWebSocket();
await _websocket.ConnectAsync(new Uri(_WSUrl), _cancelToken);
}
catch (Exception exception)
{
throw new Exception($"Issue connecting to websocket, error {exception}");
}
}
mtreit
mtreit•5mo ago
Why aren't you using an off the shelf solution for web sockets?
Pannekoekje
Pannekoekje•5mo ago
it uses the off the shelf websocket
mtreit
mtreit•5mo ago
Also, those blind try-catch of any exception type without tracing out the exceptions seems like a bad idea.
Pannekoekje
Pannekoekje•5mo ago
The client is just a library for an API, the _client inside the lib is just a ClientWebSocket;
mtreit
mtreit•5mo ago
Also an unbounded exponential backoff is a bad idea. When do you dispose the existing _websocket instance? That's probably another bug.
Pannekoekje
Pannekoekje•5mo ago
but none of those are relevant for the question, no?
mtreit
mtreit•5mo ago
I don't know.
Pannekoekje
Pannekoekje•5mo ago
Like I said, the reconnect logic works in other places but I can't get it to work in the routed API call
mtreit
mtreit•5mo ago
Is it throwing an error? You didn't say what wasn't working.
Pannekoekje
Pannekoekje•5mo ago
Yes, can't paste it fully since its more than 2000 chars
mtreit
mtreit•5mo ago
$paste
MODiX
MODiX•5mo ago
If your code is too long, you can post to https://paste.mod.gg/ and copy the link into chat for others to see your shared code!
Pannekoekje
Pannekoekje•5mo ago
Thx 🙂 Ah then I can share the full stack trace, sec
Pannekoekje
Pannekoekje•5mo ago
BlazeBin - hkzedgtrzztu
A tool for sharing your source code with the world!
Pannekoekje
Pannekoekje•5mo ago
2nd link has the full stack trace if I recall correctly the behaviour is the same with both .Wait() and await
mtreit
mtreit•5mo ago
That exception is in the Authenticate call, which implies the Reconnect method already returned successfully.
Pannekoekje
Pannekoekje•5mo ago
which would mean the socket has been improperly closed between the 2 calls?
mtreit
mtreit•5mo ago
That part is unclear. I'm not sure if your Reconnect concept is valid if the remote server has terminated the connection. You might ask someone in #web to take a look at what you're doing because as I said I've never worked with web sockets. But I would probably start by making sure you correctly dispose of things, that you don't let your backoff delays get too high, that you properly set a KeepAlive value, add some tracing in the code to make sure you know exactly what exceptions are happening and where, etc. That should help eliminate possible issues and help track down why it's failing. I doubt it has anything to do with Minimal APIs but maybe there's something there I don't understand.
Pannekoekje
Pannekoekje•5mo ago
Hmm, I'll check the #web channel, the reconnect logic is working fine in other places like I said Thanks 🙂 !
mtreit
mtreit•5mo ago
Hmm, that didn't seem to elicit much of a response did it?
Pannekoekje
Pannekoekje•5mo ago
No it doesn't 😛 I'm logging the websocket state now in between the calls to see if it is actually open or not here is hoping it breaks 🙂 ofc it doesn't break when you're staring at it 🙂 I'll try again tomorrow, thx
mtreit
mtreit•5mo ago
Heisenbug
life grinder
life grinder•5mo ago
tbh it would be wise to create a small example to reproduce the issue it could help you too
Pannekoekje
Pannekoekje•4mo ago
Hmmm It seems the websocket state is still in "open" but it isn't ?
try
{
await _client.GetAccount();
}
catch
{
await LogAsync($"Failed, state: {_client.WebsocketState}");
await _client.Reconnect();
await LogAsync($"Reconnected, state: {_client.WebsocketState}");
await _client.Authenticate();
await _client.GetAccount();
}
try
{
await _client.GetAccount();
}
catch
{
await LogAsync($"Failed, state: {_client.WebsocketState}");
await _client.Reconnect();
await LogAsync($"Reconnected, state: {_client.WebsocketState}");
await _client.Authenticate();
await _client.GetAccount();
}
Gives
[02-14-2024 19:17:18.668226] Main Program - Failed, state: Open
[02-14-2024 19:17:18.668610] Main Program - Reconnected, state: Open
[02-14-2024 19:17:18.668226] Main Program - Failed, state: Open
[02-14-2024 19:17:18.668610] Main Program - Reconnected, state: Open
Pannekoekje
Pannekoekje•4mo ago
Stack Overflow
WebSocketException (0x80004005): The remote party closed the WebSoc...
I have a Xamarin app that communicates using WebSocket. On the client side, I am referencing the ClientWebSocket. code: using (var client = new ClientWebSocket() { Options = { KeepAliveInterval =...
Pannekoekje
Pannekoekje•4mo ago
Seems like it's half open; I'll just create an exception case for this. Wondering why this doesn't happen in the other reconnect logic however thinking about it, the other reconnect scenarios have very active websockets, this one can just be idle for hours on end. I'll fix this thx for thinking with me 🙂 !
life grinder
life grinder•4mo ago
maybe the other side is not fully adehering to the websocket standard? i've had issues like this
Pannekoekje
Pannekoekje•4mo ago
Their implementation seems quite fucky indeed, but its fine, I'll just check for this specific error: WebSocketError.ConnectionClosedPrematurely