public TAggregate GetById <TAggregate>(string bucketId, IIdentity id, int versionToLoad) where TAggregate : class, IAggregateEx { //try to acquire a lock on the identity, to minimize risk of ConcurrencyException //do not sleep more than a certain amount of time (avoid some missing dispose). Int32 sleepCount = 0; Boolean lockAcquired = false; while (!(lockAcquired = idSerializerDictionary.TryAdd(id, _identity)) && sleepCount < 100) { //some other thread is accessing that entity. Sleeping is the best choiche, because //the lock will be removed after a save, involving IO. Thread.Sleep(50); sleepCount++; } if (lockAcquired == true) { identityAcquireLock.Add(id); //Debug.WriteLine("Lock acquired [{3}] for identity {0} _identity {1}, stored {2}", id, _identity, idSerializerDictionary[id], lockAcquired); } //else //{ // //Debug.WriteLine("Acquire failed sleepCount = {0}", sleepCount); //} ISnapshot snapshot = this.GetSnapshot <TAggregate>(bucketId, id, versionToLoad); IEventStream stream = this.OpenStream(bucketId, id, versionToLoad, snapshot); IAggregateEx aggregate = this.GetAggregate <TAggregate>(snapshot, stream); ApplyEventsToAggregate(versionToLoad, stream, aggregate); return(aggregate as TAggregate); }
private IEventStream PrepareStream(string bucketId, IAggregateEx aggregate, Dictionary <string, object> headers) { IEventStream stream; var streamsId = bucketId + "@" + aggregate.Id; if (!this._streams.TryGetValue(streamsId, out stream)) { this._streams[streamsId] = stream = this._eventStore.CreateStream(bucketId, aggregate.Id.AsString()); } foreach (var item in headers) { stream.UncommittedHeaders[item.Key] = item.Value; } aggregate.GetUncommittedEvents() .Cast <object>() .Select(x => new EventMessage { Body = x }) .ToList() .ForEach(stream.Add); return(stream); }
public static void ThrowHandlerNotFound(this IAggregateEx aggregate, object eventMessage) { string exceptionMessage = "Aggregate of type '{0}' raised an event of type '{1}' but not handler could be found to handle the message." .FormatWith(aggregate.GetType().Name, eventMessage.GetType().Name); throw new HandlerForDomainEventNotFoundException(exceptionMessage); }
private void AfterSave(IIdentity id, IRepositoryEx repositoryEx, IAggregateEx aggregate) { //store the repository on the cache, actually we are keeping the very //same entity that was disposed by the caller. var cacheEntry = new CacheEntry(repositoryEx, aggregate); Cache.Add(id.AsString(), cacheEntry, _cachePolicy); }
protected void SetupContext(IAggregateEx aggregate) { var context = _currentCommand.AllContextKeys .ToDictionary<string, string, object>( key => key, key => _currentCommand.GetContextData(key) ); context["command.name"] = _currentCommand.GetType().Name; aggregate.EnterContext(context); }
public void Verify_NumberOfCommitsShapshotPersistenceStrategy(Int32 treshold, Int32 version, Int32 numberOfEventsSaved, Boolean expected) { NumberOfCommitsShapshotPersistenceStrategy sut = new NumberOfCommitsShapshotPersistenceStrategy(treshold); IAggregateEx aggregate = NSubstitute.Substitute.For <IAggregateEx>(); aggregate.Version.ReturnsForAnyArgs(version); var result = sut.ShouldSnapshot(aggregate, numberOfEventsSaved); Assert.That(result, Is.EqualTo(expected)); }
private static Dictionary <string, object> PrepareHeaders( IAggregateEx aggregate, Action <IDictionary <string, object> > updateHeaders) { var headers = new Dictionary <string, object>(); headers[AggregateTypeHeader] = aggregate.GetType().FullName; if (updateHeaders != null) { updateHeaders(headers); } return(headers); }
public override void Save(IAggregateEx aggregate, Guid commitId, Action <IDictionary <string, object> > updateHeaders) { var checker = aggregate as IInvariantsChecker; if (checker != null) { var result = checker.CheckInvariants(); if (!result) { throw new InvariantNotSatifiedException(aggregate.Id, result.ErrorMessage); } } Save(GetBucketFor(aggregate), aggregate, commitId, updateHeaders); }
public bool ShouldSnapshot(IAggregateEx aggregate, int numberOfEventsSaved) { //we need to save the aggregate if one of the event number are a multiple of the commit threshold. var actualVersion = aggregate.Version; var oldVersion = actualVersion - numberOfEventsSaved; for (int i = oldVersion + 1; i <= actualVersion; i++) { if (i % _commitsThreshold == 0) { return(true); } } return(false); }
/// <summary> /// /// </summary> /// <param name="bucketId"></param> /// <param name="aggregate"></param> /// <param name="commitId"></param> /// <param name="updateHeaders"></param> /// <returns></returns> public Int32 Save(string bucketId, IAggregateEx aggregate, Guid commitId, Action <IDictionary <string, object> > updateHeaders) { if (_disposed) { throw new ObjectDisposedException("This instance of repository was already disposed"); } Dictionary <string, object> headers = PrepareHeaders(aggregate, updateHeaders); Int32 uncommittedEvents = aggregate.GetUncommittedEvents().Count; while (true) { IEventStream stream = this.PrepareStream(bucketId, aggregate, headers); int commitEventCount = stream.CommittedEvents.Count; try { stream.CommitChanges(commitId); aggregate.ClearUncommittedEvents(); return(uncommittedEvents); } catch (DuplicateCommitException dex) { stream.ClearChanges(); _logger.Debug(String.Format("Duplicate commit exception bucket {0} - id {1} - commitid {2}. \n{3}", bucketId, aggregate.Id, commitId, dex)); return(0); //no events commited } catch (ConcurrencyException e) { _logger.Warn(String.Format("Concurrency Exception bucket {0} - id {1} - commitid {2}. \n{3}", bucketId, aggregate.Id, commitId, e)); if (this.ThrowOnConflict(stream, commitEventCount)) { //@@FIX -> aggiungere prima del lancio dell'eccezione stream.ClearChanges(); throw new ConflictingCommandException(e.Message, e); } stream.ClearChanges(); } catch (StorageException e) { throw new PersistenceException(e.Message, e); } finally { ReleaseAggregateId(aggregate.Id); } } }
public void Snapshot(IAggregateEx aggregate, String bucket, Int32 numberOfEventsSaved) { if (SnapshotsSettings.HasOptedOut(aggregate.GetType())) { return; } var memento = aggregate.GetSnapshot(); var snapshot = new Snapshot(bucket, aggregate.Id.AsString(), aggregate.Version, memento); if (_cacheEnabled) { _cache.Set(aggregate.Id.AsString(), snapshot, _standardCachePolicy); } if (_snapshotPersistenceStrategy.ShouldSnapshot(aggregate, numberOfEventsSaved)) { _persister.Persist(snapshot, aggregate.GetType().FullName); } }
public override Int32 Save(IAggregateEx aggregate, Guid commitId, Action <IDictionary <string, object> > updateHeaders) { var checker = aggregate as IInvariantsChecker; if (checker != null) { var result = checker.CheckInvariants(); if (!result) { throw new InvariantNotSatifiedException(aggregate.Id, result.ErrorMessage); } } var bucketId = GetBucketFor(aggregate); var numOfEvents = Save(bucketId, aggregate, commitId, updateHeaders); //If we reach here we need to check if we want to persiste a snapshot. SnapshotManager.Snapshot(aggregate, bucketId, numOfEvents); return(numOfEvents); }
public TAggregate GetById <TAggregate>(string bucketId, IIdentity id, int versionToLoad) where TAggregate : class, IAggregateEx { if (_disposed) { throw new ObjectDisposedException("This instance of repository was already disposed"); } Stopwatch sw = null; if (NeventStoreExGlobalConfiguration.MetricsEnabled) { sw = Stopwatch.StartNew(); } if (NeventStoreExGlobalConfiguration.RepositoryLockOnAggregateId) { //try to acquire a lock on the identity, to minimize risk of ConcurrencyException //do not sleep more than a certain amount of time (avoid some missing dispose). bool lockAcquired = TryAcquireLock(id); if (lockAcquired == false) { //There is nothing to do if a lock failed to be aquired, but it worth to be signaled. FailedLockCounter.Increment(); } } ISnapshot snapshot = this.GetSnapshot <TAggregate>(bucketId, id, versionToLoad); IEventStream stream = this.OpenStream(bucketId, id, versionToLoad, snapshot); IAggregateEx aggregate = this.GetAggregate <TAggregate>(snapshot, stream); //cache loaded stream to avoid reload during save. _streams[aggregate] = stream; ApplyEventsToAggregate(versionToLoad, stream, aggregate); if (NeventStoreExGlobalConfiguration.MetricsEnabled) { sw.Stop(); RepositoryLoadCounter.Increment(typeof(TAggregate).Name, sw.ElapsedTicks); } return(aggregate as TAggregate); }
public void Save(string bucketId, IAggregateEx aggregate, Guid commitId, Action <IDictionary <string, object> > updateHeaders) { Dictionary <string, object> headers = PrepareHeaders(aggregate, updateHeaders); while (true) { IEventStream stream = this.PrepareStream(bucketId, aggregate, headers); int commitEventCount = stream.CommittedEvents.Count; try { stream.CommitChanges(commitId); aggregate.ClearUncommittedEvents(); return; } catch (DuplicateCommitException) { stream.ClearChanges(); return; } catch (ConcurrencyException e) { if (this.ThrowOnConflict(stream, commitEventCount)) { //@@FIX -> aggiungere prima del lancio dell'eccezione stream.ClearChanges(); throw new ConflictingCommandException(e.Message, e); } stream.ClearChanges(); } catch (StorageException e) { throw new PersistenceException(e.Message, e); } finally { ReleaseAggregateId(aggregate.Id); } } }
public virtual void Register(IAggregateEx aggregate) { if (aggregate == null) { throw new ArgumentNullException("aggregate"); } this.registered = aggregate; // Get instance methods named Apply with one parameter returning void var applyMethods = aggregate.GetType() .GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) .Where( m => m.Name == "Apply" && m.GetParameters().Length == 1 && m.ReturnParameter.ParameterType == typeof(void)) .Select(m => new { Method = m, MessageType = m.GetParameters().Single().ParameterType }); foreach (var apply in applyMethods) { MethodInfo applyMethod = apply.Method; this.handlers.Add(apply.MessageType, m => applyMethod.Invoke(aggregate, new[] { m })); } }
protected static void ClearUncommittedEvents() { IAggregateEx agg = Aggregate; agg.ClearUncommittedEvents(); }
public void Snapshot(IAggregateEx aggregate, String bucket, Int32 numberOfEventsSaved) { }
public bool ShouldSnapshot(IAggregateEx aggregate, int numberOfEventsSaved) { return(false); }
string GetBucketFor(IAggregateEx aggregate) { return(GetBucketFor(aggregate.GetType(), aggregate.Id)); }
public ConventionEventRouterEx(bool throwOnApplyNotFound, IAggregateEx aggregate) : this(throwOnApplyNotFound) { this.Register(aggregate); }
private static void ApplyEventsToAggregate(int versionToLoad, IEventStream stream, IAggregateEx aggregate) { if (versionToLoad == 0 || aggregate.Version < versionToLoad) { foreach (var @event in stream.CommittedEvents.Select(x => x.Body)) { aggregate.ApplyEvent(@event); } } }
public CacheEntry(IRepositoryEx repositoryEx, IAggregateEx aggregate) { RepositoryEx = repositoryEx; Aggregate = aggregate; }
public virtual Int32 Save(IAggregateEx aggregate, Guid commitId, Action <IDictionary <string, object> > updateHeaders) { return(Save(Bucket.Default, aggregate, commitId, updateHeaders)); }