Skip to content

Commit 9ffbdf5

Browse files
committed
TS-38029 Rework Commons
1 parent 96549ce commit 9ffbdf5

6 files changed

+52
-25
lines changed

Commander.Server/ProfilerTestController.cs

+5-3
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,13 @@ namespace Cqse.Teamscale.Profiler.Commander.Server
1010
public class ProfilerTestController : ControllerBase
1111
{
1212
private readonly ProfilerIpc profilerIpc;
13+
private readonly ProfilerTestControllerState state;
1314
private readonly ILogger logger;
1415

15-
public ProfilerTestController(ProfilerIpc profilerIpc, ILogger<ProfilerTestController> logger)
16+
public ProfilerTestController(ProfilerIpc profilerIpc, ProfilerTestControllerState state, ILogger<ProfilerTestController> logger)
1617
{
1718
this.profilerIpc = profilerIpc;
19+
this.state = state;
1820
this.logger = logger;
1921
}
2022

@@ -26,7 +28,7 @@ public string GetCurrent()
2628

2729
public long GetStart()
2830
{
29-
return profilerIpc.TestStartMS;
31+
return state.TestStartMS;
3032
}
3133

3234
[HttpPost("start/{testName}")]
@@ -38,7 +40,7 @@ public HttpStatusCode StartTest(string testName)
3840
}
3941

4042
logger.LogInformation("Starting test: {}", testName);
41-
profilerIpc.TestStartMS = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
43+
state.TestStartMS = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
4244
profilerIpc.StartTest(HttpUtility.UrlDecode(testName));
4345
return HttpStatusCode.NoContent;
4446
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
namespace Cqse.Teamscale.Profiler.Commander.Server
2+
{
3+
/// <summary>
4+
/// As the controller is stateless, we store infos about the current test run in this state class.
5+
/// </summary>
6+
public class ProfilerTestControllerState
7+
{
8+
public long TestStartMS { get; set; } = 0;
9+
}
10+
}

Commander.Server/Program.cs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
using Cqse.Teamscale.Profiler.Commons.Ipc;
2+
using Cqse.Teamscale.Profiler.Commander.Server;
23

34
var builder = WebApplication.CreateBuilder(new WebApplicationOptions());
45
// explicitly initialize the Ipc, otherwise it might be created upon 1st request and we miss the start event in the profiler
5-
builder.Services.AddSingleton<ProfilerIpc>(new ProfilerIpc(new IpcConfig()));
6+
builder.Services.AddSingleton(new ProfilerIpc(new IpcConfig()));
7+
builder.Services.AddSingleton(new ProfilerTestControllerState());
68
builder.Services.AddControllers();
79

810
var app = builder.Build();

Commons/Ipc/ProfilerClient.cs

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using NetMQ.Sockets;
2+
3+
namespace Cqse.Teamscale.Profiler.Commons.Ipc
4+
{
5+
internal class ProfilerClient
6+
{
7+
ProfilerClient(string clientAddress, RequestSocket socket)
8+
{
9+
ClientAddress = clientAddress;
10+
Socket = socket;
11+
}
12+
13+
public string ClientAddress { get; }
14+
public RequestSocket Socket { get; }
15+
}
16+
}

Commons/Ipc/ProfilerIpc.cs

-2
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@ public class ProfilerIpc : IDisposable
1515
/// </summary>
1616
public string TestName { get; private set; } = String.Empty;
1717

18-
public long TestStartMS { get; set; } = 0;
19-
2018
public IpcConfig Config { get; }
2119

2220
public ProfilerIpc(IpcConfig config)

Commons/Ipc/ZmqIpcServer.cs

+18-19
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public class ZmqIpcServer : IDisposable
1616
private NetMQPoller? poller;
1717
private ResponseSocket? responseSocket;
1818

19-
private Dictionary<int, Tuple<string, RequestSocket>> clients = new Dictionary<int, Tuple<string, RequestSocket>>();
19+
private Dictionary<int, ProfilerClient> pidToClient = new Dictionary<int, ProfilerClient>();
2020

