Beispiel #1
0
    /// <inheritdoc/>
    public async Task <FilterValidationResult> Validate(TypeFilterWithEventSourcePartitionDefinition persistedDefinition, IFilterProcessor <TypeFilterWithEventSourcePartitionDefinition> filter, StreamPosition lastUnprocessedEvent, CancellationToken cancellationToken)
    {
        try
        {
            var changedEventTypes = GetChangedEventTypes(persistedDefinition, filter.Definition);

            if (EventTypesHaveNotChanged(changedEventTypes))
            {
                return(FilterValidationResult.Succeeded());
            }

            var streamTypesFetcher = await _eventFetchers.GetTypeFetcherFor(
                filter.Scope,
                new EventLogStreamDefinition(),
                cancellationToken).ConfigureAwait(false);

            var typesInSourceStream = await streamTypesFetcher.FetchInRange(
                new StreamPositionRange(StreamPosition.Start, lastUnprocessedEvent),
                cancellationToken).ConfigureAwait(false);

            return(SourceStreamContainsChangedEventTypes(typesInSourceStream, changedEventTypes)
                ? FilterValidationResult.Failed("The new filter definition has added or removed event types that have already been filtered")
                : FilterValidationResult.Succeeded());
        }
        catch (Exception exception)
        {
            return(FilterValidationResult.Failed(exception.Message));
        }
    }
    /// <inheritdoc/>
    public FilterValidationResult DefinitionsAreEqual(IFilterDefinition persisted, IFilterDefinition registered)
    {
        if (persisted.Partitioned != registered.Partitioned)
        {
            return(FilterValidationResult.Failed($"The new stream generated from the filter will not match the old stream. {(persisted.Partitioned ? "The previous filter is partitioned while the new filter is not" : "The previous filter is not partitioned while the new filter is")}"));
        }

        if (persisted.Public != registered.Public)
        {
            return(FilterValidationResult.Failed($"The new stream generated from the filter will not match the old stream. {(persisted.Public ? "The previous filter is public while the new filter is not" : "The previous filter is not public while the new filter is")}"));
        }

        return(FilterValidationResult.Succeeded());
    }
    static bool EventsAreNotEqual(IFilterDefinition filterDefinition, StreamEvent newEvent, StreamEvent oldEvent, out FilterValidationResult failedResult)
    {
        failedResult = default;
        if (newEvent.Event.EventLogSequenceNumber != oldEvent.Event.EventLogSequenceNumber)
        {
            failedResult = FilterValidationResult.Failed($"Event in new stream at position {newEvent.Position} is event {newEvent.Event.EventLogSequenceNumber} while the event in the old stream is event {oldEvent.Event.EventLogSequenceNumber}");
            return(true);
        }

        if (filterDefinition.Partitioned && newEvent.Partition != oldEvent.Partition)
        {
            failedResult = FilterValidationResult.Failed($"Event in new stream at position {newEvent.Position} has is in partition {newEvent.Partition} while the event in the old stream is in partition {oldEvent.Partition}");
            return(true);
        }
        return(false);
    }
Beispiel #4
0
    static bool FilterDefinitionHasBeenPersisted(Try <IFilterDefinition> tryGetFilterDefinition, out IFilterDefinition persistedDefinition, out FilterValidationResult validationResult)
    {
        if (!tryGetFilterDefinition.Success)
        {
            validationResult = tryGetFilterDefinition.Exception is StreamDefinitionDoesNotExist
                ? FilterValidationResult.Succeeded()
                : FilterValidationResult.Failed(tryGetFilterDefinition.Exception.Message);

            persistedDefinition = default;
            return(false);
        }

        persistedDefinition = tryGetFilterDefinition.Result;
        validationResult    = default;
        return(true);
    }
Beispiel #5
0
    /// <inheritdoc/>
    public async Task <FilterValidationResult> Validate <TDefinition>(IFilterProcessor <TDefinition> filter, CancellationToken cancellationToken)
        where TDefinition : IFilterDefinition
    {
        var tryGetProcessorState = await _streamProcessorStates
                                   .TryGetFor(new StreamProcessorId(filter.Scope, filter.Definition.TargetStream.Value, filter.Definition.SourceStream), cancellationToken)
                                   .ConfigureAwait(false);

        if (!StreamProcessorHasProcessedEvents(tryGetProcessorState, out var validationResult, out var lastUnprocessedEvent))
        {
            return(validationResult);
        }

        _logger.TryGetFilterDefinition(filter.Identifier, _tenant);
        var tryGetFilterDefinition = await _filterDefinitions.TryGetFromStream(filter.Scope, filter.Definition.TargetStream, cancellationToken).ConfigureAwait(false);

        if (!FilterDefinitionHasBeenPersisted(tryGetFilterDefinition, out var persistedDefinition, out validationResult))
        {
            _logger.NoPersistedFilterDefinition(filter.Identifier, _tenant);
            return(validationResult);
        }

        var definitionResult = _definitionComparer.DefinitionsAreEqual(persistedDefinition, filter.Definition);

        if (!definitionResult.Success)
        {
            return(definitionResult);
        }

        if (FilterDefinitionTypeHasChanged(persistedDefinition, filter.Definition))
        {
            return(FilterValidationResult.Failed("Filter definition type has changed"));
        }

        _logger.FindingFilterValidator(filter.Identifier);
        if (!TryGetValidatorFor <TDefinition>(out var validator))
        {
            return(FilterValidationResult.Failed($"No available filter validator for type {filter.Definition.GetType()}"));
        }

        _logger.ValidatingFilter(filter.Identifier);
        return(await validator.Validate((TDefinition)persistedDefinition, filter, lastUnprocessedEvent, cancellationToken).ConfigureAwait(false));
    }
