C
C#3mo ago
Mehdi

SignalR Blocking Issue: Infinite Wait When Calling a Method from Client

Hello here is a Hub I implemented, the goal is to make a board game turn system, the most important part is in the method LaunchGame. I ask in the while loop two question "PiocheRequest" and "CoordRequest". The functions works well for the first 2 player in the loop. But at the third, the client send it successfully but the server is blocked and don't trigger PiocheResponse. What I tried: Using locks, mutexes because I think it's a threading problem but it didn't gave me a different result. Many thanks in advance,
5 Replies
Mehdi
Mehdi3mo ago
You have the full code of. my lobby if you want to try in local Here is how I call from client the methods in general: (Here PiocheRequest)
_connection.On<string, string>("PiocheRequest", async (request, requestId) =>
{
Console.WriteLine(request);
try{
var coords = Console.ReadLine();
var task = _connection.SendAsync("PiocheResponse", requestId, coords);
await task;
if(task.IsCompletedSuccessfully){
Console.WriteLine("Ok le message a ete envoye");
} else {
Console.WriteLine("On a des problemes a envoyer la tuile a piocher.");
}
} catch (Exception e){
throw;
}
});
_connection.On<string, string>("PiocheRequest", async (request, requestId) =>
{
Console.WriteLine(request);
try{
var coords = Console.ReadLine();
var task = _connection.SendAsync("PiocheResponse", requestId, coords);
await task;
if(task.IsCompletedSuccessfully){
Console.WriteLine("Ok le message a ete envoye");
} else {
Console.WriteLine("On a des problemes a envoyer la tuile a piocher.");
}
} catch (Exception e){
throw;
}
});
graph TD
A[Client] -->|Connects| B((OkeyHub))
B -->|Sends lobby list| C((Client))
C -->|Chooses lobby| B
B -->|Joins lobby| D((Room))
B -->|Starts game| E((Jeu))
E -->|Distributes tiles| B
B -->|Sends game start message| C
C -->|Receives game start message| A
E -->|Requests player turn| B
B -->|Requests tile discard coordinates| A
A -->|Sends coordinates| B
B -->|Processes discard| E
E -->|Requests tile draw choice| B
B -->|Requests tile draw choice| A
A -->|Sends draw choice| B
B -->|Processes draw choice| E
E -->|Checks game end| B
B -->|Continues game loop| E
E -->|Game ends| B
B -->|Sends game end message| C
C -->|Receives game end message| A
A -->|Disconnects| B
B -->|Handles disconnection| D
D -->|Updates room status| B
graph TD
A[Client] -->|Connects| B((OkeyHub))
B -->|Sends lobby list| C((Client))
C -->|Chooses lobby| B
B -->|Joins lobby| D((Room))
B -->|Starts game| E((Jeu))
E -->|Distributes tiles| B
B -->|Sends game start message| C
C -->|Receives game start message| A
E -->|Requests player turn| B
B -->|Requests tile discard coordinates| A
A -->|Sends coordinates| B
B -->|Processes discard| E
E -->|Requests tile draw choice| B
B -->|Requests tile draw choice| A
A -->|Sends draw choice| B
B -->|Processes draw choice| E
E -->|Checks game end| B
B -->|Continues game loop| E
E -->|Game ends| B
B -->|Sends game end message| C
C -->|Receives game end message| A
A -->|Disconnects| B
B -->|Handles disconnection| D
D -->|Updates room status| B
Here is a mermaid diagram of the logic I really need
Mehdi
Mehdi3mo ago
Ok, I did an update of my code, with advice of @TeBeCo I used a Singleton and DI approach so here is my code re-written: But I need to order the sendings of request to the client. I thought about a Queue is this a good approach ?
Mehdi
Mehdi3mo ago
Ok I have added the logic and at the third turn during my PiocheRequest the server is blocked:
Mehdi
Mehdi3mo ago
I don't understand why it's only happening at the third turn Ok I found the blocking issue:
public async Task<string> PiocheRequest(string connectionId)
{
var requestId = Guid.NewGuid().ToString();
var tcs = new TaskCompletionSource<string>();
await this._responsesLock.WaitAsync();
try
{
_responses[requestId] = tcs;
}
finally
{
this._responsesLock.Release();
}
await this._hubContext.Clients.Client(connectionId).SendAsync("PiocheRequest", "Veuillez choisir la tuile à piocher (Centre ou Defausse)", requestId);
await this._responsesLock.WaitAsync();
try
{
var response = await _responses[requestId].Task;
_responses.TryRemove(requestId, out _);
return response;
}
finally
{
this._responsesLock.Release();
}
}

public async Task PiocheResponse(string requestId, string response)
{
await this._responsesLock.WaitAsync();
try
{
if (_responses.TryGetValue(requestId, out var responseTask))
{
responseTask.SetResult(response);
}
}
finally
{
this._responsesLock.Release();
}

}
public async Task<string> PiocheRequest(string connectionId)
{
var requestId = Guid.NewGuid().ToString();
var tcs = new TaskCompletionSource<string>();
await this._responsesLock.WaitAsync();
try
{
_responses[requestId] = tcs;
}
finally
{
this._responsesLock.Release();
}
await this._hubContext.Clients.Client(connectionId).SendAsync("PiocheRequest", "Veuillez choisir la tuile à piocher (Centre ou Defausse)", requestId);
await this._responsesLock.WaitAsync();
try
{
var response = await _responses[requestId].Task;
_responses.TryRemove(requestId, out _);
return response;
}
finally
{
this._responsesLock.Release();
}
}

public async Task PiocheResponse(string requestId, string response)
{
await this._responsesLock.WaitAsync();
try
{
if (_responses.TryGetValue(requestId, out var responseTask))
{
responseTask.SetResult(response);
}
}
finally
{
this._responsesLock.Release();
}

}
I have a blocking problem here After the await this._hubContext.Clients.Client(connectionId).SendAsync("PiocheRequest", "Veuillez choisir la tuile à piocher (Centre ou Defausse)", requestId); it's blocking
Mehdi
Mehdi3mo ago
Here is my new code in a github repo: https://github.com/mehdi-arch/okeygameserver
GitHub
GitHub - mehdi-arch/okeygameserver
Contribute to mehdi-arch/okeygameserver development by creating an account on GitHub.