diff --git a/src/NATS.Client/KeyValue/IKeyValue.cs b/src/NATS.Client/KeyValue/IKeyValue.cs
index 47bb66534..9c2cfb632 100644
--- a/src/NATS.Client/KeyValue/IKeyValue.cs
+++ b/src/NATS.Client/KeyValue/IKeyValue.cs
@@ -102,6 +102,16 @@ public interface IKeyValue
///
KeyValueWatchSubscription Watch(string key, IKeyValueWatcher watcher, params KeyValueWatchOption[] watchOptions);
+ ///
+ /// Watch updates for a specific key, starting from a specific revision
+ ///
+ /// the key
+ /// the watcher
+ /// the revision to start from
+ /// the watch options to apply. If multiple conflicting options are supplied, the last options wins.
+ ///
+ KeyValueWatchSubscription Watch(string key, IKeyValueWatcher watcher, ulong fromRevision, params KeyValueWatchOption[] watchOptions);
+
///
/// Watch updates for all keys
///
@@ -110,6 +120,15 @@ public interface IKeyValue
/// The KeyValueWatchSubscription
KeyValueWatchSubscription WatchAll(IKeyValueWatcher watcher, params KeyValueWatchOption[] watchOptions);
+ ///
+ /// Watch updates for all keys, starting from a specific revision
+ ///
+ /// the watcher
+ /// the revision to start from
+ /// the watch options to apply. If multiple conflicting options are supplied, the last options wins.
+ /// The KeyValueWatchSubscription
+ KeyValueWatchSubscription WatchAll(IKeyValueWatcher watcher, ulong fromRevision, params KeyValueWatchOption[] watchOptions);
+
///
/// Get a list of the keys in a bucket.
///
diff --git a/src/NATS.Client/KeyValue/KeyValue.cs b/src/NATS.Client/KeyValue/KeyValue.cs
index 7554cfb08..2b3994b9c 100644
--- a/src/NATS.Client/KeyValue/KeyValue.cs
+++ b/src/NATS.Client/KeyValue/KeyValue.cs
@@ -153,13 +153,26 @@ public KeyValueWatchSubscription Watch(string key, IKeyValueWatcher watcher, par
{
Validator.ValidateKvKeyWildcardAllowedRequired(key);
Validator.ValidateNotNull(watcher, "Watcher is required");
- return new KeyValueWatchSubscription(this, key, watcher, watchOptions);
+ return new KeyValueWatchSubscription(this, key, watcher, ConsumerConfiguration.UlongUnset, watchOptions);
+ }
+
+ public KeyValueWatchSubscription Watch(string key, IKeyValueWatcher watcher, ulong fromRevision, params KeyValueWatchOption[] watchOptions)
+ {
+ Validator.ValidateKvKeyWildcardAllowedRequired(key);
+ Validator.ValidateNotNull(watcher, "Watcher is required");
+ return new KeyValueWatchSubscription(this, key, watcher, fromRevision, watchOptions);
}
public KeyValueWatchSubscription WatchAll(IKeyValueWatcher watcher, params KeyValueWatchOption[] watchOptions)
{
Validator.ValidateNotNull(watcher, "Watcher is required");
- return new KeyValueWatchSubscription(this, ">", watcher, watchOptions);
+ return new KeyValueWatchSubscription(this, ">", watcher, ConsumerConfiguration.UlongUnset, watchOptions);
+ }
+
+ public KeyValueWatchSubscription WatchAll(IKeyValueWatcher watcher, ulong fromRevision, params KeyValueWatchOption[] watchOptions)
+ {
+ Validator.ValidateNotNull(watcher, "Watcher is required");
+ return new KeyValueWatchSubscription(this, ">", watcher, fromRevision, watchOptions);
}
private PublishAck _write(string key, byte[] data, MsgHeader h) {
diff --git a/src/NATS.Client/KeyValue/KeyValueWatchOption.cs b/src/NATS.Client/KeyValue/KeyValueWatchOption.cs
index 359757e05..788cde052 100644
--- a/src/NATS.Client/KeyValue/KeyValueWatchOption.cs
+++ b/src/NATS.Client/KeyValue/KeyValueWatchOption.cs
@@ -22,7 +22,7 @@ public enum KeyValueWatchOption
IgnoreDelete,
///
- /// Only get meta data, skip value when retrieving data from the server.
+ /// Only get metadata, skip value when retrieving data from the server.
///
MetaOnly,
diff --git a/src/NATS.Client/KeyValue/KeyValueWatchSubscription.cs b/src/NATS.Client/KeyValue/KeyValueWatchSubscription.cs
index 82a8d25a9..2ca87edd2 100644
--- a/src/NATS.Client/KeyValue/KeyValueWatchSubscription.cs
+++ b/src/NATS.Client/KeyValue/KeyValueWatchSubscription.cs
@@ -24,7 +24,7 @@ public class KeyValueWatchSubscription : IDisposable
private readonly object subLock;
public KeyValueWatchSubscription(KeyValue kv, string keyPattern,
- IKeyValueWatcher watcher, params KeyValueWatchOption[] watchOptions)
+ IKeyValueWatcher watcher, ulong fromRevision, params KeyValueWatchOption[] watchOptions)
{
subLock = new object();
string subscribeSubject = kv.ReadSubject(keyPattern);
@@ -44,14 +44,23 @@ public KeyValueWatchSubscription(KeyValue kv, string keyPattern,
}
}
- if (deliverPolicy == DeliverPolicy.New || kv._getLast(subscribeSubject) == null)
+ if (fromRevision > 0)
{
- endOfDataSent = new InterlockedBoolean(true);
- watcher.EndOfData();
+ deliverPolicy = DeliverPolicy.ByStartSequence;
+ endOfDataSent = new InterlockedBoolean();
}
else
{
- endOfDataSent = new InterlockedBoolean(false);
+ fromRevision = ConsumerConfiguration.UlongUnset; // easier on the builder since we aren't starting at a fromRevision
+ if (deliverPolicy == DeliverPolicy.New || kv._getLast(subscribeSubject) == null)
+ {
+ endOfDataSent = new InterlockedBoolean(true);
+ watcher.EndOfData();
+ }
+ else
+ {
+ endOfDataSent = new InterlockedBoolean();
+ }
}
PushSubscribeOptions pso = PushSubscribeOptions.Builder()
@@ -61,12 +70,13 @@ public KeyValueWatchSubscription(KeyValue kv, string keyPattern,
ConsumerConfiguration.Builder()
.WithAckPolicy(AckPolicy.None)
.WithDeliverPolicy(deliverPolicy)
+ .WithStartSequence(fromRevision)
.WithHeadersOnly(headersOnly)
.WithFilterSubject(subscribeSubject)
.Build())
.Build();
- EventHandler handler = (sender, args) =>
+ void Handler(object sender, MsgHandlerEventArgs args)
{
KeyValueEntry kve = new KeyValueEntry(args.Message);
if (includeDeletes || kve.Operation.Equals(KeyValueOperation.Put))
@@ -79,9 +89,9 @@ public KeyValueWatchSubscription(KeyValue kv, string keyPattern,
endOfDataSent.Set(true);
watcher.EndOfData();
}
- };
+ }
- sub = kv.js.PushSubscribeAsync(subscribeSubject, handler, false, pso);
+ sub = kv.js.PushSubscribeAsync(subscribeSubject, Handler, false, pso);
if (endOfDataSent.IsFalse())
{
ulong pending = sub.GetConsumerInformation().CalculatedPending;
diff --git a/src/Tests/IntegrationTests/TestKeyValue.cs b/src/Tests/IntegrationTests/TestKeyValue.cs
index 41dce3c6f..ca21499f3 100644
--- a/src/Tests/IntegrationTests/TestKeyValue.cs
+++ b/src/Tests/IntegrationTests/TestKeyValue.cs
@@ -738,20 +738,24 @@ public void TestWatch()
string key1 = "key.1";
string key2 = "key.2";
- Object[] key1AllExpecteds = new Object[] {
+ object[] key1AllExpecteds = {
"a", "aa", KeyValueOperation.Delete, "aaa", KeyValueOperation.Delete, KeyValueOperation.Purge
};
+
+ object[] key1FromRevisionExpecteds = {
+ "aa", KeyValueOperation.Delete, "aaa"
+ };
- Object[] noExpecteds = new Object[0];
- Object[] purgeOnlyExpecteds = { KeyValueOperation.Purge };
+ object[] noExpecteds = Array.Empty