예제 #1
0
        public async Task <IReadOnlyCollection <ICommittedDomainEvent> > CommitEventsAsync(
            IIdentity id,
            IReadOnlyCollection <SerializedEvent> serializedEvents,
            CancellationToken cancellationToken)
        {
            using (await _asyncLock.WaitAsync(cancellationToken).ConfigureAwait(false))
            {
                var committedDomainEvents = new List <ICommittedDomainEvent>();

                var aggregatePath = _filesEventLocator.GetEntityPath(id);
                if (!Directory.Exists(aggregatePath))
                {
                    Directory.CreateDirectory(aggregatePath);
                }

                foreach (var serializedEvent in serializedEvents)
                {
                    var eventPath = _filesEventLocator.GetEventPath(id, serializedEvent.AggregateSequenceNumber);
                    _globalSequenceNumber++;
                    _eventLog[_globalSequenceNumber] = eventPath;

                    var fileEventData = new FileEventData
                    {
                        AggregateId             = id.Value,
                        AggregateSequenceNumber = serializedEvent.AggregateSequenceNumber,
                        Data                 = serializedEvent.SerializedData,
                        Metadata             = serializedEvent.SerializedMetadata,
                        GlobalSequenceNumber = _globalSequenceNumber,
                    };

                    var json = _jsonSerializer.Serialize(fileEventData, true);

                    using (var streamWriter = CreateNewTextFile(eventPath, fileEventData))
                    {
                        _log.Verbose("Writing file '{0}'", eventPath);
                        await streamWriter.WriteAsync(json).ConfigureAwait(false);
                    }

                    committedDomainEvents.Add(fileEventData);
                }

                using (var streamWriter = File.CreateText(_logFilePath))
                {
                    _log.Verbose(
                        "Writing global sequence number '{0}' to '{1}'",
                        _globalSequenceNumber,
                        _logFilePath);
                    var json = _jsonSerializer.Serialize(
                        new EventStoreLog
                    {
                        GlobalSequenceNumber = _globalSequenceNumber,
                        Log = _eventLog
                    },
                        true);
                    await streamWriter.WriteAsync(json).ConfigureAwait(false);
                }

                return(committedDomainEvents);
            }
        }
예제 #2
0
        public void UnsyncedWillThrow()
        {
            var fsm = new FileEventStateMachine();

            Assert.Throws <ArgumentOutOfRangeException> (() => fsm.Set("a", 0, 0, false, FileState.Removed));

            // Add a busted FileEventData
            var eventData = new FileEventData {
                Kind = EventDataKind.Changed,
                Args = new FileEventArgs(),
            };

            Assert.Throws <ArgumentOutOfRangeException> (() => fsm.Set("a", 0, 0, false, FileState.Removed));
        }
예제 #3
0
        private StreamWriter CreateNewTextFile(string path, FileEventData fileEventData)
        {
            try
            {
                var stream = new FileStream(path, FileMode.CreateNew);
                return(new StreamWriter(stream));
            }
            catch (IOException)
            {
                if (File.Exists(path))
                {
                    throw new OptimisticConcurrencyException(
                              $"Event {fileEventData.AggregateSequenceNumber} already exists for entity with ID '{fileEventData.AggregateId}'");
                }

                throw;
            }
        }
예제 #4
0
        public void AddAndRemove()
        {
            var fsm = new FileEventStateMachine();

            var eventData = new FileEventData {
                Kind = EventDataKind.Changed,
                Args = new FileEventArgs("a", false),
            };

            fsm.Queue(eventData);

            fsm.Set("a", 0, 0, false, FileState.Removed);
            fsm.RemoveLastEventData("a");

            Assert.IsFalse(fsm.TryGet("a", out var state));

            fsm.RemoveLastEventData("a");
            Assert.IsFalse(fsm.TryGet("a", out state));
        }
