2017-10-10 4 views
1

私は特定のリモートマシンを監視する監視ツールのようなものを書いています。 マシンが稼動しているかどうか、IISがそこで実行されているかどうか、さらにいくつかのパラメータを取得します。
マシンのアップ/ダウン状態を3分ごとに監視できます。 IISの状態は〜1分ごとに監視できます。
これらのパラメータの一部が変更された場合、変更がログに記録されます(DistinctUntilChanged)。同じであれば何もしません。他のものがいくつかの値を出している間に観測可能なものを1つだけ放出する

私はマシンの状態とIISステータスのための1つの観測可能性を作成しました。 マシンがダウンしている場合は、他のリモートパラメータを監視する必要はありません(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!")); 

にはどうすればmachineStateObservableは、マシンがダウンしていることを示している間、それが通知を発しないであろう(その結果GetIisStateを呼び出すことはありません)というIisObservableを定義する必要がありますか?

更新:
ここでは、私が@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回ではなく1分ごとに呼び出す必要があります。 – IgorStack

+1

@IgorStack - はい、簡単です。Observable.Interval(TimeSpan.FromMinutes(1.0))ですべてを開始しますが、GetStateAsyncを呼び出して状態値を取得する可能性があります。 – Enigmativity

+0

@IgorStack - 私はあなたの答えを見ました。私は '.Select(...)'/'.Switch()'ではなく '.SelectMany'を使用します。スイッチアプローチでは値が得られないリスクがあります。 – Enigmativity

関連する問題