public async Task BasicCriteriaTest() { using (var store = GetDocumentStore()) using (var subscriptionManager = new DocumentSubscriptions(store)) { await CreateDocuments(store, 1); var lastEtag = store.GetLastWrittenEtag() ?? 0; await CreateDocuments(store, 5); var subscriptionCriteria = new SubscriptionCriteria { Collection = "Things", FilterJavaScript = " return this.Name == 'ThingNo3'", }; var subsId = subscriptionManager.Create(subscriptionCriteria, lastEtag); using (var subscription = subscriptionManager.Open <Thing>(new SubscriptionConnectionOptions() { SubscriptionId = subsId })) { var list = new BlockingCollection <Thing>(); subscription.Subscribe(x => { list.Add(x); }); await subscription.StartAsync(); Thing thing; Assert.True(list.TryTake(out thing, 5000)); Assert.Equal("ThingNo3", thing.Name); Assert.False(list.TryTake(out thing, 50)); } } }
public long CreateSubscription(SubscriptionCriteria criteria) { long id = -1; using (Database.IdentityLock.Lock()) { Database.TransactionalStorage.Batch(accessor => { id = accessor.General.GetNextIdentityValue(Constants.RavenSubscriptionsPrefix); try { if (criteria.StartEtag == null || criteria.StartEtag == Etag.Empty) { TryFigureOutFirstEtagForSubscription(criteria); } } catch (Exception e) { Log.InfoException("Could not figure out start etag for subscription automatically", e); } var config = new SubscriptionConfig { SubscriptionId = id, Criteria = criteria, AckEtag = criteria.StartEtag ?? Etag.Empty, }; SaveSubscriptionConfig(id, config); }); } return(id); }
public async Task CreateSubscriptions() { var store = GetDocumentStore(); var subscriptionCriteria = new SubscriptionCriteria { Collection = "People", }; var subsId = await store.AsyncSubscriptions.CreateAsync(subscriptionCriteria); var subscriptionCriteria2 = new SubscriptionCriteria { Collection = "Users", }; var subsId2 = await store.AsyncSubscriptions.CreateAsync(subscriptionCriteria2); var subscriptionsConfig = await store.AsyncSubscriptions.GetSubscriptionsAsync(0, 10); Assert.Equal(2, subscriptionsConfig.Count); Assert.Equal(subscriptionCriteria.Collection, subscriptionsConfig[0].Criteria.Collection); Assert.Equal(subscriptionCriteria2.FilterJavaScript, subscriptionsConfig[1].Criteria.FilterJavaScript); Assert.Equal(0, subscriptionsConfig[0].AckEtag); Assert.Equal(subsId2, subscriptionsConfig[1].SubscriptionId); // TODO fix delete handler on server side /*await store.AsyncSubscriptions.DeleteAsync(subsId); * subscriptionsConfig = await store.AsyncSubscriptions.GetSubscriptionsAsync(0, 10); * Assert.Equal(1, subscriptionsConfig.Count);*/ }
/// <summary> /// Create a new filter within the node. This filter can be used to poll for new messages that match the set of criteria /// </summary> /// <param name="filters">Message filters</param> /// <param name="ctoken">cancellation token</param> /// <returns>filter identifier</returns> public async Task <string> CreateNewMessageFilter(SubscriptionCriteria filters, CancellationToken ctoken) { JArray jarrayObj = new JArray(); var outObject = (JObject)JToken.FromObject(filters); jarrayObj.Add(outObject); return(await BuildAndSendRequest("shh_newMessageFilter", jarrayObj, string.Empty, ctoken)); }
private SubscriptionPatchDocument SetupFilterScript(SubscriptionCriteria criteria) { SubscriptionPatchDocument patch = null; if (string.IsNullOrWhiteSpace(criteria.FilterJavaScript) == false) { patch = new SubscriptionPatchDocument(TcpConnection.DocumentDatabase, criteria.FilterJavaScript); } return(patch); }
/// <summary> /// Creates and registers a new subscription to receive notifications for inbound whisper messages. /// Returns the ID of the newly created subscription. /// Either symKeyID or privateKeyID must be present. Can not be both /// </summary> /// <param name="filters">message filters</param> /// <param name="id">identifier of function call. In case of Whisper must contain the value "messages" /// This might be the case in some very rare cases, e.g. if you intend to communicate to MailServers, etc</param> /// <param name="ctoken">cancellation token</param> /// <returns>subscription id</returns> public async Task <string> Subscribe(SubscriptionCriteria filters, CancellationToken ctoken, string id = "messages") { JArray jarrayObj = new JArray(); jarrayObj.Add(id); var outObject = (JObject)JToken.FromObject(filters); jarrayObj.Add(outObject); return(await BuildAndSendRequest("shh_subscribe", jarrayObj, string.Empty, ctoken)); }
private void TryFigureOutFirstEtagForSubscription(SubscriptionCriteria criteria) { if (criteria.KeyStartsWith != null || criteria.BelongsToAnyCollection == null || criteria.BelongsToAnyCollection.Length == 0) { return; } if (!Database.IndexStorage.HasIndex(Constants.DocumentsByEntityNameIndex)) { return; } var indexDefinition = Database.IndexStorage.GetIndexInstance(Constants.DocumentsByEntityNameIndex); var lastEtag = indexDefinition.GetLastEtagFromStats(); var results = Database.Queries.Query(Constants.DocumentsByEntityNameIndex, new IndexQuery { SortedFields = new[] { new SortedField("LastModifiedTicks") }, Query = string.Join(" OR ", criteria.BelongsToAnyCollection.Select(collection => " Tag:[[" + collection + "]] ")), PageSize = 128 }, CancellationToken.None); var indexTimestamp = results.IndexTimestamp; if (results.Results.Count == 0) { criteria.StartEtag = lastEtag; return; } foreach (var document in results.Results) { var metadata = document.Value <RavenJObject>(Constants.Metadata); var lastModified = metadata.Value <DateTime>(Constants.RavenLastModified); if (lastModified > indexTimestamp) { continue; } var earliestEtag = new Etag(metadata.Value <string>("@etag")); if (earliestEtag.Changes > 0) { criteria.StartEtag = earliestEtag.DecrementBy(1); } return; } }
private static bool MatchCriteria(SubscriptionCriteria criteria, JsonDocument doc) { if (criteria.BelongsToAnyCollection != null && criteria.BelongsToAnyCollection.Contains(doc.Metadata.Value <string>(Constants.RavenEntityName), StringComparer.InvariantCultureIgnoreCase) == false) { return(false); } if (criteria.KeyStartsWith != null && doc.Key.StartsWith(criteria.KeyStartsWith) == false) { return(false); } if (criteria.PropertiesMatch != null) { foreach (var match in criteria.PropertiesMatch) { var tokens = doc.DataAsJson.SelectTokenWithRavenSyntaxReturningFlatStructure(match.Key).Select(x => x.Item1).ToArray(); foreach (var curVal in tokens) { if (RavenJToken.DeepEquals(curVal, match.Value) == false) { return(false); } } if (tokens.Length == 0) { return(false); } } } if (criteria.PropertiesNotMatch != null) { foreach (var match in criteria.PropertiesNotMatch) { var tokens = doc.DataAsJson.SelectTokenWithRavenSyntaxReturningFlatStructure(match.Key).Select(x => x.Item1).ToArray(); foreach (var curVal in tokens) { if (RavenJToken.DeepEquals(curVal, match.Value) == true) { return(false); } } } } return(true); }
private static bool MatchCriteria(SubscriptionCriteria criteria, JsonDocument doc) { if (criteria.BelongsToAnyCollection != null && criteria.BelongsToAnyCollection.Contains(doc.Metadata.Value <string>(Constants.RavenEntityName), StringComparer.InvariantCultureIgnoreCase) == false) { return(false); } if (criteria.KeyStartsWith != null && doc.Key.StartsWith(criteria.KeyStartsWith) == false) { return(false); } if (criteria.PropertiesMatch != null) { foreach (var match in criteria.PropertiesMatch) { var value = doc.DataAsJson.SelectToken(match.Key); if (value == null) { return(false); } if (RavenJToken.DeepEquals(value, match.Value) == false) { return(false); } } } if (criteria.PropertiesNotMatch != null) { foreach (var notMatch in criteria.PropertiesNotMatch) { var value = doc.DataAsJson.SelectToken(notMatch.Key); if (value != null) { if (RavenJToken.DeepEquals(value, notMatch.Value)) { return(false); } } } } return(true); }
public async Task BasicSusbscriptionTest() { using (var store = GetDocumentStore()) { await CreateDocuments(store, 1); var lastEtag = store.GetLastWrittenEtag() ?? 0; await CreateDocuments(store, 5); var subscriptionCriteria = new SubscriptionCriteria { Collection = "Things", }; var subsId = await store.AsyncSubscriptions.CreateAsync(subscriptionCriteria, lastEtag); using (var subscription = store.AsyncSubscriptions.Open <Thing>(new SubscriptionConnectionOptions { SubscriptionId = subsId })) { var bc = new BlockingCollection <Thing>(); subscription.Subscribe(x => { bc.Add(x); }); await subscription.StartAsync(); Thing thing; for (var i = 0; i < 5; i++) { Assert.True(bc.TryTake(out thing, 1000)); } Assert.False(bc.TryTake(out thing, 50)); for (var j = 0; j < 2; j++) { await CreateDocuments(store, 1); Assert.True(bc.TryTake(out thing, 500)); Assert.False(bc.TryTake(out thing, 50)); } } } }
public Task <long> CreateAsync <T>(SubscriptionCriteria <T> criteria, long startEtag = 0, string database = null) { if (criteria == null) { throw new InvalidOperationException("Cannot create a subscription if criteria is null"); } var nonGenericCriteria = new SubscriptionCriteria { Collection = documentStore.Conventions.GetTypeTagName(typeof(T)), FilterJavaScript = criteria.FilterJavaScript }; return(CreateAsync(nonGenericCriteria, startEtag, database)); }
public Task <long> CreateAsync <T>(SubscriptionCriteria <T> criteria, string database = null) { if (criteria == null) { throw new InvalidOperationException("Cannot create a subscription if criteria is null"); } var nonGenericCriteria = new SubscriptionCriteria(); nonGenericCriteria.BelongsToAnyCollection = new [] { documentStore.Conventions.GetTypeTagName(typeof(T)) }; nonGenericCriteria.KeyStartsWith = criteria.KeyStartsWith; nonGenericCriteria.PropertiesMatch = criteria.GetPropertiesMatchStrings(); nonGenericCriteria.PropertiesNotMatch = criteria.GetPropertiesNotMatchStrings(); return(CreateAsync(nonGenericCriteria, database)); }
private IDisposable RegisterForNotificationOnNewDocuments(SubscriptionCriteria criteria) { _waitForMoreDocuments = new AsyncManualResetEvent(CancellationTokenSource.Token); Action <DocumentChangeNotification> registerNotification = notification => { if (notification.CollectionName == criteria.Collection) { _waitForMoreDocuments.SetByAsyncCompletion(); } }; TcpConnection.DocumentDatabase.Notifications.OnDocumentChange += registerNotification; return(new DisposableAction(() => { TcpConnection.DocumentDatabase.Notifications.OnDocumentChange -= registerNotification; })); }
public async Task <long> CreateAsync(SubscriptionCriteria criteria, string database = null) { if (criteria == null) { throw new InvalidOperationException("Cannot create a subscription if criteria is null"); } var commands = database == null ? documentStore.AsyncDatabaseCommands : documentStore.AsyncDatabaseCommands.ForDatabase(database); using (var request = commands.CreateRequest("/subscriptions/create", "POST")) { await request.WriteAsync(RavenJObject.FromObject(criteria)).ConfigureAwait(false); return(request.ReadResponseJson().Value <long>("Id")); } }
public async Task CreateSubscription() { using (var store = GetDocumentStore()) { var subscriptionCriteria = new SubscriptionCriteria { Collection = "People", }; var subsId = await store.AsyncSubscriptions.CreateAsync(subscriptionCriteria); var subscriptionsConfig = await store.AsyncSubscriptions.GetSubscriptionsAsync(0, 10); Assert.Equal(1, subscriptionsConfig.Count); Assert.Equal(subscriptionCriteria.Collection, subscriptionsConfig[0].Criteria.Collection); Assert.Equal(subscriptionCriteria.FilterJavaScript, subscriptionsConfig[0].Criteria.FilterJavaScript); Assert.Equal(0, subscriptionsConfig[0].AckEtag); Assert.Equal(subsId, subscriptionsConfig[0].SubscriptionId); } }
public async Task BasicSusbscriptionTest() { var store = GetDocumentStore(); await CreateDocuments(store, 1); long lastEtag; using (var session = store.OpenAsyncSession()) { var thing = await session.LoadAsync <Thing>("things/1"); lastEtag = session.Advanced.GetEtagFor(thing) ?? 0; } await CreateDocuments(store, 5); var subscriptionCriteria = new SubscriptionCriteria { Collection = "Things", }; var subsId = await store.AsyncSubscriptions.CreateAsync(subscriptionCriteria, lastEtag); using (var subscription = store.AsyncSubscriptions.Open <Thing>(new SubscriptionConnectionOptions() { SubscriptionId = subsId })) { var list = new BlockingCollection <Thing>(); subscription.Subscribe(x => { list.Add(x); }); await subscription.StartAsync(); Thing thing; for (var i = 0; i < 5; i++) { Assert.True(list.TryTake(out thing, 1000)); } Assert.False(list.TryTake(out thing, 50)); } }
public long CreateSubscription(SubscriptionCriteria criteria) { long id = -1; Database.TransactionalStorage.Batch(accessor => { id = accessor.General.GetNextIdentityValue(Constants.RavenSubscriptionsPrefix); var config = new SubscriptionConfig { SubscriptionId = id, Criteria = criteria, AckEtag = Etag.Empty }; SaveSubscriptionConfig(id, config); }); return(id); }
public async Task <long> CreateAsync(SubscriptionCriteria criteria, long startEtag = 0, string database = null) { if (criteria == null) { throw new InvalidOperationException("Cannot create a subscription if criteria is null"); } JsonOperationContext jsonOperationContext; var requestExecuter = documentStore.GetRequestExecuter(database ?? documentStore.DefaultDatabase); requestExecuter.ContextPool.AllocateOperationContext(out jsonOperationContext); var command = new CreateSubscriptionCommand() { Context = jsonOperationContext, Criteria = criteria, StartEtag = startEtag }; await requestExecuter.ExecuteAsync(command, jsonOperationContext); return(command.Result.Id); }
public long Create <T>(SubscriptionCriteria <T> criteria, string database = null) { return(innerAsync.CreateAsync(criteria, database).ResultUnwrap()); }
public async Task StronglyTypedDataSubscriptions() { using (var store = GetDocumentStore()) { using (var session = store.OpenAsyncSession()) { for (int i = 0; i < 5; i++) { await session.StoreAsync(new PersonWithAddress() { Name = "James", Address = new Address() { ZipCode = 12345 } }); await session.StoreAsync(new PersonWithAddress() { Name = "James", Address = new Address() { ZipCode = 54321 } }); await session.StoreAsync(new PersonWithAddress() { Name = "David", Address = new Address() { ZipCode = 12345 } }); await session.StoreAsync(new Person()); } await session.SaveChangesAsync(); } var criteria = new SubscriptionCriteria <PersonWithAddress> { FilterJavaScript = "return this.Name == 'James' && this.Address.ZipCode != 54321" }; var id = await store.AsyncSubscriptions.CreateAsync(criteria); using ( var subscription = store.AsyncSubscriptions.Open <PersonWithAddress>(new SubscriptionConnectionOptions { SubscriptionId = id })) { var users = new BlockingCollection <PersonWithAddress>(); subscription.Subscribe(users.Add); await subscription.StartAsync(); PersonWithAddress userToTake; for (var i = 0; i < 5; i++) { Assert.True(users.TryTake(out userToTake, 50000)); Assert.Equal("James", userToTake.Name); Assert.Equal(12345, userToTake.Address.ZipCode); } Assert.False(users.TryTake(out userToTake, 50)); } } }
public void FullBackupToOneZipFile() { var tempFileName = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); Directory.CreateDirectory(tempFileName); using (var database = CreateDocumentDatabase()) { var context = DocumentsOperationContext.ShortTermSingleUse(database); var subscriptionCriteria = new SubscriptionCriteria { Collection = "Users", }; var obj = RavenJObject.FromObject(subscriptionCriteria); var objString = obj.ToString(Formatting.None); var stream = new MemoryStream(); var streamWriter = new StreamWriter(stream); streamWriter.Write(objString); streamWriter.Flush(); stream.Position = 0; var reader = context.Read(stream, "docs/1"); database.SubscriptionStorage.CreateSubscription(reader); database.IndexStore.CreateIndex(new IndexDefinition() { Name = "Users_ByName", Maps = { "from user in docs.Users select new { user.Name }" }, Type = IndexType.Map }); database.IndexStore.CreateIndex(new IndexDefinition() { Name = "Users_ByName2", Maps = { "from user in docs.Users select new { user.Name }" }, Type = IndexType.Map }); using (var tx = context.OpenWriteTransaction()) { var doc2 = CreateDocument(context, "users/2", new DynamicJsonValue { ["Name"] = "Edward", [Constants.Metadata.Key] = new DynamicJsonValue { [Constants.Headers.RavenEntityName] = "Users" } }); database.DocumentsStorage.Put(context, "users/2", null, doc2); tx.Commit(); } database.SubscriptionStorage.Environment().Options.ManualFlushing = true; database.SubscriptionStorage.Environment().FlushLogToDataFile(); foreach (var index in database.IndexStore.GetIndexes()) { index._indexStorage.Environment().Options.ManualFlushing = true; index._indexStorage.Environment().FlushLogToDataFile(); } database.DocumentsStorage.Environment.Options.ManualFlushing = true; database.DocumentsStorage.Environment.FlushLogToDataFile(); database.FullBackupTo(Path.Combine(tempFileName, "backup-test.backup")); BackupMethods.Full.Restore(Path.Combine(tempFileName, "backup-test.backup"), Path.Combine(tempFileName, "backup-test.data")); } using (var database = CreateDocumentDatabase(runInMemory: false, dataDirectory: Path.Combine(tempFileName, "backup-test.data"))) { var context = DocumentsOperationContext.ShortTermSingleUse(database); using (var tx = context.OpenReadTransaction()) { Assert.NotNull(database.DocumentsStorage.Get(context, "users/2")); Assert.Equal(database.IndexStore.GetIndex(1).Name, "Users_ByName"); Assert.Equal(database.IndexStore.GetIndex(2).Name, "Users_ByName2"); Assert.Equal(database.SubscriptionStorage.GetAllSubscriptionsCount(), 1); } } }
public unsafe void GetCriteriaAndEtag(long id, DocumentsOperationContext context, out SubscriptionCriteria criteria, out long startEtag) { var transactionPersistentContext = new TransactionPersistentContext(); using (var tx = _environment.ReadTransaction(transactionPersistentContext)) { var config = GetSubscriptionConfig(id, tx); int criteriaSize; var criteriaPtr = config.Read(SubscriptionSchema.SubscriptionTable.CriteriaIndex, out criteriaSize); var criteriaBlittable = new BlittableJsonReaderObject(criteriaPtr, criteriaSize, context); criteria = JsonDeserializationServer.SubscriptionCriteria(criteriaBlittable); startEtag = *(long *)config.Read(SubscriptionSchema.SubscriptionTable.AckEtagIndex, out criteriaSize); } }
public async Task SubscriptionStrategyConnectIfFree() { using (var store = GetDocumentStore()) { await CreateDocuments(store, 1); long lastEtag; using (var session = store.OpenAsyncSession()) { var thing = await session.LoadAsync <Thing>("things/1"); lastEtag = session.Advanced.GetEtagFor(thing) ?? 0; } await CreateDocuments(store, 5); var subscriptionCriteria = new SubscriptionCriteria { Collection = "Things", }; var subsId = await store.AsyncSubscriptions.CreateAsync(subscriptionCriteria, lastEtag); using ( var acceptedSubscription = store.AsyncSubscriptions.Open <Thing>(new SubscriptionConnectionOptions() { SubscriptionId = subsId, TimeToWaitBeforeConnectionRetryMilliseconds = 10000 })) { var acceptedSusbscriptionList = new BlockingCollection <Thing>(); acceptedSubscription.Subscribe(x => { acceptedSusbscriptionList.Add(x); }); await acceptedSubscription.StartAsync(); Thing thing; // wait until we know that connection was established for (var i = 0; i < 5; i++) { Assert.True(acceptedSusbscriptionList.TryTake(out thing, 1000)); } Assert.False(acceptedSusbscriptionList.TryTake(out thing, 50)); // open second subscription using ( var rejectedSusbscription = store.AsyncSubscriptions.Open <Thing>(new SubscriptionConnectionOptions() { SubscriptionId = subsId, Strategy = SubscriptionOpeningStrategy.OpenIfFree, TimeToWaitBeforeConnectionRetryMilliseconds = 6000 })) { rejectedSusbscription.Subscribe(thing1 => { }); await Assert.ThrowsAsync <SubscriptionInUseException>(async() => await rejectedSusbscription.StartAsync()); } } } }
public async Task StronglyTypedDataSubscriptions(string storage) { using (var store = NewDocumentStore(requestedStorage: storage)) { using (var session = store.OpenSession()) { for (int i = 0; i < 10; i++) { session.Store(new PersonWithAddress() { Name = "James", Address = new Address() { ZipCode = 12345 } }); session.Store(new PersonWithAddress() { Name = "James", Address = new Address() { ZipCode = 54321 } }); session.Store(new PersonWithAddress() { Name = "David", Address = new Address() { ZipCode = 12345 } }); session.Store(new Person()); } session.SaveChanges(); } var criteria = new SubscriptionCriteria <PersonWithAddress>(); criteria.PropertyMatch(x => x.Name, "James"); criteria.PropertyNotMatch(x => x.Address.ZipCode, 54321); var id = await store.AsyncSubscriptions.CreateAsync(criteria); var subscription = await store.AsyncSubscriptions.OpenAsync <PersonWithAddress>(id, new SubscriptionConnectionOptions()); var users = new List <PersonWithAddress>(); subscription.Subscribe(users.Add); Assert.True(SpinWait.SpinUntil(() => users.Count >= 10, TimeSpan.FromSeconds(60))); Assert.Equal(10, users.Count); foreach (var user in users) { Assert.Equal("James", user.Name); Assert.Equal(12345, user.Address.ZipCode); } } }
public long Create(SubscriptionCriteria criteria, long startEtag = 0, string database = null) { return(AsyncHelpers.RunSync(() => innerAsync.CreateAsync(criteria, startEtag, database))); }
public async Task SubscriptionStrategyConnectIfFree() { using (var store = GetDocumentStore()) { await CreateDocuments(store, 1); var lastEtag = store.GetLastWrittenEtag() ?? 0; await CreateDocuments(store, 5); var subscriptionCriteria = new SubscriptionCriteria { Collection = "Things", }; var subsId = await store.AsyncSubscriptions.CreateAsync(subscriptionCriteria, lastEtag); using ( var acceptedSubscription = store.AsyncSubscriptions.Open <Thing>(new SubscriptionConnectionOptions() { SubscriptionId = subsId, TimeToWaitBeforeConnectionRetryMilliseconds = 20000 })) { var acceptedSusbscriptionList = new BlockingCollection <Thing>(); acceptedSubscription.Subscribe(x => { acceptedSusbscriptionList.Add(x); }); await acceptedSubscription.StartAsync(); Thing thing; // wait until we know that connection was established for (var i = 0; i < 5; i++) { Assert.True(acceptedSusbscriptionList.TryTake(out thing, 1000)); } Assert.False(acceptedSusbscriptionList.TryTake(out thing, 50)); // open second subscription using ( var rejectedSusbscription = store.AsyncSubscriptions.Open <Thing>(new SubscriptionConnectionOptions() { SubscriptionId = subsId, Strategy = SubscriptionOpeningStrategy.OpenIfFree, TimeToWaitBeforeConnectionRetryMilliseconds = 2000 })) { rejectedSusbscription.Subscribe(thing1 => { }); // sometime not throwing (on linux) when written like this: // await Assert.ThrowsAsync<SubscriptionInUseException>(async () => await rejectedSusbscription.StartAsync()); // so we put this in a try block try { await rejectedSusbscription.StartAsync(); Assert.False(true); // we didn't throw - so test failed } catch (SubscriptionInUseException) { } } } } }
public async Task SubscriptionSimpleTakeOverStrategy() { using (var store = GetDocumentStore()) { await CreateDocuments(store, 1); var lastEtag = store.GetLastWrittenEtag() ?? 0; await CreateDocuments(store, 5); var subscriptionCriteria = new SubscriptionCriteria { Collection = "Things", }; var subsId = await store.AsyncSubscriptions.CreateAsync(subscriptionCriteria, lastEtag); using ( var acceptedSubscription = store.AsyncSubscriptions.Open <Thing>(new SubscriptionConnectionOptions() { SubscriptionId = subsId })) { var acceptedSusbscriptionList = new BlockingCollection <Thing>(); var takingOverSubscriptionList = new BlockingCollection <Thing>(); acceptedSubscription.Subscribe(x => { acceptedSusbscriptionList.Add(x); }); var batchProccessedByFirstSubscription = new AsyncManualResetEvent(); acceptedSubscription.AfterAcknowledgment += () => batchProccessedByFirstSubscription.SetByAsyncCompletion(); await acceptedSubscription.StartAsync(); Thing thing; // wait until we know that connection was established for (var i = 0; i < 5; i++) { Assert.True(acceptedSusbscriptionList.TryTake(out thing, 5000), "no doc"); } Assert.True(await batchProccessedByFirstSubscription.WaitAsync(TimeSpan.FromSeconds(15)), "no ack"); Assert.False(acceptedSusbscriptionList.TryTake(out thing)); // open second subscription using (var takingOverSubscription = store.AsyncSubscriptions.Open <Thing>(new SubscriptionConnectionOptions() { SubscriptionId = subsId, Strategy = SubscriptionOpeningStrategy.TakeOver })) { takingOverSubscription.Subscribe(x => takingOverSubscriptionList.Add(x)); await takingOverSubscription.StartAsync(); await CreateDocuments(store, 5); // wait until we know that connection was established for (var i = 0; i < 5; i++) { Assert.True(takingOverSubscriptionList.TryTake(out thing, 5000), "no doc takeover"); } Assert.False(takingOverSubscriptionList.TryTake(out thing)); } } } }
public async Task SubscriptionWaitStrategy() { using (var store = GetDocumentStore()) { await CreateDocuments(store, 1); var lastEtag = store.GetLastWrittenEtag() ?? 0; await CreateDocuments(store, 5); var subscriptionCriteria = new SubscriptionCriteria { Collection = "Things", }; var subsId = await store.AsyncSubscriptions.CreateAsync(subscriptionCriteria, lastEtag); using ( var acceptedSubscription = store.AsyncSubscriptions.Open <Thing>(new SubscriptionConnectionOptions() { SubscriptionId = subsId })) { var acceptedSusbscriptionList = new BlockingCollection <Thing>(); var waitingSubscriptionList = new BlockingCollection <Thing>(); var ackSentAmre = new AsyncManualResetEvent(); acceptedSubscription.AfterAcknowledgment += () => ackSentAmre.SetByAsyncCompletion(); acceptedSubscription.Subscribe(x => { acceptedSusbscriptionList.Add(x); Thread.Sleep(20); }); await acceptedSubscription.StartAsync(); // wait until we know that connection was established Thing thing; // wait until we know that connection was established for (var i = 0; i < 5; i++) { Assert.True(acceptedSusbscriptionList.TryTake(out thing, 50000)); } Assert.False(acceptedSusbscriptionList.TryTake(out thing, 50)); // open second subscription using ( var waitingSubscription = store.AsyncSubscriptions.Open <Thing>(new SubscriptionConnectionOptions() { SubscriptionId = subsId, Strategy = SubscriptionOpeningStrategy.WaitForFree, TimeToWaitBeforeConnectionRetryMilliseconds = 250 })) { waitingSubscription.Subscribe(x => { waitingSubscriptionList.Add(x); }); var taskStarted = waitingSubscription.StartAsync(); var completed = await Task.WhenAny(taskStarted, Task.Delay(60000)); Assert.False(completed == taskStarted); Assert.True(await ackSentAmre.WaitAsync(TimeSpan.FromSeconds(50))); acceptedSubscription.Dispose(); await CreateDocuments(store, 5); // wait until we know that connection was established for (var i = 0; i < 5; i++) { Assert.True(waitingSubscriptionList.TryTake(out thing, 1000)); } Assert.False(waitingSubscriptionList.TryTake(out thing, 50)); } } } }
public long Create <T>(SubscriptionCriteria <T> criteria, string database = null) { return(AsyncHelpers.RunSync(() => innerAsync.CreateAsync(criteria, database))); }