예제 #5
0
        public async Task<IReadOnlyCollection<ICommittedDomainEvent>> CommitEventsAsync(IIdentity id, IReadOnlyCollection<SerializedEvent> serializedEvents, CancellationToken cancellationToken)
        {
            using (await _asyncLock.WaitAsync(cancellationToken).ConfigureAwait(false))
            {
                var committedDomainEvents = new List<ICommittedDomainEvent>();

                var aggregatePath = _filesEventLocator.GetEntityPath(id);
                if (!Directory.Exists(aggregatePath))
                {
                    Directory.CreateDirectory(aggregatePath);
                }

                foreach (var serializedEvent in serializedEvents)
                {
                    var eventPath = _filesEventLocator.GetEventPath(id, serializedEvent.AggregateSequenceNumber);
                    _globalSequenceNumber++;
                    _eventLog[_globalSequenceNumber] = eventPath;

                    var fileEventData = new FileEventData
                        {
                            AggregateId = id.Value,
                            AggregateSequenceNumber = serializedEvent.AggregateSequenceNumber,
                            Data = serializedEvent.SerializedData,
                            Metadata = serializedEvent.SerializedMetadata,
                            GlobalSequenceNumber = _globalSequenceNumber,
                        };
            
                    var json = _jsonSerializer.Serialize(fileEventData, true);

                    if (File.Exists(eventPath))
                    {
                        // TODO: This needs to be on file creation
                        throw new OptimisticConcurrencyException(string.Format(
                            "Event {0} already exists for entity with ID '{1}'",
                            fileEventData.AggregateSequenceNumber,
                            id));
                    }

                    using (var streamWriter = File.CreateText(eventPath))
                    {
                        _log.Verbose("Writing file '{0}'", eventPath);
                        await streamWriter.WriteAsync(json).ConfigureAwait(false);
                    }

                    committedDomainEvents.Add(fileEventData);
                }

                using (var streamWriter = File.CreateText(_logFilePath))
                {
                    _log.Verbose(
                        "Writing global sequence number '{0}' to '{1}'",
                        _globalSequenceNumber,
                        _logFilePath);
                    var json = _jsonSerializer.Serialize(
                        new EventStoreLog
                        {
                            GlobalSequenceNumber = _globalSequenceNumber,
                            Log = _eventLog,
                        },
                        true);
                    await streamWriter.WriteAsync(json).ConfigureAwait(false);
                }

                return committedDomainEvents;
            }
        }
예제 #6
0
        protected override async Task <IReadOnlyCollection <ICommittedDomainEvent> > CommitEventsAsync <TAggregate, TIdentity>(
            TIdentity id,
            IReadOnlyCollection <SerializedEvent> serializedEvents,
            CancellationToken cancellationToken)
        {
            using (await _asyncLock.WaitAsync(cancellationToken).ConfigureAwait(false))
            {
                var aggregateType         = typeof(TAggregate);
                var committedDomainEvents = new List <ICommittedDomainEvent>();

                var aggregatePath = GetAggregatePath(aggregateType, id);
                if (!Directory.Exists(aggregatePath))
                {
                    Directory.CreateDirectory(aggregatePath);
                }

                foreach (var serializedEvent in serializedEvents)
                {
                    var eventPath = GetEventPath(aggregateType, id, serializedEvent.AggregateSequenceNumber);
                    _globalSequenceNumber++;
                    _log[_globalSequenceNumber] = eventPath;

                    var fileEventData = new FileEventData
                    {
                        AggregateId             = id.Value,
                        AggregateSequenceNumber = serializedEvent.AggregateSequenceNumber,
                        Data                 = serializedEvent.SerializedData,
                        Metadata             = serializedEvent.SerializedMetadata,
                        GlobalSequenceNumber = _globalSequenceNumber,
                    };

                    var json = _jsonSerializer.Serialize(fileEventData, true);

                    if (File.Exists(eventPath))
                    {
                        // TODO: This needs to be on file creation
                        throw new OptimisticConcurrencyException(string.Format(
                                                                     "Event {0} already exists for aggregate '{1}' with ID '{2}'",
                                                                     fileEventData.AggregateSequenceNumber,
                                                                     aggregateType.Name,
                                                                     id));
                    }

                    using (var streamWriter = File.CreateText(eventPath))
                    {
                        Log.Verbose("Writing file '{0}'", eventPath);
                        await streamWriter.WriteAsync(json).ConfigureAwait(false);
                    }

                    committedDomainEvents.Add(fileEventData);
                }

                using (var streamWriter = File.CreateText(_logFilePath))
                {
                    Log.Verbose(
                        "Writing global sequence number '{0}' to '{1}'",
                        _globalSequenceNumber,
                        _logFilePath);
                    var json = _jsonSerializer.Serialize(
                        new EventStoreLog
                    {
                        GlobalSequenceNumber = _globalSequenceNumber,
                        Log = _log,
                    },
                        true);
                    await streamWriter.WriteAsync(json).ConfigureAwait(false);
                }

                return(committedDomainEvents);
            }
        }
