【问题标题】:.net remoting - Better solution to wait for a service to initialize ?.net 远程处理 - 等待服务初始化的更好解决方案?
【发布时间】:2014-06-02 10:35:14
【问题描述】:

上下文

我有一个客户端应用程序(我无法修改,即我只有二进制文件),它需要不时运行外部命令,这些命令依赖于初始化时间很长(大约 20 秒)的资源。

因此,我决定在“CommandServer.exe”应用程序(系统托盘中的单个实例)中一次性初始化此资源,并让我的客户端应用程序调用使用 .net 远程处理执行的中间“ExecuteCommand.exe”程序服务器上的操作。 “ExecuteCommand.exe”负责在第一次调用时启动服务器,然后让它保持活动状态以加速进一步的命令。

服务:

public interface IMyService
{
    void ExecuteCommand(string[] args);
}

“CommandServer.exe”(在资源初始化期间使用WindowsFormsApplicationBase 进行单实例管理 + 用户友好的启动画面):

private void onStartupFirstInstance(object sender, StartupEventArgs e)
{
    // Register communication channel
    channel = new TcpServerChannel("CommandServerChannel", 8234);
    ChannelServices.RegisterChannel(channel, false);

    // Register service
    var resource = veryLongToInitialize();
    service = new MyServiceImpl(resource);            
    RemotingServices.Marshal(service, "CommandServer");

    // Create icon in system tray
    notifyIcon = new NotifyIcon();
    ... 
}

中间“ExecuteCommand.exe”:

static void Main(string[] args)
{
    startCommandServerIfRequired();

    var channel = new TcpClientChannel();           
    ChannelServices.RegisterChannel(channel, false);

    var service = (IMyService)Activator.GetObject(typeof(IMyService), "tcp://localhost:8234/CommandServer");

    service.RunCommand(args);
}

问题

由于服务器启动时间很长(初始化所需资源大约需要 20 秒),“ExecuteCommand.exe”在 service.RunCommand(args) 行失败,因为服务器尚不可用。

问题

在调用service.RunCommand 时,有没有一种优雅的方法可以在接收“服务不可用”之前调整延迟?

NB1:目前我正在通过在服务器中添加一个互斥锁来指示完成初始化并让“ExecuteCommand.exe”在调用service.RunCommand之前等待这个互斥锁来解决这个问题。

NB2:我没有使用 .net 远程处理的背景,也没有推荐替换的 WCF。 (我选择了 .net 远程处理,因为这看起来更容易在运行外部命令时设置这个单次问题)。

【问题讨论】:

    标签: remoting


    【解决方案1】:

    找到了一个更好的解决方案,添加一些ManualResetEvent,而不是在应用程序之间共享Mutex:

    服务器:

    private void onStartupFirstInstance(object sender, StartupEventArgs e)
    {
        // Event to indicate when server is ready
        serverReadyEvent = new ManualResetEvent(false);
    
          // Register communication channel
          channel = new TcpServerChannel("CommandServerChannel", 8234);
          ChannelServices.RegisterChannel(channel, false);
    
          // Register service (even if not fully initialized)
          var resources = new ServiceResources();
          service = new MyServiceImpl(resources, serverReadyEvent);            
          RemotingServices.Marshal(service, "CommandServer");
    
          // Finalize service initialization
          resources.Initialize();
    
          // Create icon in system tray
          notifyIcon = new NotifyIcon();
          ...
    
        // Indicate server is now ready to process remote commands
        serverReadyEvent.Set();         
    }
    

    服务实现:

    class MyServiceImpl : MarshalByRefObject, IMyService
    {
        public MyServiceImpl(ServiceResources preAllocatedResources, ManualResetEvent serverReadyEvent)
        {
            this.resources = preAllocatedResources;
            this.serverReadyEvent = serverReadyEvent;    
        }
    
        public override object InitializeLifetimeService()
        {
            return null;
        }
    
        public void ExecuteCommand(string[] args)
        {
            if (!serverReadyEvent.WaitOne(20000))
            {
                throw new TimeoutException("Server did not initialized within expected delay.");
            }
    
            ...                       
        }
    
        private ManualResetEvent serverReadyEvent;
        private ServiceResources resources;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-05-05
      • 1970-01-01
      • 2012-03-31
      • 2016-07-27
      • 1970-01-01
      • 2011-12-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多