优化星尘工厂启动速度,获取本地进程名比较慢,平均200ms,有时候超过500ms

This commit is contained in:
大石头 2022-08-25 19:31:39 +08:00
parent c2fc53bc44
commit e84aee9481
8 changed files with 303 additions and 264 deletions

View File

@ -0,0 +1,15 @@
using Stardust.Models;
using Xunit;
namespace ClientTest;
public class AgentInfoTests
{
[Fact]
public void Test1()
{
var inf = AgentInfo.GetLocal(true);
Assert.NotNull(inf);
}
}

View File

@ -188,6 +188,7 @@ internal class MyService : ServiceBase, IServiceProvider
//var uri = new NetUri(set.LocalServer);
try
{
// 必须支持Udp因为需要支持局域网广播搜索功能
var svr = new ApiServer(set.LocalPort)
{
Tracer = _factory?.Tracer,

View File

@ -2,200 +2,211 @@
using NewLife;
using NewLife.Agent;
using NewLife.Log;
using NewLife.Model;
using NewLife.Net;
using NewLife.Remoting;
using NewLife.Serialization;
using NewLife.Threading;
using Stardust;
using Stardust.Managers;
using Stardust.Models;
using IHost = NewLife.Agent.IHost;
namespace StarAgent
namespace StarAgent;
[Api(null)]
public class StarService : IApi
{
[Api(null)]
public class StarService : IApi
#region
/// <summary>
/// 网络会话
/// </summary>
public IApiSession Session { get; set; }
/// <summary>服务对象</summary>
public ServiceBase Service { get; set; }
/// <summary>服务主机</summary>
public IHost Host { get; set; }
/// <summary>应用服务管理</summary>
public ServiceManager Manager { get; set; }
///// <summary>插件管理</summary>
//public PluginManager PluginManager { get; set; }
/// <summary>星尘设置</summary>
public StarSetting StarSetting { get; set; }
/// <summary>星尘代理设置</summary>
public Setting AgentSetting { get; set; }
private AgentInfo _agentInfo;
#endregion
#region
public StarService()
{
#region
/// <summary>
/// 网络会话
/// </summary>
public IApiSession Session { get; set; }
/// <summary>服务对象</summary>
public ServiceBase Service { get; set; }
/// <summary>服务主机</summary>
public IHost Host { get; set; }
/// <summary>应用服务管理</summary>
public ServiceManager Manager { get; set; }
///// <summary>插件管理</summary>
//public PluginManager PluginManager { get; set; }
/// <summary>星尘设置</summary>
public StarSetting StarSetting { get; set; }
/// <summary>星尘代理设置</summary>
public Setting AgentSetting { get; set; }
#endregion
#region
/// <summary>信息</summary>
/// <returns></returns>
[Api(nameof(Info))]
public AgentInfo Info(AgentInfo info)
// 获取本地进程名比较慢平均200ms有时候超过500ms
Task.Run(() =>
{
XTrace.WriteLine("Info<={0}", info.ToJson());
var set = StarSetting;
// 使用对方送过来的星尘服务端地址
if (set.Server.IsNullOrEmpty() && !info.Server.IsNullOrEmpty())
{
set.Server = info.Server;
set.Save();
XTrace.WriteLine("StarAgent使用应用[{0}]送过来的星尘服务端地址:{1}", info.ProcessName, info.Server);
if (Service is MyService svc)
{
ThreadPool.QueueUserWorkItem(s =>
{
svc.StartFactory();
svc.StartClient();
});
}
}
var ai = AgentInfo.GetLocal();
ai.Server = set.Server;
ai.Services = Manager?.Services.Select(e => e.Name).ToArray();
ai.Code = AgentSetting.Code;
return ai;
}
void CheckLocal()
{
if (Session is INetSession ns && !ns.Remote.Address.IsLocal()) throw new InvalidOperationException("禁止非本机操作!");
}
/// <summary>杀死并启动进程</summary>
/// <param name="processId">进程</param>
/// <param name="delay">延迟结束的秒数</param>
/// <param name="fileName">文件名</param>
/// <param name="arguments">参数</param>
/// <param name="workingDirectory">工作目录</param>
/// <returns></returns>
[Api(nameof(KillAndStart))]
public Object KillAndStart(Int32 processId, Int32 delay, String fileName, String arguments, String workingDirectory)
{
CheckLocal();
var p = Process.GetProcessById(processId);
if (p == null) throw new InvalidOperationException($"无效进程Id[{processId}]");
var name = p.ProcessName;
var pid = 0;
ThreadPool.QueueUserWorkItem(s =>
{
WriteLog("杀死进程 {0}/{1},等待 {2}秒", processId, p.ProcessName, delay);
if (delay > 0) Thread.Sleep(delay * 1000);
try
{
if (!p.HasExited)
{
p.Kill();
p.WaitForExit(5_000);
}
}
catch (Exception ex)
{
XTrace.WriteException(ex);
}
// 启动进程
if (!fileName.IsNullOrEmpty())
{
WriteLog("启动进程:{0} {1} {2}", fileName, arguments, workingDirectory);
var si = new ProcessStartInfo
{
FileName = fileName,
Arguments = arguments,
WorkingDirectory = workingDirectory,
// false时目前控制台合并到当前控制台一起退出
// true时目标控制台独立窗口不会一起退出
UseShellExecute = true,
};
var p2 = Process.Start(si);
pid = p2.Id;
WriteLog("应用[{0}]启动成功 PID={1}", p2.ProcessName, p2.Id);
}
});
return new { name, pid };
}
/// <summary>安装应用服务(星尘代理守护)</summary>
/// <param name="service"></param>
/// <returns></returns>
[Api(nameof(Install))]
public ProcessInfo Install(ServiceInfo service)
{
XTrace.WriteLine("Install<={0}", service.ToJson());
CheckLocal();
var rs = Manager.Install(service);
if (rs != null)
{
var set = Setting.Current;
set.Services = Manager.Services;
set.Save();
}
return rs;
}
/// <summary>卸载应用服务</summary>
/// <param name="serviceName"></param>
/// <returns></returns>
[Api(nameof(Uninstall))]
public Boolean Uninstall(String serviceName)
{
XTrace.WriteLine("Uninstall<={0}", serviceName);
CheckLocal();
var rs = Manager.Uninstall(serviceName, "ServiceUninstall");
if (rs)
{
var set = Setting.Current;
set.Services = Manager.Services;
set.Save();
}
return rs;
}
#endregion
#region
/// <summary>日志</summary>
public ILog Log { get; set; }
/// <summary>写日志</summary>
/// <param name="format"></param>
/// <param name="args"></param>
public void WriteLog(String format, params Object[] args) => Log?.Info(format, args);
#endregion
_agentInfo = AgentInfo.GetLocal(true);
});
}
#endregion
#region
/// <summary>信息</summary>
/// <returns></returns>
[Api(nameof(Info))]
public AgentInfo Info(AgentInfo info)
{
//using var span = Manager?.Tracer?.NewSpan("ApiInfo");
XTrace.WriteLine("Info<={0}", info.ToJson());
var set = StarSetting;
// 使用对方送过来的星尘服务端地址
if (set.Server.IsNullOrEmpty() && !info.Server.IsNullOrEmpty())
{
set.Server = info.Server;
set.Save();
XTrace.WriteLine("StarAgent使用应用[{0}]送过来的星尘服务端地址:{1}", info.ProcessId, info.Server);
if (Service is MyService svc)
{
ThreadPool.QueueUserWorkItem(s =>
{
svc.StartFactory();
svc.StartClient();
});
}
}
var ai = _agentInfo ??= AgentInfo.GetLocal(true);
ai.Server = set.Server;
ai.Services = Manager?.Services.Select(e => e.Name).ToArray();
ai.Code = AgentSetting.Code;
return ai;
}
private void CheckLocal()
{
if (Session is INetSession ns && !ns.Remote.Address.IsLocal()) throw new InvalidOperationException("禁止非本机操作!");
}
/// <summary>杀死并启动进程</summary>
/// <param name="processId">进程</param>
/// <param name="delay">延迟结束的秒数</param>
/// <param name="fileName">文件名</param>
/// <param name="arguments">参数</param>
/// <param name="workingDirectory">工作目录</param>
/// <returns></returns>
[Api(nameof(KillAndStart))]
public Object KillAndStart(Int32 processId, Int32 delay, String fileName, String arguments, String workingDirectory)
{
CheckLocal();
var p = Process.GetProcessById(processId);
if (p == null) throw new InvalidOperationException($"无效进程Id[{processId}]");
var name = p.ProcessName;
var pid = 0;
ThreadPool.QueueUserWorkItem(s =>
{
WriteLog("杀死进程 {0}/{1},等待 {2}秒", processId, p.ProcessName, delay);
if (delay > 0) Thread.Sleep(delay * 1000);
try
{
if (!p.HasExited)
{
p.Kill();
p.WaitForExit(5_000);
}
}
catch (Exception ex)
{
XTrace.WriteException(ex);
}
// 启动进程
if (!fileName.IsNullOrEmpty())
{
WriteLog("启动进程:{0} {1} {2}", fileName, arguments, workingDirectory);
var si = new ProcessStartInfo
{
FileName = fileName,
Arguments = arguments,
WorkingDirectory = workingDirectory,
// false时目前控制台合并到当前控制台一起退出
// true时目标控制台独立窗口不会一起退出
UseShellExecute = true,
};
var p2 = Process.Start(si);
pid = p2.Id;
WriteLog("应用[{0}]启动成功 PID={1}", p2.ProcessName, p2.Id);
}
});
return new { name, pid };
}
/// <summary>安装应用服务(星尘代理守护)</summary>
/// <param name="service"></param>
/// <returns></returns>
[Api(nameof(Install))]
public ProcessInfo Install(ServiceInfo service)
{
XTrace.WriteLine("Install<={0}", service.ToJson());
CheckLocal();
var rs = Manager.Install(service);
if (rs != null)
{
var set = Setting.Current;
set.Services = Manager.Services;
set.Save();
}
return rs;
}
/// <summary>卸载应用服务</summary>
/// <param name="serviceName"></param>
/// <returns></returns>
[Api(nameof(Uninstall))]
public Boolean Uninstall(String serviceName)
{
XTrace.WriteLine("Uninstall<={0}", serviceName);
CheckLocal();
var rs = Manager.Uninstall(serviceName, "ServiceUninstall");
if (rs)
{
var set = Setting.Current;
set.Services = Manager.Services;
set.Save();
}
return rs;
}
#endregion
#region
/// <summary>日志</summary>
public ILog Log { get; set; }
/// <summary>写日志</summary>
/// <param name="format"></param>
/// <param name="args"></param>
public void WriteLog(String format, params Object[] args) => Log?.Info(format, args);
#endregion
}

View File

@ -39,7 +39,6 @@
<Compile Include="..\StarAgent\Program.cs" Link="Program.cs" />
<Compile Include="..\StarAgent\Setting.cs" Link="Setting.cs" />
<Compile Include="..\StarAgent\StarService.cs" Link="StarService.cs" />
<Compile Include="..\StarAgent\StarService2.cs" Link="StarService2.cs" />
</ItemGroup>
<ItemGroup>

View File

@ -17,13 +17,13 @@ namespace Stardust;
public class LocalStarClient
{
#region
/// <summary>代理信息</summary>
/// <summary>本机代理信息</summary>
public AgentInfo Info { get; private set; }
/// <summary>本地服务端地址</summary>
public String Server { get => _local?.Server; set => _local.Server = value; }
public String Server { get; set; }
private readonly AgentInfo _local;
private AgentInfo _local;
private ApiClient _client;
#endregion
@ -31,8 +31,8 @@ public class LocalStarClient
/// <summary>实例化</summary>
public LocalStarClient()
{
_local = AgentInfo.GetLocal();
_local.Server = StarSetting.Current.Server;
//_local = AgentInfo.GetLocal();
//_local.Server = StarSetting.Current.Server;
}
#endregion
@ -49,14 +49,17 @@ public class LocalStarClient
var set = StarSetting.Current;
if (set.Debug) _client.EncoderLog = Log;
_local = AgentInfo.GetLocal(false);
_local.Server = !Server.IsNullOrEmpty() ? Server : StarSetting.Current.Server;
}
/// <summary>获取信息</summary>
/// <returns></returns>
public AgentInfo GetInfo()
{
var task = GetInfoAsync();
return task.Wait(1500) ? task.Result : null;
var task = Task.Run(GetInfoAsync);
return task.Wait(500) ? task.Result : null;
}
/// <summary>获取信息</summary>

View File

@ -59,6 +59,7 @@ internal class ServiceController : DisposeBase
if (Process != null) return false;
var service = Info;
if (service == null) return false;
// 修正路径
var workDir = service.WorkingDirectory;
@ -140,7 +141,7 @@ internal class ServiceController : DisposeBase
var p = Process;
if (p == null) return;
WriteLog("停止应用 PID={0}/{0} 原因:{2}", p.Id, p.ProcessName, reason);
WriteLog("停止应用 PID={0}/{1} 原因:{2}", p.Id, p.ProcessName, reason);
using var span = Tracer?.NewSpan("StopService", $"{Info.Name} reason={reason}");
try
@ -185,7 +186,7 @@ internal class ServiceController : DisposeBase
else
{
Process = null;
WriteLog("应用[{0}/{1}]已退出!", p.ProcessName, p.Id);
WriteLog("应用[{0}/{1}]已退出!", p.Id, Name);
}
}
@ -196,7 +197,7 @@ internal class ServiceController : DisposeBase
p = Process.GetProcessById(ProcessId);
if (p != null && !p.HasExited && p.ProcessName == ProcessName)
{
WriteLog("应用[{0}/{1}]已启动,直接接管", Name, p.Id);
WriteLog("应用[{0}/{1}]已启动,直接接管", p.Id, Name);
SetProcess(p);
if (Info != null && Info.ReloadOnChange) StartMonitor();

View File

@ -3,81 +3,89 @@ using System.Net;
using NewLife;
using NewLife.Reflection;
namespace Stardust.Models
namespace Stardust.Models;
/// <summary>代理信息</summary>
public class AgentInfo
{
/// <summary>代理信息</summary>
public class AgentInfo
#region
/// <summary>进程标识</summary>
public Int32 ProcessId { get; set; }
/// <summary>进程名称</summary>
public String ProcessName { get; set; }
/// <summary>版本</summary>
public String Version { get; set; }
/// <summary>文件路径</summary>
public String FileName { get; set; }
/// <summary>命令参数</summary>
public String Arguments { get; set; }
/// <summary>本地IP地址</summary>
public String IP { get; set; }
/// <summary>服务端地址</summary>
public String Server { get; set; }
/// <summary>节点编码</summary>
public String Code { get; set; }
/// <summary>应用服务</summary>
public String[] Services { get; set; }
#endregion
#region
/// <summary>
/// 获取本地信息
/// </summary>
/// <returns></returns>
public static AgentInfo GetLocal(Boolean full)
{
#region
/// <summary>进程标识</summary>
public Int32 ProcessId { get; set; }
var p = Process.GetCurrentProcess();
var asmx = AssemblyX.Entry;
var fileName = p.MainModule.FileName;
var args = Environment.CommandLine.TrimStart(Path.ChangeExtension(fileName, ".dll")).Trim();
//var ip = GetIps();
/// <summary>进程名称</summary>
public String ProcessName { get; set; }
/// <summary>版本</summary>
public String Version { get; set; }
/// <summary>文件路径</summary>
public String FileName { get; set; }
/// <summary>命令参数</summary>
public String Arguments { get; set; }
/// <summary>本地IP地址</summary>
public String IP { get; set; }
/// <summary>服务端地址</summary>
public String Server { get; set; }
/// <summary>节点编码</summary>
public String Code { get; set; }
/// <summary>应用服务</summary>
public String[] Services { get; set; }
#endregion
#region
/// <summary>
/// 获取本地信息
/// </summary>
/// <returns></returns>
public static AgentInfo GetLocal()
var inf = new AgentInfo
{
var p = Process.GetCurrentProcess();
var asmx = AssemblyX.Entry;
var fileName = p.MainModule.FileName;
var args = Environment.CommandLine.TrimStart(Path.ChangeExtension(fileName, ".dll")).Trim();
var ip = GetIps();
Version = asmx?.FileVersion,
ProcessId = p.Id,
// 获取本地进程名比较慢平均200ms有时候超过500ms
//ProcessName = p.ProcessName,
FileName = fileName,
Arguments = args,
//IP = ip,
};
return new AgentInfo
{
Version = asmx?.FileVersion,
ProcessId = p.Id,
ProcessName = p.ProcessName,
FileName = fileName,
Arguments = args,
IP = ip,
};
if (full)
{
inf.ProcessName = p.ProcessName;
inf.IP = GetIps();
}
/// <summary>
/// 获取本地IP地址
/// </summary>
/// <returns></returns>
public static String GetIps()
{
try
{
return NetHelper.GetIPsWithCache()
.Where(ip => ip.IsIPv4() && !IPAddress.IsLoopback(ip) && ip.GetAddressBytes()[0] != 169)
.Join();
}
catch
{
return null;
}
}
#endregion
return inf;
}
/// <summary>
/// 获取本地IP地址
/// </summary>
/// <returns></returns>
public static String GetIps()
{
try
{
return NetHelper.GetIPsWithCache()
.Where(ip => ip.IsIPv4() && !IPAddress.IsLoopback(ip) && ip.GetAddressBytes()[0] != 169)
.Join();
}
catch
{
return null;
}
}
#endregion
}

View File

@ -140,6 +140,7 @@ public class StarFactory : DisposeBase
// 借助本地StarAgent获取服务器地址
try
{
//XTrace.WriteLine("正在探测本机星尘代理……");
var inf = Local.GetInfo();
var server = inf?.Server;
if (!server.IsNullOrEmpty())