2017-10-10 65 views
1

我正在写一种监视指定远程机器的监视工具。 它会检索机器是否启动,IIS是否在那里运行以及一些参数。
机器的加/减状态可以监控,比如说3分钟。 并且IIS状态可以每〜1分钟监视一次。
如果其中一些参数发生变化,它将记录变化(DistinctUntilChanged),如果它保持不变,它将不会执行任何操作。发出一个observable只有当其他发出一些值

我为机器状态创建了一个observable,为IIS状态创建了一个observable。 显然,如果机器停机(无需拨打GetIisState),则无需监控任何其他远程参数。
所以,我试图使用SkipUntilTakeUntil - 尝试排序暂停IisObservable机器停机时。 但它不工作,因为我希望它。

这里是我的机器状态观察到:

machineStateObservable = Observable.Interval(TimeSpan.FromSeconds(180)) 
    .StartWith(-1) 
    .Select(async it => new {Order = it, State = await GetMachineStateAsync(machine)}) 
    .Switch() 
    .Do(it => 
    { 
     if (it.Order == -1) // write initial state 1st time 
     { 
      var state = it.State ? "up" : "down"; 
      var msg = $"{machine.Name}: Machine initial state: {state}"; 
      Log.Info(msg); 
     } 
    }) 
    .Select(it => it.State); 

machineStateObservable 
    .DistinctUntilChanged() 
    .Buffer(2, 1).Where(it => it.Count == 2) 
    .Subscribe(it => Log.Info($"{machine.Name}: MachineState got changed from {it[0]} to: {it[1]}") 
     , ex => Log.Error(ex, "Unhandled exception!")); 

我应该如何界定IisObservable,它不会发出通知(因此不会叫GetIisState),而machineStateObservable是表明机器是跌?

更新:
这是我来到与@Enigmativity的帮助解决方案:

IisStateObservable = MachineStateObservable 
       .Select(state => state 
        ? Observable.Interval(TimeSpan.FromSeconds(2)).StartWith(0) 
           .SelectMany(it => Readings.GetServiceStateAsync()) 
        : Observable.Never<string>()) 
       .Switch() 
       .Publish(); 
+0

调用'GetIisState'在哪里? – Enigmativity

+0

这是异步方法返回IIS状态 – IgorStack

回答

1

下面是创建一个可观察到的,只有当另一个可观测产生true发出的基本格局,而不是当它产生false

void Main() 
{ 
    var states = new Subject<bool>(); 

    IObservable<int> query = 
     states 
      .Select(state => state 
       ? Observable.FromAsync(() => GetStatusAsync()) 
       : Observable.Never<int>()) 
      .Switch(); 
} 

public async Task<int> GetStatusAsync() 
{ 
    return await Task.Factory.StartNew(() => 42); 
} 

下面的代码我建议定期调用。

void Main() 
{ 
    var states = new Subject<bool>(); 

    IObservable<int> query = 
    (
     from n in Observable.Interval(TimeSpan.FromMinutes(1.0)) 
     from ms in Observable.FromAsync(() => GetMachineStateAsync()) 
     select ms 
      ? Observable.FromAsync(() => GetStatusAsync()) 
      : Observable.Never<int>() 
    ).Switch(); 
} 

public async Task<int> GetStatusAsync() 
{ 
    return await Task.Factory.StartNew(() => 42); 
} 

public async Task<bool> GetMachineStateAsync() 
{ 
    return await Task.Factory.StartNew(() => true); 
} 

,或者,根据建议的答案。

void Main() 
{ 
    var states = new Subject<bool>(); 

    IObservable<int> query = 
     states 
      .Select(state => state 
       ? Observable 
        .Interval(TimeSpan.FromSeconds(2.0)) 
        .StartWith(-1L) 
        .SelectMany(n => 
         Observable.FromAsync(() => GetStatusAsync())) 
       : Observable.Never<int>()) 
      .Switch(); 
} 

public async Task<int> GetStatusAsync() 
{ 
    return await Task.Factory.StartNew(() => 42); 
} 
+0

这是很好的代码,我会用它。 但是,当机器启动时,我需要调用GetStatusAsync并继续每隔1分钟调用一次,而不是一次。 – IgorStack

+1

@IgorStack - 是的,这很简单 - 用'Observable.Interval(TimeSpan.FromMinutes(1.0))'开始整个事情,但是你可能会调用一个'GetStateAsync'来获取你的状态值。 – Enigmativity

+0

@IgorStack - 我看了你的答案。我会使用'.SelectMany'而不是'.Select(...)'/'.Switch()' - 你的风险不会在开关方法中获得任何价值。 – Enigmativity

相关问题