シナリオは次のとおりです。通信しているデバイスは、短期間でサーバーにコールバックした場合、接続されていると見なされます。このステータスを追跡する機能をカプセル化するクラスを作成したいと思います。デバイスへの呼び出し時に、タイムアウトをリセットする必要があります。コールバック時に接続が確認され、ステータスをtrueに設定する必要があります。コールバックがタイムアウトした場合は、falseに設定する必要があります。ただし、次の呼び出しでは、現在のステータスに関係なく、タイムアウトを再度リセットできるはずです。
私は、RXは、使用してこれを達成するために考えていたswith
とtimeout
。しかし、なぜそれが機能しなくなるのかわかりません。
public class ConnectionStatus
{
private Subject<bool> pending = new Subject<bool>();
private Subject<bool> connected = new Subject<bool>();
public bool IsConnected { get; private set; }
public ConnectionStatus(CancellationToken token, short timeoutSeconds = 15)
{
pending.Select(outer => connected.Timeout(TimeSpan.FromSeconds(timeoutSeconds)))
.Switch()
.Subscribe(_ => IsConnected = true, e => IsConnected = false, token);
}
public void ConfirmConnected()
{
connected.OnNext(true);
}
public void SetPending()
{
pending.OnNext(true);
}
}
これは「テストケース」です。
var c = new ConnectionStatus(default(CancellationToken));
c.SetPending();
await Task.Delay(TimeSpan.FromSeconds(5));
c.ConfirmConnected();
c.IsConnected.Dump(); // TRUE, OK
c.SetPending();
await Task.Delay(TimeSpan.FromSeconds(5));
c.ConfirmConnected();
c.IsConnected.Dump(); // TRUE, OK
c.SetPending();
await Task.Delay(TimeSpan.FromSeconds(20));
c.IsConnected.Dump(); // FALSE, OK
c.ConfirmConnected();
c.IsConnected.Dump(); // FALSE, OK
c.SetPending();
await Task.Delay(TimeSpan.FromSeconds(10));
c.ConfirmConnected();
c.IsConnected.Dump(); // FALSE, NOT OK!
内側のオブザーバブルのタイムアウトによって、外側のオブザーバブルも停止していると思います。outer =>
ラムダもはや呼び出されません。正しい方法は何ですか?
ありがとうございました
問題は、Timeout
本質的にRxサブスクリプションを爆破する例外を引き起こすことです。タイムアウトがトリガーされた後(コーディングしたとおり)、他の通知は送信されません。Rx文法では、*OnNext
メッセージの後に1つOnCompleted
または1つのメッセージを続けることができますOnError
。後OnError
からがTimeout
送信され、あなたはこれ以上のメッセージが表示されます。
OnNext
メッセージではなくメッセージを介してタイムアウトメッセージを配信する必要がありOnError
ます。古いコードでは、anyOnError
をfalseに、anyOnNext
をtrueに変換しました。代わりに、適切な新しいIsConnected
値をOnNext
メッセージに埋め込む必要があります。その方法は次のとおりです。
public ConnectionStatus(CancellationToken token, short timeoutSeconds = 15)
{
pending.Select(_ => connected
.Timeout(TimeSpan.FromSeconds(timeoutSeconds))
.Materialize()
.Select(n => n.Kind == NotificationKind.OnError && n.Exception.GetType() == typeof(TimeoutException)
? Notification.CreateOnNext(false)
: n)
.Dematerialize()
.Take(1)
)
.Switch()
.Subscribe(b => IsConnected = b, token);
}
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加