public async Task Worker(IDocumentStore store, CancellationToken cancellationToken) { string subscriptionName = await store.Subscriptions.CreateAsync <Order>(x => x.Company == "companies/11"); SubscriptionWorker <Order> subscription = store.Subscriptions.GetSubscriptionWorker <Order>(subscriptionName); Task subscriptionTask = subscription.Run(x => x.Items.ForEach(item => Console.WriteLine($"Order #{item.Result.Id} will be shipped via: {item.Result.ShipVia}")), cancellationToken); await subscriptionTask; }
public Worker(ILogger <Worker> logger, IHostApplicationLifetime appLifetime, IOptions <WorkerParams> options, SubscriptionWorker subscriptionWorker, AzureAdWorker azureAdWorker) { _logger = logger; _appLifetime = appLifetime; _subscriptionWorker = subscriptionWorker; _azureAdWorker = azureAdWorker; _parms = options.Value; }
public static void PreWarm(this IApplicationBuilder applicationBuilder) { Startup.LoadTypes(); //SubscriptionWorker worker = new SubscriptionWorker() var internalSubscriptionService = Boolean.Parse(ConfigurationReader.GetValue("InternalSubscriptionService")); if (internalSubscriptionService) { String eventStoreConnectionString = ConfigurationReader.GetValue("EventStoreSettings", "ConnectionString"); Int32 inflightMessages = Int32.Parse(ConfigurationReader.GetValue("AppSettings", "InflightMessages")); Int32 persistentSubscriptionPollingInSeconds = Int32.Parse(ConfigurationReader.GetValue("AppSettings", "PersistentSubscriptionPollingInSeconds")); String filter = ConfigurationReader.GetValue("AppSettings", "InternalSubscriptionServiceFilter"); String ignore = ConfigurationReader.GetValue("AppSettings", "InternalSubscriptionServiceIgnore"); String streamName = ConfigurationReader.GetValue("AppSettings", "InternalSubscriptionFilterOnStreamName"); Int32 cacheDuration = Int32.Parse(ConfigurationReader.GetValue("AppSettings", "InternalSubscriptionServiceCacheDuration")); ISubscriptionRepository subscriptionRepository = SubscriptionRepository.Create(eventStoreConnectionString, cacheDuration); ((SubscriptionRepository)subscriptionRepository).Trace += (sender, s) => Extensions.log(TraceEventType.Information, "REPOSITORY", s); // init our SubscriptionRepository subscriptionRepository.PreWarm(CancellationToken.None).Wait(); var eventHandlerResolver = Startup.ServiceProvider.GetService <IDomainEventHandlerResolver>(); SubscriptionWorker concurrentSubscriptions = SubscriptionWorker.CreateConcurrentSubscriptionWorker(eventStoreConnectionString, eventHandlerResolver, subscriptionRepository, inflightMessages, persistentSubscriptionPollingInSeconds); concurrentSubscriptions.Trace += (_, args) => concurrentLog(TraceEventType.Information, args.Message); concurrentSubscriptions.Warning += (_, args) => concurrentLog(TraceEventType.Warning, args.Message); concurrentSubscriptions.Error += (_, args) => concurrentLog(TraceEventType.Error, args.Message); if (!String.IsNullOrEmpty(ignore)) { concurrentSubscriptions = concurrentSubscriptions.IgnoreSubscriptions(ignore); } if (!String.IsNullOrEmpty(filter)) { //NOTE: Not overly happy with this design, but //the idea is if we supply a filter, this overrides ignore concurrentSubscriptions = concurrentSubscriptions.FilterSubscriptions(filter) .IgnoreSubscriptions(null); } if (!String.IsNullOrEmpty(streamName)) { concurrentSubscriptions = concurrentSubscriptions.FilterByStreamName(streamName); } concurrentSubscriptions.StartAsync(CancellationToken.None).Wait(); } }
public void SubscriptionWorker_DefaultValues_WorkerCreated() { Task <List <PersistentSubscriptionInfo> > getSubscriptions = new(TestData.GetPersistentSubscriptions_DemoEstate); String eventStoreConnectionString = "esdb://*****:*****@192.168.1.133:2113?tls=false&tlsVerifyCert=false"; ISubscriptionRepository subscriptionService = SubscriptionRepository.Create(getSubscriptions); SubscriptionWorker concurrentSubscriptions = SubscriptionWorker.CreateConcurrentSubscriptionWorker(eventStoreConnectionString, this.domainEventHandlerResolver.Object, subscriptionService); concurrentSubscriptions.FilterSubscriptions.ShouldBeNull(); concurrentSubscriptions.IgnoreSubscriptions.ShouldBe("local-"); concurrentSubscriptions.StreamNameFilter.ShouldBeNull(); concurrentSubscriptions.InflightMessages.ShouldBe(200); concurrentSubscriptions.IsOrdered.ShouldBeFalse(); }
static async Task SubscriptionsTest() { String eventStoreConnectionString = "esdb://127.0.0.1:2113?tls=false"; Int32 inflightMessages = 1; Int32 persistentSubscriptionPollingInSeconds = 10; String filter = String.Empty; String ignore = String.Empty; String streamName = String.Empty; Int32 cacheDuration = 0; ISubscriptionRepository subscriptionRepository = SubscriptionRepository.Create(eventStoreConnectionString, cacheDuration); //((SubscriptionRepository)subscriptionRepository).Trace += (sender, s) => Extensions.log(TraceEventType.Information, "REPOSITORY", s); // init our SubscriptionRepository subscriptionRepository.PreWarm(CancellationToken.None).Wait(); IDomainEventHandlerResolver eventHandlerResolver = new DomainEventHandlerResolver(new Dictionary <String, String[]>(), null); SubscriptionWorker concurrentSubscriptions = SubscriptionWorker.CreateConcurrentSubscriptionWorker(Program.ConfigureEventStoreSettings(), eventHandlerResolver, subscriptionRepository, inflightMessages, persistentSubscriptionPollingInSeconds); //concurrentSubscriptions.Trace += (_, args) => Extensions.concurrentLog(TraceEventType.Information, args.Message); //concurrentSubscriptions.Warning += (_, args) => Extensions.concurrentLog(TraceEventType.Warning, args.Message); //concurrentSubscriptions.Error += (_, args) => Extensions.concurrentLog(TraceEventType.Error, args.Message); if (!String.IsNullOrEmpty(ignore)) { concurrentSubscriptions = concurrentSubscriptions.IgnoreSubscriptions(ignore); } if (!String.IsNullOrEmpty(filter)) { //NOTE: Not overly happy with this design, but //the idea is if we supply a filter, this overrides ignore concurrentSubscriptions = concurrentSubscriptions.FilterSubscriptions(filter) .IgnoreSubscriptions(null); } if (!String.IsNullOrEmpty(streamName)) { concurrentSubscriptions = concurrentSubscriptions.FilterByStreamName(streamName); } concurrentSubscriptions.StartAsync(CancellationToken.None).Wait(); }
private void InsertProductsToUsers(SubscriptionWorker <dynamic> subscription) { var rand = new Random(); var ct = new CancellationTokenSource(); int min = 0; subscription.Run(batch => { foreach (var doc in batch.Items) { if (doc.Id.StartsWith($"user2.{GenralGuid}") == false) { continue; } if (min >= doc.Result.Age) { continue; } min = doc.Result.Age; var randNumber1 = rand.Next(1, 6); for (var i = 0; i < randNumber1; i++) { var randNumber2 = rand.Next(0, 2); var randNumber3 = rand.Next(0, 4); Debug.Assert(randNumber2 * randNumber3 < ProductsCount); if (doc.Result.Products == null) { doc.Result.Products = new LinkedList <string>(); } doc.Result.Products.AddFirst($"products.{GenralGuid}/{_productsGuid[randNumber2 * randNumber3]}"); } using (var session = DocumentStore.OpenSession()) { session.Store(doc.Result); session.SaveChanges(); } if (doc.Result.Age == 5000) { ct.Cancel(); } } }, ct.Token); }
public static IHostBuilder CreateHostBuilder(string[] args) { Console.Title = "Messaging Service"; //At this stage, we only need our hosting file for ip and ports IConfigurationRoot config = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("hosting.json", optional: true) .AddJsonFile("hosting.development.json", optional: true) .AddEnvironmentVariables().Build(); IHostBuilder hostBuilder = Host.CreateDefaultBuilder(args); hostBuilder.ConfigureLogging(logging => { logging.AddConsole(); }).ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup <Startup>(); webBuilder.UseConfiguration(config); webBuilder.UseKestrel(); }) .ConfigureServices(services => { RequestSentToEmailProviderEvent e = new RequestSentToEmailProviderEvent(Guid.Parse("2AA2D43B-5E24-4327-8029-1135B20F35CE"), "", new List <String>(), "", "", true); RequestSentToSMSProviderEvent s = new RequestSentToSMSProviderEvent(Guid.NewGuid(), "", "", ""); TypeProvider.LoadDomainEventsTypeDynamically(); services.AddHostedService <SubscriptionWorker>(provider => { IDomainEventHandlerResolver r = provider.GetRequiredService <IDomainEventHandlerResolver>(); EventStorePersistentSubscriptionsClient p = provider.GetRequiredService <EventStorePersistentSubscriptionsClient>(); HttpClient h = provider.GetRequiredService <HttpClient>(); SubscriptionWorker worker = new SubscriptionWorker(r, p, h); worker.TraceGenerated += Worker_TraceGenerated; return(worker); }); }); return(hostBuilder); }
private void CreateOrderDoc(SubscriptionWorker <dynamic> subscription) { var rand = new Random(); var ct = new CancellationTokenSource(new TimeSpan(0, 60, 0)); subscription.Run(batch => { foreach (var doc in batch.Items) { /*if (doc.Id.StartsWith($"user2.{GenralGuid}") == false) * { * ReportInfo($"DocID: {doc.Id}"); * continue; * }*/ using (var session = DocumentStore.OpenSession()) { var shipper = rand.Next(0, 10); var list = new LinkedList <string>(); var x = (doc.Result.ProductsNames as JArray).GetEnumerator(); while (x.MoveNext()) { list.AddFirst(x.Current.ToString()); } var user = new Order { ShipVia = $"shipper.{GenralGuid}-{_shipperGuid[shipper]}", ShipTo = doc.Id, ProductsNames = list }; session.Store(user, $"order.{GenralGuid}/"); _shipper[shipper] += 1; session.SaveChanges(); } } }, ct.Token); }
public async Task SubscriptionWorker_CanBeStartedAndStopped() { CancellationToken cancellationToken = CancellationToken.None; SubscriptionWorker sw = SubscriptionWorker.CreateConcurrentSubscriptionWorker(this.EventStoreConnectionString, this.domainEventHandlerResolver.Object, this.SubscriptionRepository).UseInMemory(); await sw.StartAsync(cancellationToken); //Give our service time to run await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken); sw.IsRunning.ShouldBeTrue(); await sw.StopAsync(cancellationToken); sw.IsRunning.ShouldBe(false); var stillConnected = sw.GetPersistentSubscription().Count; stillConnected.ShouldBe(0); }
public async Task SubscriptionWorker_CanBeCreatedAndReceiveEvents() { CancellationToken cancellationToken = CancellationToken.None; TestDomainEventHandler eventHandler1 = new(); Int32 inflight = 200; Int32 pollingInSeconds = 60; this.domainEventHandlerResolver.Setup(d => d.GetDomainEventHandlers(It.IsAny <IDomainEvent>())).Returns(new List <IDomainEventHandler>() { eventHandler1 }); SubscriptionWorker sw = SubscriptionWorker.CreateConcurrentSubscriptionWorker(this.EventStoreConnectionString, this.domainEventHandlerResolver.Object, this.SubscriptionRepository, inflight, pollingInSeconds).UseInMemory(); await sw.StartAsync(cancellationToken); //Give our service time to run await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken); sw.IsRunning.ShouldBeTrue(); PersistentSubscription ps = sw.GetPersistentSubscription()[0]; String @event = "{\r\n \"estateId\": \"4fc2692f-067a-443e-8006-335bf2732248\",\r\n \"estateName\": \"Demo Estate\"\r\n}\t"; ps.Connected.ShouldBeTrue(); ps.PersistentSubscriptionDetails.InflightMessages.ShouldBe(inflight); //Manually add events. ((InMemoryPersistentSubscriptionsClient)ps.PersistentSubscriptionsClient).WriteEvent(@event, "EstateCreatedEvent", cancellationToken); eventHandler1.DomainEvents.Count.ShouldBe(1); }
public void Subscribe() { const string subName = "NewOrders"; var subscriptionCreationOptions = new SubscriptionCreationOptions { Name = subName, }; try { InternetShopStore.Store.Subscriptions.GetSubscriptionState(subName, InternetShopStore.DatabaseName); } catch (SubscriptionDoesNotExistException) { InternetShopStore.Store.Subscriptions.Create <Order>(options: subscriptionCreationOptions, database: InternetShopStore.DatabaseName); } _subscription = InternetShopStore.Store.Subscriptions.GetSubscriptionWorker <Order>(subName); _subscription.Run(x => x.Items.ForEach(async item => { await _hubContext.Clients.All.SendAsync("OrderAdded", $"{item.Result.Product.Name}"); }), CancellationToken.None); }
public async Task CreationExamples() { string name; IDocumentStore store = new DocumentStore(); #region create_whole_collection_generic_with_name name = await store.Subscriptions.CreateAsync(new SubscriptionCreationOptions <Order> { Name = "OrdersProcessingSumbscription" }); #endregion #region create_whole_collection_generic_with_mentor_node name = await store.Subscriptions.CreateAsync(new SubscriptionCreationOptions <Order> { MentorNode = "D" }); #endregion #region create_whole_collection_generic1 name = await store.Subscriptions.CreateAsync <Order>(); #endregion #region create_whole_collection_RQL name = await store.Subscriptions.CreateAsync(new SubscriptionCreationOptions() { Query = "From Orders" }); #endregion #region create_filter_only_generic name = await store.Subscriptions.CreateAsync <Order>(x => x.Lines.Sum(line => line.PricePerUnit *line.Quantity) > 100); #endregion #region create_filter_only_RQL name = await store.Subscriptions.CreateAsync(new SubscriptionCreationOptions() { Query = @" declare function getOrderLinesSum(doc){ var sum = 0; for (var i in doc.Lines) { sum += doc.Lines[i];} return sum; } From Orders as o Where getOrderLinesSum(o) > 100" }); #endregion #region create_filter_and_projection_generic name = store.Subscriptions.Create( new SubscriptionCreationOptions <Order>() { Filter = x => x.Lines.Sum(line => line.PricePerUnit * line.Quantity) > 100, Projection = x => new { Id = x.Id, Total = x.Lines.Sum(line => line.PricePerUnit * line.Quantity), ShipTo = x.ShipTo, EmployeeName = RavenQuery.Load <Employee>(x.Employee).FirstName + " " + RavenQuery.Load <Employee>(x.Employee).LastName } }); #endregion #region create_filter_and_projection_RQL name = await store.Subscriptions.CreateAsync(new SubscriptionCreationOptions() { Query = @"declare function getOrderLinesSum(doc){ var sum = 0; for (var i in doc.Lines) { sum += doc.Lines[i];} return sum; } declare function projectOrder(doc){ var employee = LoadDocument(doc.Employee); return { Id: order.Id, Total: getOrderLinesSum(order), ShipTo: order.ShipTo, EmployeeName: employee.FirstName + ' ' + employee.LastName }; } From Orders as o Where getOrderLinesSum(o) > 100 Select projectOrder(o)" }); #endregion #region create_simple_revisions_subscription_generic name = store.Subscriptions.Create( new SubscriptionCreationOptions <Revision <Order> >()); #endregion #region create_simple_revisions_subscription_RQL name = await store.Subscriptions.CreateAsync(new SubscriptionCreationOptions() { Query = @"From Orders (Revisions = true)" }); #endregion #region use_simple_revision_subscription_generic SubscriptionWorker <Revision <Order> > revisionWorker = store.Subscriptions.GetSubscriptionWorker <Revision <Order> >(name); await revisionWorker.Run((SubscriptionBatch <Revision <Order> > x) => { foreach (var documentsPair in x.Items) { var prev = documentsPair.Result.Previous; var current = documentsPair.Result.Current; ProcessOrderChanges(prev, current); } } ); #endregion void ProcessOrderChanges(Order prev, Order cur) { } #region create_projected_revisions_subscription_generic name = store.Subscriptions.Create( new SubscriptionCreationOptions <Revision <Order> >() { Filter = tuple => tuple.Current.Lines.Count > tuple.Previous.Lines.Count, Projection = tuple => new { PreviousRevenue = tuple.Previous.Lines.Sum(x => x.PricePerUnit * x.Quantity), CurrentRevenue = tuple.Current.Lines.Sum(x => x.PricePerUnit * x.Quantity) } }); #endregion #region create_projected_revisions_subscription_RQL name = await store.Subscriptions.CreateAsync(new SubscriptionCreationOptions() { Query = @"declare function getOrderLinesSum(doc){ var sum = 0; for (var i in doc.Lines) { sum += doc.Lines[i];} return sum; } From Orders (Revisions = true) Where getOrderLinesSum(this.Current) > getOrderLinesSum(this.Previous) Select { PreviousRevenue: getOrderLinesSum(this.Previous), CurrentRevenue: getOrderLinesSum(this.Current) }" }); #endregion #region consume_revisions_subscription_generic SubscriptionWorker <OrderRevenues> revenuesComparisonWorker = store.Subscriptions.GetSubscriptionWorker <OrderRevenues>(name); await revenuesComparisonWorker.Run(x => { foreach (var item in x.Items) { Console.WriteLine($"Revenue for order with Id: {item.Id} grown from {item.Result.PreviousRevenue} to {item.Result.CurrentRevenue}"); } }); #endregion SubscriptionWorker <Order> subscription; var cancellationToken = new CancellationTokenSource().Token; #region consumption_0 var subscriptionName = await store.Subscriptions.CreateAsync <Order>(x => x.Company == "companies/11"); subscription = store.Subscriptions.GetSubscriptionWorker <Order>(subscriptionName); var subscriptionTask = subscription.Run(x => x.Items.ForEach(item => Console.WriteLine($"Order #{item.Result.Id} will be shipped via: {item.Result.ShipVia}")), cancellationToken); await subscriptionTask; #endregion #region open_1 subscription = store.Subscriptions.GetSubscriptionWorker <Order>(name); #endregion #region open_2 subscription = store.Subscriptions.GetSubscriptionWorker <Order>(new SubscriptionWorkerOptions(name) { Strategy = SubscriptionOpeningStrategy.WaitForFree }); #endregion #region open_3 subscription = store.Subscriptions.GetSubscriptionWorker <Order>(new SubscriptionWorkerOptions(name) { Strategy = SubscriptionOpeningStrategy.WaitForFree, MaxDocsPerBatch = 500, IgnoreSubscriberErrors = true }); #endregion }
public async Task DistributedRevisionsSubscription(int nodesAmount) { var uniqueRevisions = new HashSet <string>(); var uniqueDocs = new HashSet <string>(); var(_, leader) = await CreateRaftCluster(nodesAmount).ConfigureAwait(false); var defaultDatabase = GetDatabaseName(); await CreateDatabaseInCluster(defaultDatabase, nodesAmount, leader.WebUrl).ConfigureAwait(false); using (var store = new DocumentStore { Urls = new[] { leader.WebUrl }, Database = defaultDatabase }.Initialize()) { await SetupRevisions(leader, defaultDatabase).ConfigureAwait(false); var reachedMaxDocCountMre = new AsyncManualResetEvent(); var ackSent = new AsyncManualResetEvent(); var continueMre = new AsyncManualResetEvent(); await GenerateDistributedRevisionsDataAsync(defaultDatabase); var subscriptionId = await store.Subscriptions.CreateAsync <Revision <User> >().ConfigureAwait(false); var docsCount = 0; var revisionsCount = 0; var expectedRevisionsCount = 0; SubscriptionWorker <Revision <User> > subscription = null; int i; for (i = 0; i < 10; i++) { subscription = store.Subscriptions.GetSubscriptionWorker <Revision <User> >(new SubscriptionWorkerOptions(subscriptionId) { MaxErroneousPeriod = nodesAmount == 5 ? TimeSpan.FromSeconds(15) : TimeSpan.FromSeconds(5), MaxDocsPerBatch = 1, TimeToWaitBeforeConnectionRetry = TimeSpan.FromMilliseconds(100) }); subscription.AfterAcknowledgment += async b => { Assert.True(await continueMre.WaitAsync(TimeSpan.FromSeconds(60))); try { if (revisionsCount == expectedRevisionsCount) { continueMre.Reset(); ackSent.Set(); } Assert.True(await continueMre.WaitAsync(TimeSpan.FromSeconds(60))); } catch (Exception) { } }; var started = new AsyncManualResetEvent(); var task = subscription.Run(b => { started.Set(); HandleSubscriptionBatch(nodesAmount, b, uniqueDocs, ref docsCount, uniqueRevisions, reachedMaxDocCountMre, ref revisionsCount); }); var cont = task.ContinueWith(t => { reachedMaxDocCountMre.SetException(t.Exception); ackSent.SetException(t.Exception); }, TaskContinuationOptions.OnlyOnFaulted); await Task.WhenAny(task, started.WaitAsync(TimeSpan.FromSeconds(60))); if (started.IsSet) { break; } Assert.IsType <SubscriptionDoesNotExistException>(task.Exception.InnerException); subscription.Dispose(); } Assert.NotEqual(i, 10); expectedRevisionsCount = nodesAmount + 2; continueMre.Set(); Assert.True(await ackSent.WaitAsync(_reasonableWaitTime).ConfigureAwait(false), $"Doc count is {docsCount} with revisions {revisionsCount}/{expectedRevisionsCount} (1st assert)"); ackSent.Reset(true); var disposedTag = await KillServerWhereSubscriptionWorks(defaultDatabase, subscription.SubscriptionName).ConfigureAwait(false); await WaitForResponsibleNodeToChange(defaultDatabase, subscription.SubscriptionName, disposedTag); continueMre.Set(); expectedRevisionsCount += 2; Assert.True(await ackSent.WaitAsync(_reasonableWaitTime).ConfigureAwait(false), $"Doc count is {docsCount} with revisions {revisionsCount}/{expectedRevisionsCount} (2nd assert)"); ackSent.Reset(true); continueMre.Set(); expectedRevisionsCount = (int)Math.Pow(nodesAmount, 2); if (nodesAmount == 5) { var secondDisposedTag = await KillServerWhereSubscriptionWorks(defaultDatabase, subscription.SubscriptionName).ConfigureAwait(false); await WaitForResponsibleNodeToChange(defaultDatabase, subscription.SubscriptionName, secondDisposedTag); } Assert.True(await reachedMaxDocCountMre.WaitAsync(_reasonableWaitTime).ConfigureAwait(false), $"Doc count is {docsCount} with revisions {revisionsCount}/{expectedRevisionsCount} (3rd assert)"); } }
public void AllClientsWith_WaitForFree_StrategyShouldGetAccessToSubscription() { using (var store = GetDocumentStore()) { var id = store.Subscriptions.Create <User>(); const int numberOfClients = 4; var subscriptions = new SubscriptionWorker <User> [numberOfClients]; var processed = new ManualResetEvent[numberOfClients]; var done = new bool[numberOfClients]; for (int i = 0; i < numberOfClients; i++) { processed[i] = new ManualResetEvent(false); } var userShouldnotexist = "user/shouldNotExist"; using (var session = store.OpenSession()) { session.Store(new User(), userShouldnotexist); session.SaveChanges(); //session.Delete(userShouldnotexist); } for (int i = 0; i < numberOfClients; i++) { var clientNumber = i; subscriptions[clientNumber] = store.Subscriptions.GetSubscriptionWorker <User>(new SubscriptionWorkerOptions(id) { Strategy = SubscriptionOpeningStrategy.WaitForFree }); subscriptions[clientNumber].AfterAcknowledgment += x => { processed[clientNumber].Set(); return(Task.CompletedTask); }; subscriptions[clientNumber].Run(x => { }); Thread.Sleep(200); } for (int i = 0; i < numberOfClients; i++) { using (var s = store.OpenSession()) { s.Store(new User()); s.SaveChanges(); } var index = WaitHandle.WaitAny(processed, waitForDocTimeout); Assert.NotEqual(WaitHandle.WaitTimeout, index); subscriptions[index].Dispose(); done[index] = true; processed[index].Reset(); } for (int i = 0; i < numberOfClients; i++) { Assert.True(done[i]); } } }
public async Task CanReleaseSubscription() { SubscriptionWorker <dynamic> subscriptionWorker = null; SubscriptionWorker <dynamic> throwingSubscriptionWorker = null; SubscriptionWorker <dynamic> notThrowingSubscriptionWorker = null; var store = GetDocumentStore(); try { Server.ServerStore.Observer.Suspended = true; var id = store.Subscriptions.Create(new SubscriptionCreationOptions <User>()); subscriptionWorker = store.Subscriptions.GetSubscriptionWorker(new SubscriptionWorkerOptions(id) { Strategy = SubscriptionOpeningStrategy.OpenIfFree, TimeToWaitBeforeConnectionRetry = TimeSpan.FromSeconds(5) }); var mre = new AsyncManualResetEvent(); PutUserDoc(store); var t = subscriptionWorker.Run(x => { mre.Set(); }); Assert.True(await mre.WaitAsync(_reasonableWaitTime)); mre.Reset(); throwingSubscriptionWorker = store.Subscriptions.GetSubscriptionWorker(new SubscriptionWorkerOptions(id) { Strategy = SubscriptionOpeningStrategy.OpenIfFree, TimeToWaitBeforeConnectionRetry = TimeSpan.FromSeconds(5) }); var subscriptionTask = throwingSubscriptionWorker.Run(x => { }); Assert.True(await Assert.ThrowsAsync <SubscriptionInUseException>(() => { return(subscriptionTask); }).WaitAsync(_reasonableWaitTime)); store.Subscriptions.DropConnection(id); notThrowingSubscriptionWorker = store.Subscriptions.GetSubscriptionWorker(new SubscriptionWorkerOptions(id) { TimeToWaitBeforeConnectionRetry = TimeSpan.FromSeconds(5), Strategy = SubscriptionOpeningStrategy.WaitForFree }); t = notThrowingSubscriptionWorker.Run(x => { mre.Set(); }); PutUserDoc(store); Assert.True(await mre.WaitAsync(_reasonableWaitTime)); } finally { subscriptionWorker?.Dispose(); throwingSubscriptionWorker?.Dispose(); notThrowingSubscriptionWorker?.Dispose(); store.Dispose(); } }
public async Task ShouldKeepPullingDocsAfterServerRestart() { var dataPath = NewDataPath(); IDocumentStore store = null; RavenServer server = null; SubscriptionWorker <dynamic> subscriptionWorker = null; try { var co = new ServerCreationOptions { RunInMemory = false, CustomSettings = new Dictionary <string, string>() { [RavenConfiguration.GetKey(x => x.Core.DataDirectory)] = dataPath }, RegisterForDisposal = false }; server = GetNewServer(co); store = new DocumentStore() { Urls = new[] { server.ServerStore.GetNodeHttpServerUrl() }, Database = "RavenDB_2627", }.Initialize(); var doc = new DatabaseRecord(store.Database); var result = store.Maintenance.Server.Send(new CreateDatabaseOperationWithoutNameValidation(doc)); await WaitForRaftIndexToBeAppliedInCluster(result.RaftCommandIndex, _reasonableWaitTime); using (var session = store.OpenSession()) { session.Store(new User()); session.Store(new User()); session.Store(new User()); session.Store(new User()); session.SaveChanges(); } var id = store.Subscriptions.Create(new SubscriptionCreationOptions <User>()); subscriptionWorker = store.Subscriptions.GetSubscriptionWorker(new SubscriptionWorkerOptions(id) { TimeToWaitBeforeConnectionRetry = TimeSpan.FromSeconds(1), MaxDocsPerBatch = 1 }); var gotBatch = new ManualResetEventSlim(); var gotArek = new ManualResetEventSlim(); var t = subscriptionWorker.Run(x => { gotBatch.Set(); foreach (var item in x.Items) { if (item.Id == "users/arek") { gotArek.Set(); } } }); Assert.True(gotBatch.Wait(_reasonableWaitTime)); Server.ServerStore.DatabasesLandlord.UnloadDirectly(store.Database); for (int i = 0; i < 150; i++) { try { using (var session = store.OpenSession()) { session.Store(new User(), "users/arek"); session.SaveChanges(); } break; } catch { Thread.Sleep(25); if (i > 100) { throw; } } } Assert.True(gotArek.Wait(_reasonableWaitTime)); } finally { subscriptionWorker?.Dispose(); store?.Dispose(); server.Dispose(); } }
public async Task MixedCluster_DistributedRevisionsSubscription() { var uniqueRevisions = new HashSet <string>(); var uniqueDocs = new HashSet <string>(); var nodesAmount = 5; var(leader, peers, local) = await CreateMixedCluster(new[] { "4.0.7-nightly-20180820-0400", "4.0.7-nightly-20180820-0400" }, 2, new Dictionary <string, string> { [RavenConfiguration.GetKey(x => x.Cluster.MoveToRehabGraceTime)] = "1" }); var stores = await GetStores(leader, peers, local, modifyDocumentStore : s => s.Conventions.DisableTopologyUpdates = false); using (stores.Disposable) { var storeA = stores.Stores[0]; var dbName = await CreateDatabase(storeA, nodesAmount); await Task.Delay(500); await RevisionsHelper.SetupRevisions(leader.ServerStore, dbName).ConfigureAwait(false); var reachedMaxDocCountMre = new AsyncManualResetEvent(); var ackSent = new AsyncManualResetEvent(); var continueMre = new AsyncManualResetEvent(); GenerateDistributedRevisionsData(dbName, stores.Stores); var subscriptionId = await storeA.Subscriptions.CreateAsync <Revision <User> >(database : dbName).ConfigureAwait(false); var docsCount = 0; var revisionsCount = 0; var expectedRevisionsCount = 0; SubscriptionWorker <Revision <User> > subscription = null; int i; for (i = 0; i < 10; i++) { subscription = storeA.Subscriptions.GetSubscriptionWorker <Revision <User> >(new SubscriptionWorkerOptions(subscriptionId) { MaxDocsPerBatch = 1, TimeToWaitBeforeConnectionRetry = TimeSpan.FromMilliseconds(100) }, dbName); subscription.AfterAcknowledgment += async b => { await continueMre.WaitAsync(); try { if (revisionsCount == expectedRevisionsCount) { continueMre.Reset(); ackSent.Set(); } await continueMre.WaitAsync(); } catch (Exception) { } }; var started = new AsyncManualResetEvent(); var task = subscription.Run(b => { started.Set(); HandleSubscriptionBatch(nodesAmount, b, uniqueDocs, ref docsCount, uniqueRevisions, reachedMaxDocCountMre, ref revisionsCount); }); await Task.WhenAny(task, started.WaitAsync()); if (started.IsSet) { break; } Assert.IsType <SubscriptionDoesNotExistException>(task.Exception.InnerException); subscription.Dispose(); } Assert.NotEqual(i, 10); expectedRevisionsCount = nodesAmount + 2; continueMre.Set(); Assert.True(await ackSent.WaitAsync(_reasonableWaitTime).ConfigureAwait(false), $"Doc count is {docsCount} with revisions {revisionsCount}/{expectedRevisionsCount} (1st assert)"); ackSent.Reset(true); await KillServerWhereSubscriptionWorks(storeA, dbName, subscription.SubscriptionName, (leader, peers, local)).ConfigureAwait(false); continueMre.Set(); expectedRevisionsCount += 2; Assert.True(await ackSent.WaitAsync(_reasonableWaitTime).ConfigureAwait(false), $"Doc count is {docsCount} with revisions {revisionsCount}/{expectedRevisionsCount} (2nd assert)"); ackSent.Reset(true); continueMre.Set(); expectedRevisionsCount = (int)Math.Pow(nodesAmount, 2); await KillServerWhereSubscriptionWorks(storeA, dbName, subscription.SubscriptionName, (leader, peers, local)).ConfigureAwait(false); Assert.True(await reachedMaxDocCountMre.WaitAsync(_reasonableWaitTime).ConfigureAwait(false), $"Doc count is {docsCount} with revisions {revisionsCount}/{expectedRevisionsCount} (3rd assert)"); } }