mirror of
https://github.com/immense/Remotely.git
synced 2025-10-26 11:27:15 +00:00
Adjust load tester. Made AddOrUpdateDevice async.
This commit is contained in:
parent
382a9a6c32
commit
934bf9a14a
@ -87,13 +87,13 @@ namespace Remotely.Server.Hubs
|
||||
}
|
||||
}
|
||||
|
||||
public Task<bool> DeviceCameOnline(Device device)
|
||||
public async Task<bool> DeviceCameOnline(Device device)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (CheckForDeviceBan(device.ID, device.DeviceName))
|
||||
{
|
||||
return Task.FromResult(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
var ip = Context.GetHttpContext()?.Connection?.RemoteIpAddress;
|
||||
@ -105,12 +105,13 @@ namespace Remotely.Server.Hubs
|
||||
|
||||
if (CheckForDeviceBan(device.PublicIP))
|
||||
{
|
||||
return Task.FromResult(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_dataService.AddOrUpdateDevice(device, out var updatedDevice))
|
||||
var result = await _dataService.AddOrUpdateDevice(device);
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
Device = updatedDevice;
|
||||
Device = result.Value;
|
||||
|
||||
_serviceSessionCache.AddOrUpdateByConnectionId(Context.ConnectionId, Device);
|
||||
|
||||
@ -124,14 +125,14 @@ namespace Remotely.Server.Hubs
|
||||
|
||||
foreach (var connection in connections)
|
||||
{
|
||||
connection.InvokeCircuitEvent(CircuitEventName.DeviceUpdate, Device);
|
||||
await connection.InvokeCircuitEvent(CircuitEventName.DeviceUpdate, Device);
|
||||
}
|
||||
return Task.FromResult(true);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Organization wasn't found.
|
||||
return Task.FromResult(false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -140,7 +141,7 @@ namespace Remotely.Server.Hubs
|
||||
}
|
||||
|
||||
Context.Abort();
|
||||
return Task.FromResult(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
public async Task DeviceHeartbeat(Device device)
|
||||
@ -163,8 +164,14 @@ namespace Remotely.Server.Hubs
|
||||
}
|
||||
|
||||
|
||||
_dataService.AddOrUpdateDevice(device, out var updatedDevice);
|
||||
Device = updatedDevice;
|
||||
var result = await _dataService.AddOrUpdateDevice(device);
|
||||
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Device = result.Value;
|
||||
|
||||
_serviceSessionCache.AddOrUpdateByConnectionId(Context.ConnectionId, Device);
|
||||
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using Immense.RemoteControl.Shared.Models;
|
||||
using Immense.RemoteControl.Shared;
|
||||
using Immense.RemoteControl.Shared.Models;
|
||||
using Microsoft.AspNetCore.Components.Forms;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
@ -29,7 +30,7 @@ namespace Remotely.Server.Services
|
||||
|
||||
InviteLink AddInvite(string orgID, InviteViewModel invite);
|
||||
|
||||
bool AddOrUpdateDevice(Device device, out Device updatedDevice);
|
||||
Task<Result<Device>> AddOrUpdateDevice(Device device);
|
||||
|
||||
Task AddOrUpdateSavedScript(SavedScript script, string userId);
|
||||
|
||||
@ -322,45 +323,44 @@ namespace Remotely.Server.Services
|
||||
return inviteLink;
|
||||
}
|
||||
|
||||
public bool AddOrUpdateDevice(Device device, out Device updatedDevice)
|
||||
public async Task<Result<Device>> AddOrUpdateDevice(Device device)
|
||||
{
|
||||
using var dbContext = _appDbFactory.GetContext();
|
||||
|
||||
var existingDevice = dbContext.Devices.Find(device.ID);
|
||||
if (existingDevice != null)
|
||||
var resultDevice = await dbContext.Devices.FindAsync(device.ID);
|
||||
if (resultDevice != null)
|
||||
{
|
||||
existingDevice.CurrentUser = device.CurrentUser;
|
||||
existingDevice.DeviceName = device.DeviceName;
|
||||
existingDevice.Drives = device.Drives;
|
||||
existingDevice.CpuUtilization = device.CpuUtilization;
|
||||
existingDevice.UsedMemory = device.UsedMemory;
|
||||
existingDevice.UsedStorage = device.UsedStorage;
|
||||
existingDevice.Is64Bit = device.Is64Bit;
|
||||
existingDevice.IsOnline = true;
|
||||
existingDevice.OSArchitecture = device.OSArchitecture;
|
||||
existingDevice.OSDescription = device.OSDescription;
|
||||
existingDevice.Platform = device.Platform;
|
||||
existingDevice.ProcessorCount = device.ProcessorCount;
|
||||
existingDevice.PublicIP = device.PublicIP;
|
||||
existingDevice.TotalMemory = device.TotalMemory;
|
||||
existingDevice.TotalStorage = device.TotalStorage;
|
||||
existingDevice.AgentVersion = device.AgentVersion;
|
||||
existingDevice.LastOnline = DateTimeOffset.Now;
|
||||
updatedDevice = existingDevice;
|
||||
resultDevice.CurrentUser = device.CurrentUser;
|
||||
resultDevice.DeviceName = device.DeviceName;
|
||||
resultDevice.Drives = device.Drives;
|
||||
resultDevice.CpuUtilization = device.CpuUtilization;
|
||||
resultDevice.UsedMemory = device.UsedMemory;
|
||||
resultDevice.UsedStorage = device.UsedStorage;
|
||||
resultDevice.Is64Bit = device.Is64Bit;
|
||||
resultDevice.IsOnline = true;
|
||||
resultDevice.OSArchitecture = device.OSArchitecture;
|
||||
resultDevice.OSDescription = device.OSDescription;
|
||||
resultDevice.Platform = device.Platform;
|
||||
resultDevice.ProcessorCount = device.ProcessorCount;
|
||||
resultDevice.PublicIP = device.PublicIP;
|
||||
resultDevice.TotalMemory = device.TotalMemory;
|
||||
resultDevice.TotalStorage = device.TotalStorage;
|
||||
resultDevice.AgentVersion = device.AgentVersion;
|
||||
resultDevice.LastOnline = DateTimeOffset.Now;
|
||||
}
|
||||
else
|
||||
{
|
||||
device.LastOnline = DateTimeOffset.Now;
|
||||
if (_hostEnvironment.IsDevelopment() && dbContext.Organizations.Any())
|
||||
{
|
||||
var org = dbContext.Organizations.FirstOrDefault();
|
||||
var org = await dbContext.Organizations.FirstOrDefaultAsync();
|
||||
device.Organization = org;
|
||||
device.OrganizationID = org?.ID;
|
||||
}
|
||||
|
||||
updatedDevice = device;
|
||||
resultDevice = device;
|
||||
|
||||
if (!dbContext.Organizations.Any(x => x.ID == device.OrganizationID))
|
||||
if (!await dbContext.Organizations.AnyAsync(x => x.ID == device.OrganizationID))
|
||||
{
|
||||
_logger.LogInformation(
|
||||
"Unable to add device {deviceName} because organization {organizationID}" +
|
||||
@ -369,12 +369,12 @@ namespace Remotely.Server.Services
|
||||
device.OrganizationID,
|
||||
device.ID);
|
||||
|
||||
return false;
|
||||
return Result.Fail<Device>("Organization does not exist.");
|
||||
}
|
||||
dbContext.Devices.Add(device);
|
||||
await dbContext.Devices.AddAsync(device);
|
||||
}
|
||||
dbContext.SaveChanges();
|
||||
return true;
|
||||
await dbContext.SaveChangesAsync();
|
||||
return Result.Ok(resultDevice);
|
||||
}
|
||||
|
||||
public async Task AddOrUpdateSavedScript(SavedScript script, string userId)
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using Castle.Core.Logging;
|
||||
using Microsoft.AspNetCore.Http.Connections;
|
||||
using Microsoft.AspNetCore.SignalR.Client;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Moq;
|
||||
@ -6,85 +7,93 @@ using Remotely.Agent.Services;
|
||||
using Remotely.Agent.Services.Windows;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Remotely.Tests.LoadTester
|
||||
namespace Remotely.Tests.LoadTester;
|
||||
|
||||
internal class Program
|
||||
{
|
||||
internal class Program
|
||||
private static readonly double _heartbeatMs = TimeSpan.FromMinutes(1).TotalMilliseconds;
|
||||
private static int _agentCount;
|
||||
private static string _organizationId;
|
||||
private static string _serverurl;
|
||||
private static Mock<ICpuUtilizationSampler> _cpuSampler;
|
||||
private static Mock<ILogger<DeviceInfoGeneratorWin>> _logger;
|
||||
private static DeviceInfoGeneratorWin _deviceInfo;
|
||||
private static Stopwatch _stopwatch;
|
||||
private static int _connectedCount;
|
||||
|
||||
private static void Main(string[] args)
|
||||
{
|
||||
private static readonly SemaphoreSlim _lock = new(10, 10);
|
||||
private static readonly double _heartbeatMs = TimeSpan.FromMinutes(1).TotalMilliseconds;
|
||||
private static int _agentCount;
|
||||
private static string _organizationId;
|
||||
private static string _serverurl;
|
||||
private static Mock<ICpuUtilizationSampler> _cpuSampler;
|
||||
private static Mock<ILogger<DeviceInfoGeneratorWin>> _logger;
|
||||
private static DeviceInfoGeneratorWin _deviceInfo;
|
||||
_cpuSampler = new Mock<ICpuUtilizationSampler>();
|
||||
_cpuSampler.Setup(x => x.CurrentUtilization).Returns(0);
|
||||
_logger = new Mock<ILogger<DeviceInfoGeneratorWin>>();
|
||||
|
||||
private static void Main(string[] args)
|
||||
_deviceInfo = new DeviceInfoGeneratorWin(_cpuSampler.Object, _logger.Object);
|
||||
|
||||
_stopwatch = Stopwatch.StartNew();
|
||||
ConnectAgents();
|
||||
|
||||
Console.Write("Press Enter to exit...");
|
||||
Console.ReadLine();
|
||||
}
|
||||
|
||||
private static void ConnectAgents()
|
||||
{
|
||||
try
|
||||
{
|
||||
_cpuSampler = new Mock<ICpuUtilizationSampler>();
|
||||
_cpuSampler.Setup(x => x.CurrentUtilization).Returns(0);
|
||||
_logger = new Mock<ILogger<DeviceInfoGeneratorWin>>();
|
||||
|
||||
_deviceInfo = new DeviceInfoGeneratorWin(_cpuSampler.Object, _logger.Object);
|
||||
ConnectAgents();
|
||||
|
||||
Console.Write("Press Enter to exit...");
|
||||
Console.ReadLine();
|
||||
}
|
||||
|
||||
private static void ConnectAgents()
|
||||
{
|
||||
try
|
||||
if (!CommandLineParser.CommandLineArgs.ContainsKey("serverurl") ||
|
||||
!CommandLineParser.CommandLineArgs.ContainsKey("organizationid") ||
|
||||
!CommandLineParser.CommandLineArgs.ContainsKey("agentcount"))
|
||||
{
|
||||
if (!CommandLineParser.CommandLineArgs.ContainsKey("serverurl") ||
|
||||
!CommandLineParser.CommandLineArgs.ContainsKey("organizationid") ||
|
||||
!CommandLineParser.CommandLineArgs.ContainsKey("agentcount"))
|
||||
{
|
||||
Console.WriteLine("Command line arguments must include all of the following: ");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("-serverurl [full URL of the Remotely server]");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("-organizationid [organization ID that the device will belong to]");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("-agentcount [the number of agent connections to simulate]");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Press Enter to exit...");
|
||||
Environment.Exit(0);
|
||||
}
|
||||
|
||||
_agentCount = int.Parse(CommandLineParser.CommandLineArgs["agentcount"]);
|
||||
_organizationId = CommandLineParser.CommandLineArgs["organizationid"];
|
||||
_serverurl = CommandLineParser.CommandLineArgs["serverurl"];
|
||||
|
||||
for (var i = 0; i < _agentCount; i++)
|
||||
{
|
||||
_ = StartAgent(i);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("An error occurred. Check your syntex. Error: ");
|
||||
Console.WriteLine("Command line arguments must include all of the following: ");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine(ex.Message);
|
||||
Console.WriteLine("-serverurl [full URL of the Remotely server]");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("-organizationid [organization ID that the device will belong to]");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("-agentcount [the number of agent connections to simulate]");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Press Enter to exit...");
|
||||
Environment.Exit(0);
|
||||
}
|
||||
|
||||
_agentCount = int.Parse(CommandLineParser.CommandLineArgs["agentcount"]);
|
||||
_organizationId = CommandLineParser.CommandLineArgs["organizationid"];
|
||||
_serverurl = CommandLineParser.CommandLineArgs["serverurl"];
|
||||
|
||||
for (var i = 0; i < _agentCount; i++)
|
||||
{
|
||||
_ = StartAgent(i);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("An error occurred. Check your syntex. Error: ");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task StartAgent(int i)
|
||||
private static async Task StartAgent(int i)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
await _lock.WaitAsync();
|
||||
var waitSeconds = Math.Max(3, Random.Shared.NextDouble() * 10);
|
||||
await Task.Delay(TimeSpan.FromSeconds(waitSeconds));
|
||||
|
||||
var deviceId = Guid.NewGuid().ToString();
|
||||
|
||||
var hubConnection = new HubConnectionBuilder()
|
||||
.WithUrl(_serverurl + "/hubs/service")
|
||||
.WithAutomaticReconnect(new RetryPolicy())
|
||||
.Build();
|
||||
|
||||
Console.WriteLine("Connecting device number " + i.ToString());
|
||||
Console.WriteLine($"Connecting device number {i}");
|
||||
await hubConnection.StartAsync();
|
||||
|
||||
var device = await _deviceInfo.CreateDevice(deviceId, _organizationId);
|
||||
@ -98,29 +107,47 @@ namespace Remotely.Tests.LoadTester
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
await Task.Delay(new Random().Next(1, (int)_heartbeatMs));
|
||||
var heartbeatTimer = new System.Timers.Timer(_heartbeatMs);
|
||||
heartbeatTimer.Elapsed += async (sender, args) =>
|
||||
{
|
||||
var currentInfo = await _deviceInfo.CreateDevice(device.ID, _organizationId);
|
||||
currentInfo.DeviceName = device.DeviceName;
|
||||
await hubConnection.SendAsync("DeviceHeartbeat", currentInfo);
|
||||
try
|
||||
{
|
||||
var currentInfo = await _deviceInfo.CreateDevice(device.ID, _organizationId);
|
||||
currentInfo.DeviceName = device.DeviceName;
|
||||
await hubConnection.SendAsync("DeviceHeartbeat", currentInfo);
|
||||
}
|
||||
catch { }
|
||||
};
|
||||
heartbeatTimer.Start();
|
||||
});
|
||||
|
||||
Console.WriteLine($"Connected device number {i}");
|
||||
|
||||
Interlocked.Increment(ref _connectedCount);
|
||||
if (_connectedCount == _agentCount)
|
||||
{
|
||||
Console.WriteLine($"Finished connecting all devices. Elapsed: {_stopwatch.Elapsed}");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Device {i} failed to connect.");
|
||||
Console.WriteLine(ex.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_lock.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class RetryPolicy : IRetryPolicy
|
||||
{
|
||||
public TimeSpan? NextRetryDelay(RetryContext retryContext)
|
||||
{
|
||||
return TimeSpan.FromSeconds(3);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -29,7 +29,7 @@ namespace Remotely.Tests
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void AddOrUpdateDevice()
|
||||
public async Task AddOrUpdateDevice()
|
||||
{
|
||||
var storedDevice = _dataService.GetDevice(_newDeviceID);
|
||||
|
||||
@ -43,7 +43,8 @@ namespace Remotely.Tests
|
||||
Is64Bit = Environment.Is64BitOperatingSystem
|
||||
};
|
||||
|
||||
Assert.IsTrue(_dataService.AddOrUpdateDevice(newDevice, out _));
|
||||
var result = await _dataService.AddOrUpdateDevice(newDevice);
|
||||
Assert.IsTrue(result.IsSuccess);
|
||||
|
||||
storedDevice = _dataService.GetDevice(_newDeviceID);
|
||||
|
||||
|
||||
@ -94,9 +94,9 @@ namespace Remotely.Tests
|
||||
User2 = dataService.GetUserByNameWithOrg("testuser2@test.com");
|
||||
|
||||
Device1.OrganizationID = Admin1.OrganizationID;
|
||||
dataService.AddOrUpdateDevice(Device1, out _);
|
||||
await dataService.AddOrUpdateDevice(Device1); ;
|
||||
Device2.OrganizationID = Admin1.OrganizationID;
|
||||
dataService.AddOrUpdateDevice(Device2, out _);
|
||||
await dataService.AddOrUpdateDevice(Device2);
|
||||
|
||||
dataService.AddDeviceGroup(Admin1.OrganizationID, Group1, out _, out _);
|
||||
dataService.AddDeviceGroup(Admin1.OrganizationID, Group2, out _, out _);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user