public void Register(Type atomicAggregateType) { var attribute = AtomicReadmodelInfoAttribute.GetFrom(atomicAggregateType); if (attribute == null) { throw new JarvisFrameworkEngineException($"Type {atomicAggregateType} cannot be used as atomic readmodel, it misses the AtomicReadmodelInfo attribute"); } if (_registeredTypeNames.ContainsKey(attribute.Name)) { if (_registeredTypeNames[attribute.Name] == atomicAggregateType) { return; //already added. } throw new JarvisFrameworkEngineException($"Type {atomicAggregateType} cannot be used as atomic readmodel, it uses name {attribute.Name} already in use by type {_registeredTypeNames[attribute.Name]}"); } //Simply store all information in memory, we simply need to initialize latest checkpoint if not reloaded if (!_inMemoryCheckpoint.ContainsKey(attribute.Name)) { AtomicProjectionCheckpoint atomicProjectionCheckpoint = new AtomicProjectionCheckpoint() { Id = attribute.Name, Position = 0 }; _inMemoryCheckpoint.AddOrUpdate(attribute.Name, atomicProjectionCheckpoint, (k, e) => atomicProjectionCheckpoint); } _registeredTypeNames.Add(attribute.Name, atomicAggregateType); }
public AtomicReadmodelProjectorHelper( IAtomicCollectionWrapper <TModel> atomicCollectionWrapper, IAtomicReadModelFactory atomicReadModelFactory, ILiveAtomicReadModelProcessor liveAtomicReadModelProcessor, ILogger logger) { _atomicCollectionWrapper = atomicCollectionWrapper; _atomicReadmodelInfoAttribute = AtomicReadmodelInfoAttribute.GetFrom(typeof(TModel)); _logger = logger; _atomicReadModelFactory = atomicReadModelFactory; _liveAtomicReadModelProcessor = liveAtomicReadModelProcessor; }
/// <summary> /// Register an atomic readmodel and return false if the readmodel is too old to /// be projected, it should be projected by another catchup projection engine. /// </summary> /// <param name="atomicReadmodelType"></param> /// <returns></returns> public AtomicProjectionEngine RegisterAtomicReadModel(Type atomicReadmodelType) { var attribute = AtomicReadmodelInfoAttribute.GetFrom(atomicReadmodelType); var projectionPosition = _atomicProjectionCheckpointManager.GetCheckpoint(attribute.Name); Logger.InfoFormat("Registered atomic readmodel {0} starting from position {1}", attribute.Name, projectionPosition); if (_lastPositionDispatched - projectionPosition > MaximumDifferenceForCatchupPoller) { Logger.InfoFormat("Readmodel {0} was registered in Atomic Projection Engine with catchup poller because it is too old. Last dispatched is {1} but we already dispatched {2}", attribute.Name, projectionPosition, _lastPositionDispatched); AddConsumer(projectionPosition, CatchupPollerId, atomicReadmodelType, attribute); return(this); } //default poller Logger.InfoFormat("Readmodel {0} registered in default poller in Atomic Projection Engine", attribute.Name); AddConsumer(projectionPosition, DefaultPollerId, atomicReadmodelType, attribute); return(this); }
private void AddConsumer(Int64 projectedPosition, Int32 pollerId, Type atomicReadmodelType, AtomicReadmodelInfoAttribute atomicReadmodelInfoAttribute) { //The real starting point is the minimum between actual position and what is already in the dictionary, each poller id should start from //minimum dispatched to avoid missing data. If the poller still was not added, its default value is MaxValue because it is passed to the min //value, so projectedPosition will always win. _pollerStartingPoint[pollerId] = Math.Min(TryGetStartingPoint(pollerId, Int32.MaxValue), projectedPosition); if (!_consumerBlocks.TryGetValue(atomicReadmodelInfoAttribute.AggregateIdType, out List <AtomicDispatchChunkConsumer> atomicReadmodelEventConsumers)) { atomicReadmodelEventConsumers = new List <AtomicDispatchChunkConsumer>(); _consumerBlocks.Add(atomicReadmodelInfoAttribute.AggregateIdType, atomicReadmodelEventConsumers); } //add the consumer if (!atomicReadmodelEventConsumers.Any(_ => _.Consumer.AtomicReadmodelInfoAttribute.Name == atomicReadmodelInfoAttribute.Name)) { var consumer = _atomicReadmodelProjectorHelperFactory.CreateFor(atomicReadmodelType); var atomicConsumer = new AtomicDispatchChunkConsumer(consumer, pollerId); atomicReadmodelEventConsumers.Add(atomicConsumer); } _atomicProjectionCheckpointManager.Register(atomicReadmodelType); }