예제 #7
0
        public void Functionality()
        {
            var fsm = new FileEventStateMachine();

            FilePath a = "a", b = "b", c = "c";
            var      eventData = new FileEventData {
                Kind = EventDataKind.Changed,
                Args = new FileEventArgs(new [] { a, b, c }, false),
            };

            fsm.Queue(eventData);

            Assert.AreEqual(false, fsm.TryGet(a, out var state));

            fsm.Set(a, 0, 0, false, FileState.Changed);
            fsm.Set(b, 0, 1, false, FileState.Changed);
            fsm.Set(c, 0, 2, false, FileState.Changed);

            Assert.AreEqual(true, fsm.TryGet(a, out state));
            AssertState(state, FileState.Changed, 1, 0, 0);

            Assert.AreEqual(true, fsm.TryGet(b, out state));
            AssertState(state, FileState.Changed, 1, 0, 1);

            Assert.AreEqual(true, fsm.TryGet(c, out state));
            AssertState(state, FileState.Changed, 1, 0, 2);

            eventData = new FileEventData {
                Kind = EventDataKind.Removed,
                Args = new FileEventArgs(new [] { b, a, c }, false),
            };

            fsm.Queue(eventData);

            fsm.Set(a, 1, 1, false, FileState.Removed);
            fsm.Set(b, 1, 0, false, FileState.Removed);
            fsm.Set(c, 1, 2, false, FileState.Removed);

            Assert.AreEqual(true, fsm.TryGet(a, out state));
            AssertState(state, FileState.Removed, 2, 1, 1);

            Assert.AreEqual(true, fsm.TryGet(b, out state));
            AssertState(state, FileState.Removed, 2, 1, 0);

            Assert.AreEqual(true, fsm.TryGet(c, out state));
            AssertState(state, FileState.Removed, 2, 1, 2);

            fsm.RemoveLastEventData(c);

            Assert.AreEqual(true, fsm.TryGet(a, out state));
            AssertState(state, FileState.Removed, 2, 1, 1);

            Assert.AreEqual(true, fsm.TryGet(b, out state));
            AssertState(state, FileState.Removed, 2, 1, 0);

            Assert.AreEqual(true, fsm.TryGet(c, out state));
            AssertState(state, FileState.Changed, 1, 0, 2);

            fsm.RemoveLastEventData(c);

            Assert.AreEqual(false, fsm.TryGet(c, out state));
            Assert.IsNull(state);

            void AssertState(FileEventState s, FileState fs, int count, int eventIndex, int fileIndex)
            {
                Assert.AreEqual(fs, state.FinalState);
                Assert.AreEqual(count, state.Indices.Count);
                if (count == 0)
                {
                    return;
                }

                Assert.AreEqual(eventIndex, state.Indices [count - 1].EventIndex);
                Assert.AreEqual(fileIndex, state.Indices [count - 1].FileIndex);
            }
        }