如何连续不断地听变化提要RethinkDB

时间:2018-08-12 19:33:38

标签: c# system.reactive rethinkdb

我遇到以下问题:使用RethinkDB的{​​{1}}方法运行一次,当使用时,它开始侦听给定查询的更改。查询更改时,将为您提供RunChangesAsync,它是初始状态和实际状态之间的增量。

我的问题是如何使它连续运行?

如果我使用:

Cursor<Change<Class>>

如果我在代码中指出的地方发生了更改,则while(true) { code.... //changes happening while program is here ....../ ...RunChangesAsync(); /......processed buffered items code //new changes here } 不会捕获它们。只有RunChanges正在侦听时才能捕获到的更改。在检索结果之前或之后。

因此,我尝试将RunChanges包装在RunChanges中,但是它没有像我期望的那样连续监听变化...它只是检索2个空项目(我想是垃圾)并结束。

可观察

observable

观察者

public  IObservable<Cursor<Change<UserStatus?>>> GetObservable() =>
    r.Db(Constants.DB_NAME).Table(Constants.CLIENT_TABLE).RunChangesAsync<UserStatus?>(this.con,CancellationToken.None).ToObservable();

程序

class PlayerSubscriber : IObserver<Cursor<Change<UserStatus?>>>
{
    public void OnCompleted() => Console.WriteLine("Finished");
    public void OnError(Exception error) => Console.WriteLine("error");
    public void OnNext(Cursor<Change<UserStatus?>> value)
    {
        foreach (var item in value.BufferedItems)
            Console.WriteLine(item);
    }
}

如您所见,在调试时,class Program { public static RethinkDB r = RethinkDB.R; public static bool End = false; static async Task Main(string[] args) { var address = new Address { Host = "127.0.0.1", Port = 28015 }; var con = await r.Connection().Hostname(address.Host).Port(address.Port).ConnectAsync(); var database = new Database(r, con); var obs = database.GetObservable(); var sub = new PlayerSubscriber(); var disp = obs.Subscribe(sub); Console.ReadKey(); Console.WriteLine("Hello World!"); } } 的{​​{1}}方法仅执行一次(返回两个空对象),然后关闭。

enter image description here

P.S:OnNext只是rethinkdb查询的包装器。唯一使用的方法是我发布的ObserverDatabaseGetObservable

2 个答案:

答案 0 :(得分:1)

如果您的操作具有签名Task<int> ReadAsync(),则设置轮询的方式如下:

IObservable<int> PollRead(TimeSpan interval)
{
    return
        Observable
            .Interval(interval)
            .SelectMany(n => Observable.FromAsync(() => ReadAsync()));
}

对于您创建自己的IObservable<T>实现,我也要格外注意-充满危险。如果要创建自己的观察者,则应使用Observer.Create(...)。通常,您甚至都不这样做。

答案 1 :(得分:1)

创建更改供稿时,您需要创建 一个 更改供稿对象。例如,当您运行Cursor<Change<T>>后返回.RunChangesAsync();时,这确实是您所需要的。

cursor返回的query.RunChangesAsync()对象是您的变更供稿对象,将在您要接收更改的整个生命周期中使用。

在您的示例中:

while(true)
{
 code....   //changes happening while program is here
....../
...RunChangesAsync();
/......processed buffered items
code   //new changes here
}

.RunChangesAsync();循环中包含while是不正确的方法。您无需再次重新运行查询并获得另一个Cursor<Change<T>>。我将在本文结尾处解释其工作原理。

此外,请勿在{{1​​}}对象上使用cursor.BufferedItems。游标上的cursor属性并不意味着代码会直接使用它; cursor.BufferedItems属性仅在您要在游标对象(客户端)中“窥视”特定于变更源查询的准备使用的项目的特殊情况下公开。

消费变更供稿中项目的正确方法是枚举cursor.BufferedItems对象本身,如下所示:

cursor

var cursor = await query.RunChangesAsync(conn); foreach (var item in cursor){ Console.WriteLine(item); } 的项目用完时,它将向 RethinkDB 服务器请求更多的项目。请记住,cursor循环的每次迭代都可能是阻塞调用。例如,当 1)客户端上没有要消费的项目(foreach 2)时,foreach循环会无限期阻塞服务器上没有根据您的更改供稿查询条件更改的项目。在这种情况下,.BufferedItems.Count == 0循环将一直阻塞,直到 RethinkDB 服务器向您发送准备使用的商品为止。

Documentation about using Reactive Extensions and RethinkDB in C#

有一个驱动程序单元测试,显示了.NET Reactive Extensions如何工作here

具体来说,Lines 31 - 47 in this unit test使用“响应式扩展程序”设置了更改供稿:

foreach

另外,here is a good example and explanation发生了什么以及如何使用C#消耗变更供稿:

希望有帮助。

谢谢,
布莱恩