2121
private static readonly Logger logger = LogManager.GetCurrentClassLogger();
2222

@@ -58,24 +58,24 @@ protected void StartRequestHandler()
5858
poller.RunAsync("Profiler IPC", true);
5959
}
6060

61-
private void RegisterClient(string message)
61+
private void RegisterClient(string message)
6262
{
6363
int pid = Int32.Parse(message.Split(':')[1]);
64-
lock (clients)
64+
lock (pidToClient)
6565
{
6666
string clientAddress;
67-
if (clients.ContainsKey(pid))
67+
if (pidToClient.ContainsKey(pid))
6868
{
69-
clientAddress = clients[pid].Item1;
69+
clientAddress = pidToClient[pid].ClientAddress;
7070
responseSocket.SendFrame(clientAddress);
7171
return;
7272
}
73-
portOffset++;
7473
RequestSocket clientRequestSocket = new RequestSocket();
7574
clientAddress = config.RequestSocket + ":" + ((config.StartPortNumber + portOffset) % 65535);
75+
portOffset++;
7676
clientRequestSocket.Connect(clientAddress);
7777

78-
clients.Add(pid, Tuple.Create(clientAddress, clientRequestSocket));
78+
pidToClient.Add(pid, new ProfilerClient(clientAddress, clientRequestSocket));
7979
responseSocket.SendFrame(clientAddress);
8080
logger.Info($"Registered profiler on address {clientAddress}");
8181
}
@@ -84,34 +84,33 @@ private void RegisterClient(string message)
8484
/// <summary>
8585
/// Sends the given test event to all connected profiler instances.
8686
/// </summary>
87-
/// <param name="testEvent"></param>
8887
public void SendTestEvent(string testEvent)
8988
{
9089
HashSet<int> clientsToRemove = new HashSet<int>();
91-
System.Threading.Tasks.Parallel.ForEach(clients, entry =>
90+
System.Threading.Tasks.Parallel.ForEach(pidToClient, entry =>
9291
{
93-
entry.Value.Item2.SendFrame(Encoding.UTF8.GetBytes(testEvent));
94-
if (entry.Value.Item2.TryReceiveFrameString(TimeSpan.FromSeconds(3.0), out string? response))
92+
entry.Value.Socket.SendFrame(Encoding.UTF8.GetBytes(testEvent));
93+
if (entry.Value.Socket.TryReceiveFrameString(TimeSpan.FromSeconds(3.0), out string? response))
9594
{
96-
logger.Info($"Got Response from {entry.Value.Item1}: {response}");
95+
logger.Info($"Got Response from {entry.Value.ClientAddress}: {response}");
9796
} else
9897
{
9998
lock(clientsToRemove)
10099
{
101100
clientsToRemove.Add(entry.Key);
102101
}
103-
logger.Error($"Got no response from Profiler with Socket {entry.Key}");
102+
logger.Error($"Got no response from Profiler with PID {entry.Key} with address {entry.Value.ClientAddress}, removing from clients");
104103
}
105104
});
106-
lock (clients)
105+
lock (pidToClient)
107106
{
108107
foreach (var client in clientsToRemove)
109108
{
110-
if (!clients.ContainsKey(client)) {
109+
if (!pidToClient.ContainsKey(client)) {
111110
continue;
112111
}
113-
clients[client].Item2.Close();
114-
clients.Remove(client);
112+
pidToClient[client].Socket.Close();
113+
pidToClient.Remove(client);
115114
}
116115
}
117116
}
@@ -120,9 +119,9 @@ public void Dispose()
120119
{
121120
this.poller?.Dispose();
122121
this.responseSocket?.Dispose();
123-
foreach (var client in clients)
122+
foreach (var client in pidToClient)
124123
{
125-
client.Value.Item2.Dispose();
124+
client.Value.Socket.Dispose();
126125
}
127126
NetMQConfig.Cleanup(false);
128127
}

0 commit comments

Comments
 (0)