Jacob Alber 392aa14491
fix: Add deferral to RegisterAgentType and (Add/Remove)Subscription (#5494)
Unlike with the InProcessRuntime, there is a two-phase initialization,
first when AgentsApp is built (when initial agents are registered) and
when it StartAsync()s and connects to the Gateway. Unfortunately, it is
possible to attempt to send direct RPC calls to the Gateway before the
message channel is opened; in this case, the Gateway has no connected
client corresponding to the RPC's clientId, and falls over.

The fix is to defer registering agents and subscriptions with the
gateway until after the connection is established after .StartAsync() is
called.
2025-02-11 16:03:02 -05:00

68 lines
2.0 KiB
C#

// Copyright (c) Microsoft Corporation. All rights reserved.
// FreePortManager.cs
using System.Diagnostics;
namespace Microsoft.AutoGen.Core.Grpc.Tests;
internal sealed class FreePortManager
{
private HashSet<int> takenPorts = new();
private readonly object mutex = new();
[DebuggerDisplay($"{{{nameof(Port)}}}")]
internal sealed class PortTicket(FreePortManager portManager, int port) : IDisposable
{
private FreePortManager? portManager = portManager;
public int Port { get; } = port;
public void Dispose()
{
FreePortManager? localPortManager = Interlocked.Exchange(ref this.portManager, null);
localPortManager?.takenPorts.Remove(this.Port);
}
public override string ToString()
{
return this.Port.ToString();
}
public override bool Equals(object? obj)
{
return obj is PortTicket ticket && ticket.Port == this.Port;
}
public override int GetHashCode()
{
return this.Port.GetHashCode();
}
public static implicit operator int(PortTicket ticket) => ticket.Port;
public static implicit operator string(PortTicket ticket) => ticket.ToString();
}
public PortTicket GetAvailablePort()
{
lock (mutex)
{
int port;
do
{
using var listener = new System.Net.Sockets.TcpListener(System.Net.IPAddress.Loopback, 0);
listener.Start();
port = ((System.Net.IPEndPoint)listener.LocalEndpoint).Port;
listener.Stop();
listener.Dispose();
Thread.Yield(); // Let the listener actually shut down before we try to use the port
} while (takenPorts.Contains(port));
takenPorts.Add(port);
Console.WriteLine($"FreePortManager: Yielding port {port}");
Debug.WriteLine($"FreePortManager: Yielding port {port}");
return new PortTicket(this, port);
}
}
}