Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Client Results #783

Merged
merged 8 commits into from
Jun 7, 2024
Merged

Client Results #783

merged 8 commits into from
Jun 7, 2024

Conversation

mayuki
Copy link
Member

@mayuki mayuki commented Jun 7, 2024

This PR adds a feature called "Client results," which allows the server to invoke client methods and receive results.

"Client results" is inspired by a feature of the same name implemented in SignalR. This enables invoking a particular client's method from the server's Hub or application logic and receiving results.

interface IMyHub : IStreamingHub<IMyHub, IMyHubReceiver>
{
}

interface IMyHubReveiver
{
    // The Client results method is defined in the Receiver with a return type of Task or Task<T>
    Task<string> HelloAsync(string name, int age);

    // Regular broadcast method
    void OnMessage(string message);
}

// Client implementation
class MyHubReceiver : IMyHubReceiver
{
    public async Task<string> HelloAsync(string name, int age)
    {
        Console.WriteLine($"Hello from {name} ({age})");
        var result = await ReadInputAsync();
        return result;
    }
    public void OnMessage()
    {
        Console.WriteLine($"OnMessage: {message}");
    }
}

On the server, method calls can be made through Client or Single of the group, and the result can be received.

var result = await Client.HelloAsync();
Console.WriteLine(result);
// or
var result2 = await _group.Single(clientId).HelloAsync();
Console.WriteLine(result2);

Exceptions

If an error occurs on the client, an RpcException is thrown to the caller, and if the connection is disconnected or a timeout occurs, a TaskCanceledException (OperationCanceledException) is thrown.

Timeout

The timeout for server-to-client calls is 5 seconds by default. If the timeout is exceeded, a TaskCanceledException (OperationCanceledException) is thrown to the caller. The default timeout can be set via the MagicOnionOptions.ClientResultsDefaultTimeout property.

To explicitly override the timeout per method call, specify a CancellationToken as a method argument and pass in the CancellationToken to timeout at any desired timing. Note that this cancellation does not propagate to the client; the client always receives default(CancellationToken).

interface IMyHubReceiver
{
    Task<string> DoLongWorkAsync(CancellationToken timeoutCancellationToken = default);
}
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));
var result = await Client.DoLongWorkAsync(cts.Token);
Console.WriteLine(result);

Limitations

  • Invoking calls to multiple clients is not supported. You must use either Client or Single.
  • Client results are not supported when Redis or NAT is used as the group's backplane.
  • If invoking a Hub method while a Client results method is called on the client side, it will cause a deadlock.

@mayuki mayuki merged commit 32655b8 into vNext Jun 7, 2024
3 checks passed
@mayuki mayuki deleted the feature/ClientResult branch June 7, 2024 03:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant