private static async Task Main(string[] args) { Console.WriteLine("Program started..."); // global::HibernatingRhinos.Profiler.Appender.NHibernate.NHibernateProfiler.Initialize(); var binder = new VersionedBinder(); var serializer = new JsonNetSerializer(binder); CreateDbIfNotExisting(); var nHibernateResetConfigurationProvider = new NHibernateResetConfigurationProvider( GetBaseConfiguration(), new[] { typeof(PersistentEntity).Assembly, typeof(RawStreamEntry).Assembly, typeof(CheckpointInfo).Assembly }); var configuration = nHibernateResetConfigurationProvider.GetConfigurationForTypes(typeof(RawStreamEntry), typeof(CheckpointInfo), typeof(PersistentEntity)); var sessionFactory = configuration.BuildSessionFactory(); var bus = new ObservableMessageBus(); var persistenceEngine = new PersistenceEngine(sessionFactory, configuration, serializer); await persistenceEngine.InitializeAsync(); var repo = new EventRepository( new DefaultInstanceProvider(), persistenceEngine, new RawStreamEntryFactory()); // let bus subscribe to repository and publish its committed events repo.SubscribeTo <IMessage <IEvent> >() .Subscribe((e) => bus.Publish(e)); // normal event processing bus.SubscribeTo <IMessage <IEvent> >().Subscribe((e) => { Console.WriteLine("Look, an event: " + e.ToString()); }); bus.SubscribeTo <SomethingDone>() .Subscribe((e) => { Console.WriteLine("Something done: " + e.Bla); }); bus.SubscribeTo <Renamed>() .Subscribe((e) => { Console.WriteLine("Renamed: " + e.Name); }); // complex event processing bus.SubscribeTo <IEvent>() .Buffer(2, 1) .Where(x => x.First() is SomethingDone && x.Last() is INameChangeEvent) .Subscribe((e) => { Console.WriteLine("IMessage<IEvent>: Look, a new name after something done: " + (e.First() as SomethingDone).Bla + " -> " + (e.Last() as INameChangeEvent).Name); }); bus.SubscribeTo <IEvent>() .Buffer(2, 1) .Where(x => x.First() is SomethingDone && x.Last() is INameChangeEvent) .Subscribe((e) => { Console.WriteLine("IEvent: Look, a new name after something done: " + (e.First() as SomethingDone).Bla + " -> " + (e.Last() as INameChangeEvent).Name); }); bus .SubscribeToAndUpdate <IMessage <TestAggregateRename>, TestAggregate>((aggr, cmd) => { aggr.Rename(cmd.Body.Name); }, repo); bus.SubscribeTo <IMessage <TestAggregateDoSomething> >() .Select(command => Observable.FromAsync(() => Task.Run(async() => { var aggregate = await repo.GetAsync <TestAggregate>(command.Body.Id); aggregate.DoSomething(command.Body.Foo); await repo.SaveAsync(aggregate); }))) .Concat() .Subscribe() ; Console.WriteLine("Start executing..."); var agg = new TestAggregate("abc" + Guid.NewGuid(), "test"); agg.DoSomething("bla bla bla"); agg.Rename("foo thing bar"); agg.DoSomething("ha ha"); agg.DoSomethingSpecial("<write poem>"); agg.Rename("hu?"); agg.DoSomething("hello?"); agg.Rename("Hi!"); await repo.SaveAsync(agg); agg = await repo.GetAsync <TestAggregate>(agg.Id); var projection = TestState.LoadState(agg.StateModel); var projection2 = agg.StateModel; Console.WriteLine("Name: " + projection.Name + ", " + projection.SomethingDone); Console.WriteLine("Name: " + projection2.Name + ", " + projection2.SomethingDone); Console.WriteLine("Try to mess with state:"); bus.Send(new TypedMessage <TestAggregateDoSomething>(Guid.NewGuid().ToString(), new TestAggregateDoSomething { Id = agg.Id, Foo = "Command DoSomething Bla" }, null, null, null, DateTime.UtcNow, 0)); bus.Send(new TypedMessage <TestAggregateRename>(Guid.NewGuid().ToString(), new TestAggregateRename { Id = agg.Id, Name = "Command Renamed Name" }, null, null, null, DateTime.UtcNow, 0)); agg = await repo.GetAsync <TestAggregate>(agg.Id); projection2 = agg.StateModel; Console.WriteLine("Name: " + projection2.Name); Console.WriteLine("-------"); Console.WriteLine("Database Persistence"); Console.WriteLine("-------"); //var engine = new PersistenceEngine(sessionFactory, configuration, serializer); var observerFactory = new PollingObserverFactory(persistenceEngine, TimeSpan.FromMilliseconds(500)); var observer = await observerFactory.CreateObserverAsync(0); observer.Subscribe((s) => { //Console.WriteLine("Polling: " + s.StreamName + "@" + s.StreamRevision + " - " + s.CheckpointNumber); }); await observer.StartAsync(); var repository = new EventRepository( new DefaultInstanceProvider(), persistenceEngine, new RawStreamEntryFactory()); string entityId = null; Console.WriteLine("Generate 1000 entities"); var list = new List <IEventSourcedEntity>(); for (var i = 0; i < 1000; i++) { Console.Write("."); entityId = Guid.NewGuid().ToString(); var entity = new TestAggregate(entityId, "test " + DateTime.Now.ToShortTimeString()); entity.Rename("asdfasdf"); entity.DoSomething("bla" + DateTime.Now.ToShortTimeString()); list.Add(entity); } await repository.SaveAsync(list); list.Clear(); var loadedEntity = await repository.GetAsync <TestAggregate>(entityId); Console.WriteLine("Commits: " + await persistenceEngine.LoadStreamEntriesAsync() //.Result .CountAsync()); Console.WriteLine("Rename count: " + await persistenceEngine.LoadStreamEntriesAsync(payloadTypes: new[] { typeof(Renamed) }) //.Result .CountAsync()); Console.WriteLine("Rename checkpointnumbers of renames descending: " + string.Join(", ", await persistenceEngine .LoadStreamEntriesAsync(ascending: false, payloadTypes: new[] { typeof(Renamed), typeof(SomethingDone) }) //.Result .Select(x => "" + x.CheckpointNumber).ToArrayAsync())); Console.WriteLine("Rename count: " + await persistenceEngine.LoadStreamEntriesAsync( minCheckpointNumber: await persistenceEngine.GetCurrentEventStoreCheckpointNumberAsync() - 5, payloadTypes: new[] { typeof(Renamed) }) //.Result .CountAsync()); Console.WriteLine("Current CheckpointNumber: " + await persistenceEngine.GetCurrentEventStoreCheckpointNumberAsync() //.Result ); var viewModelResetter = new StorageResetter(nHibernateResetConfigurationProvider); var checkpointPersister = new CheckpointPersister <CheckpointInfo>(sessionFactory); //Console.ReadKey(); var readRepository = new ReadRepository(sessionFactory); //return; /* * var live = new CatchUpProjector<TestState>( * new TestState(), * checkpointPersister, * persistenceEngine, * viewModelResetter, * 2000); * * var stopwatch = new Stopwatch(); * stopwatch.Start(); * live.Start(); * stopwatch.Stop(); * Console.WriteLine("live: " + stopwatch.ElapsedMilliseconds + "ms"); * * var live2 = new CatchUpProjector<VowelCountState>( * new VowelCountState(), * new NullCheckpointPersister(), * persistenceEngine, * viewModelResetter, * 2000); * live2.Start(); */ var resetter = new StorageResetter(nHibernateResetConfigurationProvider); //resetter.Reset(new[] { typeof(PersistentEntity) }); var persistentState = new CatchUpProjector <PersistentState>( new PersistentState(readRepository), checkpointPersister, persistenceEngine, viewModelResetter, observerFactory); var stopwatch = new Stopwatch(); stopwatch.Start(); await persistentState.StartAsync(); _ = Task.Run(async() => { while (true) { Console.WriteLine(persistentState.StateModel.Count); await Task.Delay(1000).ConfigureAwait(false); } }); Console.ReadKey(); stopwatch.Stop(); Console.WriteLine($"persistent: {persistentState.StateModel.Count} msgs, {stopwatch.ElapsedMilliseconds}ms -> {persistentState.StateModel.Count / (stopwatch.ElapsedMilliseconds / 1000.0)}"); observer.Dispose(); /* * Console.WriteLine(live.StateModel.Name); * Console.WriteLine(live.StateModel.SomethingDone); * Console.WriteLine(live.StateModel.StreamName); * * * Console.WriteLine("a: " + live2.StateModel.ACount); * Console.WriteLine("e: " + live2.StateModel.ECount); * Console.WriteLine("i: " + live2.StateModel.ICount); * Console.WriteLine("o: " + live2.StateModel.OCount); * Console.WriteLine("u: " + live2.StateModel.UCount); */ Console.ReadKey(); }
private static async Task Main(string[] args) { var disposables = new List <IDisposable>(); Console.WriteLine("Program started..."); var binder = new VersionedBinder(); var serializer = new JsonNetSerializer(binder); var bus = new ObservableMessageBus(); var repo = new EventRepository(new DefaultInstanceProvider(), new WriteModel.InMemory.PersistenceEngine(serializer), new WriteModel.InMemory.RawStreamEntryFactory()); // let bus subscribe to repository and publish its committed events repo.SubscribeTo <IMessage <IEvent> >() .Subscribe((e) => bus.Publish(e)); // normal event processing bus.SubscribeTo <IMessage <IEvent> >().Subscribe((e) => { Console.WriteLine("Look, an event: " + e.ToString()); }); bus.SubscribeTo <SomethingDone>() .Subscribe((e) => { Console.WriteLine("Something done: " + e.Bla); }); bus.SubscribeTo <Renamed>() .Subscribe((e) => { Console.WriteLine("Renamed: " + e.Name); }); // complex event processing bus.SubscribeTo <IEvent>() .Buffer(2, 1) .Where(x => x.First() is SomethingDone && x.Last() is INameChangeEvent) .Subscribe((e) => { Console.WriteLine("IMessage<IEvent>: Look, a new name after something done: " + (e.First() as SomethingDone).Bla + " -> " + (e.Last() as INameChangeEvent).Name); }); bus.SubscribeTo <IEvent>() .Buffer(2, 1) .Where(x => x.First() is SomethingDone && x.Last() is INameChangeEvent) .Subscribe((e) => { Console.WriteLine("IEvent: Look, a new name after something done: " + (e.First() as SomethingDone).Bla + " -> " + (e.Last() as INameChangeEvent).Name); }); bus .SubscribeToAndUpdate <IMessage <TestAggregateRename>, TestAggregate>((aggr, cmd) => { aggr.Rename(cmd.Body.Name); }, repo); bus.SubscribeTo <IMessage <TestAggregateDoSomething> >() .Select(command => Observable.FromAsync(async() => { var aggregate = await repo.GetAsync <TestAggregate>(command.Body.Id); aggregate.DoSomething(command.Body.Foo); await repo.SaveAsync(aggregate); })) .Concat() .Subscribe(); Console.WriteLine("Start executing..."); var agg = new TestAggregate("abc" + Guid.NewGuid(), "test"); agg.DoSomething("bla bla bla"); agg.Rename("foo thing bar"); agg.DoSomething("ha ha"); agg.DoSomethingSpecial("<write poem>"); agg.Rename("hu?"); agg.DoSomething("hello?"); agg.Rename("Hi!"); await repo.SaveAsync(agg); agg = await repo.GetAsync <TestAggregate>(agg.Id); var projection = TestState.LoadState(agg.StateModel); var projection2 = agg.StateModel; Console.WriteLine("Name: " + projection.Name + ", " + projection.SomethingDone); Console.WriteLine("Name: " + projection2.Name + ", " + projection2.SomethingDone); Console.WriteLine("Try to mess with state:"); bus.Send(new TypedMessage <TestAggregateDoSomething>(Guid.NewGuid().ToString(), new TestAggregateDoSomething { Id = agg.Id, Foo = "Command DoSomething Bla" }, null, null, null, DateTime.UtcNow, 0)); bus.Send(new TypedMessage <TestAggregateRename>(Guid.NewGuid().ToString(), new TestAggregateRename { Id = agg.Id, Name = "Command Renamed Name" }, null, null, null, DateTime.UtcNow, 0)); agg = await repo.GetAsync <TestAggregate>(agg.Id); projection2 = agg.StateModel; Console.WriteLine("Name: " + projection2.Name); // Console.WriteLine("Change-count: " + AlternateState.LoadState((AlernateState)null, agg.ev).ChangeCount); //SQLite3.Config(ConfigOption.Serialized); Console.WriteLine("-------"); Console.WriteLine("Database Persistence"); Console.WriteLine("-------"); SQLiteConnectionWithLock connectionFactory() { if (writeConn != null) { return(writeConn); } //SQLite3.Config(ConfigOption.Serialized); var databaseFile = "writeDatabase.db"; var connectionString = new SQLiteConnectionString(databaseFile, SQLiteOpenFlags.Create | SQLiteOpenFlags.ReadWrite | SQLiteOpenFlags.FullMutex, true, null); writeConn = new SQLiteConnectionWithLock(connectionString); using (writeConn.Lock()) { writeConn.CreateCommand(@"PRAGMA synchronous = NORMAL; PRAGMA journal_mode = WAL;", Array.Empty <object>()).ExecuteScalar <int>(); } return(writeConn); } SQLiteConnectionWithLock readConnectionFactory() { if (readConn != null) { return(readConn); } //SQLite3.Config(ConfigOption.Serialized); var databaseFile = "readDatabase.db"; var connectionString = new SQLiteConnectionString(databaseFile, SQLiteOpenFlags.Create | SQLiteOpenFlags.ReadWrite | SQLiteOpenFlags.FullMutex, true, null); readConn = new SQLiteConnectionWithLock(connectionString); using (readConn.Lock()) { readConn.CreateCommand(@"PRAGMA synchronous = NORMAL; PRAGMA temp_store = MEMORY; PRAGMA page_size = 4096; PRAGMA cache_size = 10000; PRAGMA journal_mode = WAL;", Array.Empty <object>()).ExecuteScalar <int>(); } return(readConn); } var engine = new PersistenceEngine(connectionFactory, serializer); engine.InitializeAsync().Wait(); var observerFactory = new PollingObserverFactory(engine, TimeSpan.FromMilliseconds(500)); var observer = await observerFactory.CreateObserverAsync(0); var subscription = observer.Subscribe((s) => { //Console.WriteLine("Polling: " + s.StreamName + "@" + s.StreamRevision + " - " + s.CheckpointNumber); }); disposables.Add(subscription); disposables.Add(observer); await observer.StartAsync(); var repository = new EventRepository( new DefaultInstanceProvider(), engine, new RawStreamEntryFactory()); string entityId = null; Console.WriteLine("Generate 1000 entities"); var list = new List <IEventSourcedEntity>(); for (var i = 0; i < 1000; i++) { Console.Write("."); entityId = Guid.NewGuid().ToString(); var entity = new TestAggregate(entityId, "test " + DateTime.Now.ToShortTimeString()); entity.Rename("asdfasdf"); entity.DoSomething("bla" + DateTime.Now.ToShortTimeString()); list.Add(entity); } await repository.SaveAsync(list); list.Clear(); var loadedEntity = await repository.GetAsync <TestAggregate>(entityId); var stopwatch = new Stopwatch(); stopwatch.Start(); var count = await engine.LoadStreamEntriesAsync().CountAsync(); stopwatch.Stop(); Console.WriteLine($"Load {count} entries: {stopwatch.ElapsedMilliseconds}ms"); Console.ReadKey(); Console.WriteLine("Commits: " + await engine.LoadStreamEntriesAsync() //.Result .CountAsync()); Console.WriteLine("Rename count: " + await engine.LoadStreamEntriesAsync(payloadTypes: new[] { typeof(Renamed) }) //.Result .CountAsync()); Console.WriteLine("Rename checkpointnumbers of renames descending: " + string.Join(", ", await engine .LoadStreamEntriesAsync(ascending: false, payloadTypes: new[] { typeof(Renamed), typeof(SomethingDone) }) //.Result .Select(x => "" + x.CheckpointNumber).ToArrayAsync())); Console.WriteLine("Rename count: " + await engine.LoadStreamEntriesAsync(minCheckpointNumber: await engine.GetCurrentEventStoreCheckpointNumberAsync() //.Result - 5, payloadTypes: new[] { typeof(Renamed) }) //.Result .CountAsync()); Console.WriteLine("Current CheckpointNumber: " + await engine.GetCurrentEventStoreCheckpointNumberAsync() //.Result ); var c = readConnectionFactory(); //c.RunInTransactionAsync((SQLiteConnection connection) => //{ c.RunInLock((SQLiteConnection connection) => { connection.CreateTable <CheckpointInfo>(CreateFlags.AllImplicit); }); var viewModelResetter = new StorageResetter(readConnectionFactory()); var checkpointPersister = new CheckpointPersister <CheckpointInfo>(readConnectionFactory()); //Console.ReadKey(); var readRepository = new ReadRepository(readConnectionFactory); //return; /* * var live = new CatchUpProjector<TestState>( * new TestState(), * new NullCheckpointPersister(), * engine, * viewModelResetter); * * Stopwatch stopwatch = new Stopwatch(); * stopwatch.Start(); * live.Start(); * stopwatch.Stop(); * Console.WriteLine("live: " + stopwatch.ElapsedMilliseconds + "ms"); * * var live2 = new CatchUpProjector<VowelCountState>( * new VowelCountState(), * new NullCheckpointPersister(), * engine, * viewModelResetter); * live2.Start(); * * var resetter = new StorageResetter(readConnectionFactory()); * //resetter.Reset(new[] { typeof(PersistentEntity) }); */ var persistentState = new CatchUpProjector <PersistentState>( new PersistentState(readRepository), checkpointPersister, engine, viewModelResetter, observerFactory); stopwatch.Start(); await persistentState.StartAsync(); _ = Task.Run(async() => { while (true) { Console.WriteLine(persistentState.StateModel.Count); await Task.Delay(1000).ConfigureAwait(false); } }); Console.ReadKey(); stopwatch.Stop(); Console.WriteLine($"persistent: {persistentState.StateModel.Count} msgs, {stopwatch.ElapsedMilliseconds}ms -> {persistentState.StateModel.Count / (stopwatch.ElapsedMilliseconds / 1000.0)}"); /* * Console.ReadKey(); * Console.WriteLine(live.StateModel.Name); * Console.WriteLine(live.StateModel.SomethingDone); * Console.WriteLine(live.StateModel.StreamName); * * * Console.WriteLine("a: " + live2.StateModel.ACount); * Console.WriteLine("e: " + live2.StateModel.ECount); * Console.WriteLine("i: " + live2.StateModel.ICount); * Console.WriteLine("o: " + live2.StateModel.OCount); * Console.WriteLine("u: " + live2.StateModel.UCount); */ Console.ReadKey(); foreach (var disp in disposables) { disp.Dispose(); } observer.Dispose(); }