Beispiel #6
0
    static bool StreamProcessorHasProcessedEvents(Try <IStreamProcessorState> tryGetState, out FilterValidationResult validationResult, out StreamPosition lastUnprocessedEvent)
    {
        if (!tryGetState.Success)
        {
            validationResult = tryGetState.Exception is StreamProcessorStateDoesNotExist
                ? FilterValidationResult.Succeeded()
                : FilterValidationResult.Failed(tryGetState.Exception.Message);

            lastUnprocessedEvent = default;
            return(false);
        }

        lastUnprocessedEvent = tryGetState.Result.Position;

        if (lastUnprocessedEvent == StreamPosition.Start)
        {
            validationResult = FilterValidationResult.Succeeded();
            return(false);
        }

        validationResult = default;
        return(true);
    }
    async Task <FilterValidationResult> PerformValidation(IFilterProcessor <IFilterDefinition> filter, StreamPosition lastUnprocessedEvent, CancellationToken cancellationToken)
    {
        try
        {
            var streamDefinition       = new StreamDefinition(filter.Definition);
            var oldStreamEventsFetcher = await _eventFetchers.GetRangeFetcherFor(
                filter.Scope,
                streamDefinition,
                cancellationToken).ConfigureAwait(false);

            var eventLogFetcher = await _eventFetchers.GetRangeFetcherFor(
                filter.Scope,
                new EventLogStreamDefinition(),
                cancellationToken).ConfigureAwait(false);

            var oldStream = oldStreamEventsFetcher.FetchRange(
                new StreamPositionRange(StreamPosition.Start, ulong.MaxValue),
                cancellationToken);
            var eventLogStream = eventLogFetcher.FetchRange(new StreamPositionRange(StreamPosition.Start, lastUnprocessedEvent), cancellationToken);
            await using var oldStreamEnumerator = oldStream.GetAsyncEnumerator(cancellationToken);
            var newStreamPosition = 0;
            await foreach (var eventFromEventLog in eventLogStream.WithCancellation(cancellationToken))
            {
                var filteringResult = await filter.Filter(eventFromEventLog.Event, PartitionId.None, filter.Identifier, eventFromEventLog.Event.ExecutionContext, cancellationToken).ConfigureAwait(false);

                if (filteringResult is FailedFiltering failedResult)
                {
                    return(FilterValidationResult.Failed(failedResult.FailureReason));
                }

                if (!filteringResult.IsIncluded)
                {
                    continue;
                }

                if (!await oldStreamEnumerator.MoveNextAsync())
                {
                    return(FilterValidationResult.Failed("The number of events included in the new stream generated from the filter does not match the old stream."));
                }
                var oldStreamEvent = oldStreamEnumerator.Current;
                var filteredEvent  = new StreamEvent(
                    eventFromEventLog.Event,
                    new StreamPosition((ulong)newStreamPosition++),
                    filter.Definition.TargetStream,
                    filteringResult.Partition,
                    streamDefinition.Partitioned);
                if (EventsAreNotEqual(filter.Definition, filteredEvent, oldStreamEvent, out var failedValidation))
                {
                    return(failedValidation);
                }
            }

            if (await oldStreamEnumerator.MoveNextAsync())
            {
                return(FilterValidationResult.Failed($"The number of events included in the new stream generated from the filter does not match the old stream."));
            }

            return(FilterValidationResult.Succeeded());
        }
        catch (Exception exception)
        {
            return(FilterValidationResult.Failed(exception.Message));
        }
    }
Beispiel #8
0
 /// <summary>
 /// Initializes a new instance of the <see cref="FilterRegistrationResult"/> class.
 /// </summary>
 /// <param name="streamProcessor">The <see cref="StreamProcessors" />.</param>
 public FilterRegistrationResult(StreamProcessor streamProcessor)
 {
     StreamProcessor        = streamProcessor;
     FilterValidationResult = FilterValidationResult.Succeeded();
     Success = streamProcessor != default;
 }
Beispiel #9
0
 /// <summary>
 /// Initializes a new instance of the <see cref="FilterRegistrationResult"/> class.
 /// </summary>
 /// <param name="filterValidationResult">The failed <see cref="FilterValidationResult" />.</param>
 public FilterRegistrationResult(FilterValidationResult filterValidationResult)
 {
     FilterValidationResult = filterValidationResult;
 }