diff --git a/Neos.ContentRepository.BehavioralTests/Classes/Command/PerformanceMeasurementService.php b/Neos.ContentRepository.BehavioralTests/Classes/Command/PerformanceMeasurementService.php index ff37b268bce..cc67508bade 100644 --- a/Neos.ContentRepository.BehavioralTests/Classes/Command/PerformanceMeasurementService.php +++ b/Neos.ContentRepository.BehavioralTests/Classes/Command/PerformanceMeasurementService.php @@ -92,7 +92,7 @@ public function createNodesForPerformanceTest(int $nodesPerLevel, int $levels): NodeAggregateClassification::CLASSIFICATION_ROOT, ); - $this->eventPersister->publishEvents(new EventsToPublish( + $this->eventPersister->publishEvents($this->contentRepository, new EventsToPublish( $this->contentStreamEventStream->getEventStreamName(), Events::with($rootNodeAggregateWasCreated), ExpectedVersion::ANY() @@ -102,7 +102,7 @@ public function createNodesForPerformanceTest(int $nodesPerLevel, int $levels): $sumSoFar = 0; $events = []; $this->createHierarchy($rootNodeAggregateId, 1, $levels, $nodesPerLevel, $sumSoFar, $events); - $this->eventPersister->publishEvents(new EventsToPublish( + $this->eventPersister->publishEvents($this->contentRepository, new EventsToPublish( $this->contentStreamEventStream->getEventStreamName(), Events::fromArray($events), ExpectedVersion::ANY() diff --git a/Neos.ContentRepository.BehavioralTests/Classes/ProjectionRaceConditionTester/RaceTrackerCatchUpHook.php b/Neos.ContentRepository.BehavioralTests/Classes/ProjectionRaceConditionTester/RaceTrackerCatchUpHook.php index 3309f99d17d..039156ef9da 100644 --- a/Neos.ContentRepository.BehavioralTests/Classes/ProjectionRaceConditionTester/RaceTrackerCatchUpHook.php +++ b/Neos.ContentRepository.BehavioralTests/Classes/ProjectionRaceConditionTester/RaceTrackerCatchUpHook.php @@ -18,7 +18,6 @@ use Neos\ContentRepository\BehavioralTests\ProjectionRaceConditionTester\Dto\TraceEntryType; use Neos\ContentRepository\Core\EventStore\EventInterface; use Neos\ContentRepository\Core\Projection\CatchUpHookInterface; -use Neos\ContentRepositoryRegistry\Factory\ProjectionCatchUpTrigger\SubprocessProjectionCatchUpTrigger; use Neos\EventStore\Model\EventEnvelope; use Neos\Flow\Annotations as Flow; diff --git a/Neos.ContentRepository.Core/Classes/CommandHandler/PendingProjections.php b/Neos.ContentRepository.Core/Classes/CommandHandler/PendingProjections.php deleted file mode 100644 index 9a96085efe1..00000000000 --- a/Neos.ContentRepository.Core/Classes/CommandHandler/PendingProjections.php +++ /dev/null @@ -1,133 +0,0 @@ -> $projections - * @param array $sequenceNumberPerProjection - */ - public function __construct( - public Projections $projections, - private array $sequenceNumberPerProjection, - ) { - } - - public static function empty(): self - { - return new self(Projections::empty(), []); - } - - public static function fromProjectionsAndEventsAndSequenceNumber( - Projections $allProjections, - Events $events, - SequenceNumber $highestCommittedSequenceNumber - ): self { - $sequenceNumberInteger = $highestCommittedSequenceNumber->value - $events->count() + 1; - $pendingProjectionsArray = []; - $sequenceNumberPerProjection = []; - foreach ($events as $event) { - if ($event instanceof DecoratedEvent) { - $event = $event->innerEvent; - } - foreach ($allProjections as $projection) { - if ($projection->canHandle($event)) { - $sequenceNumberPerProjection[$projection::class] = $sequenceNumberInteger; - if (!in_array($projection, $pendingProjectionsArray, true)) { - $pendingProjectionsArray[] = $projection; - } - } - } - $sequenceNumberInteger++; - } - return new self(Projections::fromArray($pendingProjectionsArray), $sequenceNumberPerProjection); - } - - /** - * @param ProjectionInterface $projection - * @return SequenceNumber - */ - public function getExpectedSequenceNumber(ProjectionInterface $projection): SequenceNumber - { - if (!array_key_exists($projection::class, $this->sequenceNumberPerProjection)) { - throw new \InvalidArgumentException( - sprintf('Projection of class "%s" is not pending', $projection::class), - 1652252976 - ); - } - return SequenceNumber::fromInteger($this->sequenceNumberPerProjection[$projection::class]); - } -} diff --git a/Neos.ContentRepository.Core/Classes/CommandHandlingDependencies.php b/Neos.ContentRepository.Core/Classes/CommandHandlingDependencies.php index 1af544bd7af..725022f02e7 100644 --- a/Neos.ContentRepository.Core/Classes/CommandHandlingDependencies.php +++ b/Neos.ContentRepository.Core/Classes/CommandHandlingDependencies.php @@ -37,8 +37,9 @@ final class CommandHandlingDependencies */ private array $overriddenContentGraphInstances = []; - public function __construct(private readonly ContentRepository $contentRepository) - { + public function __construct( + private readonly ContentRepository $contentRepository + ) { } public function handle(CommandInterface $command): void @@ -110,4 +111,12 @@ public function overrideContentStreamId(WorkspaceName $workspaceName, ContentStr unset($this->overriddenContentGraphInstances[$workspaceName->value]); } } + + /** + * Fixme only required to build the possible catchup hooks + */ + public function getContentRepository(): ContentRepository + { + return $this->contentRepository; + } } diff --git a/Neos.ContentRepository.Core/Classes/ContentRepository.php b/Neos.ContentRepository.Core/Classes/ContentRepository.php index 8acc2822673..0f4fa64fcf1 100644 --- a/Neos.ContentRepository.Core/Classes/ContentRepository.php +++ b/Neos.ContentRepository.Core/Classes/ContentRepository.php @@ -130,7 +130,7 @@ public function handle(CommandInterface $command): void $eventsToPublish->expectedVersion, ); - $this->eventPersister->publishEvents($eventsToPublish); + $this->eventPersister->publishEvents($this, $eventsToPublish); } @@ -199,6 +199,15 @@ public function catchUpProjection(string $projectionClassName, CatchUpOptions $o $catchUpHook?->onAfterCatchUp(); } + public function catchupProjections(): void + { + foreach ($this->projectionsAndCatchUpHooks->projections as $projection) { + // FIXME optimise by only loading required events once and not per projection + // see https://github.com/neos/neos-development-collection/pull/4988/ + $this->catchUpProjection($projection::class, CatchUpOptions::create()); + } + } + public function setUp(): void { $this->eventStore->setup(); diff --git a/Neos.ContentRepository.Core/Classes/EventStore/EventPersister.php b/Neos.ContentRepository.Core/Classes/EventStore/EventPersister.php index 5823dee1ed5..7c53549dac8 100644 --- a/Neos.ContentRepository.Core/Classes/EventStore/EventPersister.php +++ b/Neos.ContentRepository.Core/Classes/EventStore/EventPersister.php @@ -4,9 +4,7 @@ namespace Neos\ContentRepository\Core\EventStore; -use Neos\ContentRepository\Core\CommandHandler\PendingProjections; -use Neos\ContentRepository\Core\Projection\ProjectionCatchUpTriggerInterface; -use Neos\ContentRepository\Core\Projection\Projections; +use Neos\ContentRepository\Core\ContentRepository; use Neos\EventStore\EventStoreInterface; use Neos\EventStore\Exception\ConcurrencyException; use Neos\EventStore\Model\Events; @@ -21,9 +19,7 @@ { public function __construct( private EventStoreInterface $eventStore, - private ProjectionCatchUpTriggerInterface $projectionCatchUpTrigger, private EventNormalizer $eventNormalizer, - private Projections $projections, ) { } @@ -31,7 +27,7 @@ public function __construct( * @param EventsToPublish $eventsToPublish * @throws ConcurrencyException in case the expectedVersion does not match */ - public function publishEvents(EventsToPublish $eventsToPublish): void + public function publishEvents(ContentRepository $contentRepository, EventsToPublish $eventsToPublish): void { if ($eventsToPublish->events->isEmpty()) { return; @@ -41,20 +37,12 @@ public function publishEvents(EventsToPublish $eventsToPublish): void $normalizedEvents = Events::fromArray( $eventsToPublish->events->map($this->eventNormalizer->normalize(...)) ); - $commitResult = $this->eventStore->commit( + $this->eventStore->commit( $eventsToPublish->streamName, $normalizedEvents, $eventsToPublish->expectedVersion ); - // for performance reasons, we do not want to update ALL projections all the time; but instead only - // the projections which are interested in the events from above. - // Further details can be found in the docs of PendingProjections. - $pendingProjections = PendingProjections::fromProjectionsAndEventsAndSequenceNumber( - $this->projections, - $eventsToPublish->events, - $commitResult->highestCommittedSequenceNumber - ); - $this->projectionCatchUpTrigger->triggerCatchUp($pendingProjections->projections); + $contentRepository->catchUpProjections(); } } diff --git a/Neos.ContentRepository.Core/Classes/Factory/ContentRepositoryFactory.php b/Neos.ContentRepository.Core/Classes/Factory/ContentRepositoryFactory.php index bba7d784579..94f734c3911 100644 --- a/Neos.ContentRepository.Core/Classes/Factory/ContentRepositoryFactory.php +++ b/Neos.ContentRepository.Core/Classes/Factory/ContentRepositoryFactory.php @@ -28,7 +28,6 @@ use Neos\ContentRepository\Core\Feature\WorkspaceCommandHandler; use Neos\ContentRepository\Core\Infrastructure\Property\PropertyConverter; use Neos\ContentRepository\Core\NodeType\NodeTypeManager; -use Neos\ContentRepository\Core\Projection\ProjectionCatchUpTriggerInterface; use Neos\ContentRepository\Core\Projection\ProjectionsAndCatchUpHooks; use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId; use Neos\ContentRepository\Core\SharedModel\User\UserIdProviderInterface; @@ -53,7 +52,6 @@ public function __construct( ContentDimensionSourceInterface $contentDimensionSource, Serializer $propertySerializer, ProjectionsAndCatchUpHooksFactory $projectionsAndCatchUpHooksFactory, - private readonly ProjectionCatchUpTriggerInterface $projectionCatchUpTrigger, private readonly UserIdProviderInterface $userIdProvider, private readonly ClockInterface $clock, ) { @@ -166,9 +164,7 @@ private function buildEventPersister(): EventPersister if (!$this->eventPersister) { $this->eventPersister = new EventPersister( $this->projectionFactoryDependencies->eventStore, - $this->projectionCatchUpTrigger, $this->projectionFactoryDependencies->eventNormalizer, - $this->projectionsAndCatchUpHooks->projections, ); } return $this->eventPersister; diff --git a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceCommandHandler.php b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceCommandHandler.php index 1b973751081..1851a976560 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceCommandHandler.php +++ b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceCommandHandler.php @@ -201,6 +201,7 @@ private function handlePublishWorkspace( $baseWorkspace = $this->requireBaseWorkspace($workspace, $commandHandlingDependencies); $this->publishContentStream( + $commandHandlingDependencies, $workspace->currentContentStreamId, $baseWorkspace->workspaceName, $baseWorkspace->currentContentStreamId @@ -237,6 +238,7 @@ private function handlePublishWorkspace( * @throws \Exception */ private function publishContentStream( + CommandHandlingDependencies $commandHandlingDependencies, ContentStreamId $contentStreamId, WorkspaceName $baseWorkspaceName, ContentStreamId $baseContentStreamId, @@ -289,6 +291,7 @@ private function publishContentStream( } try { $this->eventPersister->publishEvents( + $commandHandlingDependencies->getContentRepository(), new EventsToPublish( $baseWorkspaceContentStreamName->getEventStreamName(), Events::fromArray($events), @@ -500,6 +503,7 @@ function () use ($matchingCommands, $commandHandlingDependencies, $baseWorkspace // 5) take EVENTS(MATCHING) and apply them to base WS. $this->publishContentStream( + $commandHandlingDependencies, $command->contentStreamIdForMatchingPart, $baseWorkspace->workspaceName, $baseWorkspace->currentContentStreamId diff --git a/Neos.ContentRepository.Core/Classes/Projection/ProjectionCatchUpTriggerInterface.php b/Neos.ContentRepository.Core/Classes/Projection/ProjectionCatchUpTriggerInterface.php deleted file mode 100644 index 1fb20d34cbe..00000000000 --- a/Neos.ContentRepository.Core/Classes/Projection/ProjectionCatchUpTriggerInterface.php +++ /dev/null @@ -1,20 +0,0 @@ -remediation; $eventsToPublish = $remediation(); assert($eventsToPublish instanceof EventsToPublish); - $this->eventPersister->publishEvents($eventsToPublish); + $this->eventPersister->publishEvents($this->contentRepository, $eventsToPublish); } } } diff --git a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/GenericCommandExecutionAndEventPublication.php b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/GenericCommandExecutionAndEventPublication.php index c8e2118d5e4..bc49c4c9e37 100644 --- a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/GenericCommandExecutionAndEventPublication.php +++ b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/GenericCommandExecutionAndEventPublication.php @@ -140,7 +140,7 @@ protected function publishEvent(string $eventType, StreamName $streamName, array ->getValue($eventPersister); $event = $eventNormalizer->denormalize($artificiallyConstructedEvent); - $eventPersister->publishEvents(new EventsToPublish( + $eventPersister->publishEvents($this->currentContentRepository, new EventsToPublish( $streamName, Events::with($event), ExpectedVersion::ANY() diff --git a/Neos.ContentRepositoryRegistry/Classes/Command/SubprocessProjectionCatchUpCommandController.php b/Neos.ContentRepositoryRegistry/Classes/Command/SubprocessProjectionCatchUpCommandController.php deleted file mode 100644 index 6905c28646c..00000000000 --- a/Neos.ContentRepositoryRegistry/Classes/Command/SubprocessProjectionCatchUpCommandController.php +++ /dev/null @@ -1,37 +0,0 @@ -> $projectionClassName fully qualified class name of the projection to catch up - * @internal - */ - public function catchupCommand(string $contentRepository, string $projectionClassName): void - { - $contentRepositoryInstance = $this->contentRepositoryRegistry->get(ContentRepositoryId::fromString($contentRepository)); - $contentRepositoryInstance->catchUpProjection($projectionClassName, CatchUpOptions::create()); - } -} diff --git a/Neos.ContentRepositoryRegistry/Classes/ContentRepositoryRegistry.php b/Neos.ContentRepositoryRegistry/Classes/ContentRepositoryRegistry.php index b65f66004a2..a97a126b08c 100644 --- a/Neos.ContentRepositoryRegistry/Classes/ContentRepositoryRegistry.php +++ b/Neos.ContentRepositoryRegistry/Classes/ContentRepositoryRegistry.php @@ -14,7 +14,6 @@ use Neos\ContentRepository\Core\Projection\CatchUpHookFactoryInterface; use Neos\ContentRepository\Core\Projection\ContentGraph\ContentSubgraphInterface; use Neos\ContentRepository\Core\Projection\ContentGraph\Node; -use Neos\ContentRepository\Core\Projection\ProjectionCatchUpTriggerInterface; use Neos\ContentRepository\Core\Projection\ProjectionFactoryInterface; use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId; use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryIds; @@ -25,7 +24,6 @@ use Neos\ContentRepositoryRegistry\Factory\ContentDimensionSource\ContentDimensionSourceFactoryInterface; use Neos\ContentRepositoryRegistry\Factory\EventStore\EventStoreFactoryInterface; use Neos\ContentRepositoryRegistry\Factory\NodeTypeManager\NodeTypeManagerFactoryInterface; -use Neos\ContentRepositoryRegistry\Factory\ProjectionCatchUpTrigger\ProjectionCatchUpTriggerFactoryInterface; use Neos\ContentRepositoryRegistry\Factory\UserIdProvider\UserIdProviderFactoryInterface; use Neos\ContentRepositoryRegistry\SubgraphCachingInMemory\ContentSubgraphWithRuntimeCaches; use Neos\ContentRepositoryRegistry\SubgraphCachingInMemory\SubgraphCachePool; @@ -174,7 +172,6 @@ private function buildFactory(ContentRepositoryId $contentRepositoryId): Content $this->buildContentDimensionSource($contentRepositoryId, $contentRepositorySettings), $this->buildPropertySerializer($contentRepositoryId, $contentRepositorySettings), $this->buildProjectionsFactory($contentRepositoryId, $contentRepositorySettings), - $this->buildProjectionCatchUpTrigger($contentRepositoryId, $contentRepositorySettings), $this->buildUserIdProvider($contentRepositoryId, $contentRepositorySettings), $clock ); @@ -267,17 +264,6 @@ private function buildProjectionsFactory(ContentRepositoryId $contentRepositoryI return $projectionsFactory; } - /** @param array $contentRepositorySettings */ - private function buildProjectionCatchUpTrigger(ContentRepositoryId $contentRepositoryId, array $contentRepositorySettings): ProjectionCatchUpTriggerInterface - { - isset($contentRepositorySettings['projectionCatchUpTrigger']['factoryObjectName']) || throw InvalidConfigurationException::fromMessage('Content repository "%s" does not have projectionCatchUpTrigger.factoryObjectName configured.', $contentRepositoryId->value); - $projectionCatchUpTriggerFactory = $this->objectManager->get($contentRepositorySettings['projectionCatchUpTrigger']['factoryObjectName']); - if (!$projectionCatchUpTriggerFactory instanceof ProjectionCatchUpTriggerFactoryInterface) { - throw InvalidConfigurationException::fromMessage('projectionCatchUpTrigger.factoryObjectName for content repository "%s" is not an instance of %s but %s.', $contentRepositoryId->value, ProjectionCatchUpTriggerFactoryInterface::class, get_debug_type($projectionCatchUpTriggerFactory)); - } - return $projectionCatchUpTriggerFactory->build($contentRepositoryId, $contentRepositorySettings['projectionCatchUpTrigger']['options'] ?? []); - } - /** @param array $contentRepositorySettings */ private function buildUserIdProvider(ContentRepositoryId $contentRepositoryId, array $contentRepositorySettings): UserIdProviderInterface { diff --git a/Neos.ContentRepositoryRegistry/Classes/Factory/ProjectionCatchUpTrigger/CatchUpTriggerWithSynchronousOption.php b/Neos.ContentRepositoryRegistry/Classes/Factory/ProjectionCatchUpTrigger/CatchUpTriggerWithSynchronousOption.php deleted file mode 100644 index d6b5342d1e9..00000000000 --- a/Neos.ContentRepositoryRegistry/Classes/Factory/ProjectionCatchUpTrigger/CatchUpTriggerWithSynchronousOption.php +++ /dev/null @@ -1,79 +0,0 @@ -contentRepositoryRegistry->get($this->contentRepositoryId); - foreach ($projections as $projection) { - $projectionClassName = get_class($projection); - $contentRepository->catchUpProjection($projectionClassName, CatchUpOptions::create()); - } - } else { - $this->inner->triggerCatchUp($projections); - } - } -} diff --git a/Neos.ContentRepositoryRegistry/Classes/Factory/ProjectionCatchUpTrigger/ProjectionCatchUpTriggerFactoryInterface.php b/Neos.ContentRepositoryRegistry/Classes/Factory/ProjectionCatchUpTrigger/ProjectionCatchUpTriggerFactoryInterface.php deleted file mode 100644 index 5f73b1859ad..00000000000 --- a/Neos.ContentRepositoryRegistry/Classes/Factory/ProjectionCatchUpTrigger/ProjectionCatchUpTriggerFactoryInterface.php +++ /dev/null @@ -1,12 +0,0 @@ - $options */ - public function build(ContentRepositoryId $contentRepositoryId, array $options): ProjectionCatchUpTriggerInterface; -} diff --git a/Neos.ContentRepositoryRegistry/Classes/Factory/ProjectionCatchUpTrigger/SubprocessProjectionCatchUpTrigger.php b/Neos.ContentRepositoryRegistry/Classes/Factory/ProjectionCatchUpTrigger/SubprocessProjectionCatchUpTrigger.php deleted file mode 100644 index f72541368a4..00000000000 --- a/Neos.ContentRepositoryRegistry/Classes/Factory/ProjectionCatchUpTrigger/SubprocessProjectionCatchUpTrigger.php +++ /dev/null @@ -1,43 +0,0 @@ - - */ - protected $flowSettings; - - public function __construct( - private readonly ContentRepositoryId $contentRepositoryId - ) { - } - - public function triggerCatchUp(Projections $projections): void - { - // modelled after https://github.com/neos/Neos.EventSourcing/blob/master/Classes/EventPublisher/JobQueueEventPublisher.php#L103 - // and https://github.com/Flowpack/jobqueue-common/blob/master/Classes/Queue/FakeQueue.php - foreach ($projections as $projection) { - Scripts::executeCommandAsync( - 'neos.contentrepositoryregistry:subprocessprojectioncatchup:catchup', - $this->flowSettings, - [ - 'contentRepositoryIdentifier' => $this->contentRepositoryId->value, - 'projectionClassName' => get_class($projection) - ] - ); - } - } -} diff --git a/Neos.ContentRepositoryRegistry/Classes/Factory/ProjectionCatchUpTrigger/SubprocessProjectionCatchUpTriggerFactory.php b/Neos.ContentRepositoryRegistry/Classes/Factory/ProjectionCatchUpTrigger/SubprocessProjectionCatchUpTriggerFactory.php deleted file mode 100644 index 8695f517d82..00000000000 --- a/Neos.ContentRepositoryRegistry/Classes/Factory/ProjectionCatchUpTrigger/SubprocessProjectionCatchUpTriggerFactory.php +++ /dev/null @@ -1,22 +0,0 @@ - $options */ - public function build(ContentRepositoryId $contentRepositoryId, array $options): ProjectionCatchUpTriggerInterface - { - return new CatchUpTriggerWithSynchronousOption( - $contentRepositoryId, - new SubprocessProjectionCatchUpTrigger($contentRepositoryId) - ); - } -} diff --git a/Neos.ContentRepositoryRegistry/Configuration/Settings.yaml b/Neos.ContentRepositoryRegistry/Configuration/Settings.yaml index 44e28699641..87f26a8c811 100644 --- a/Neos.ContentRepositoryRegistry/Configuration/Settings.yaml +++ b/Neos.ContentRepositoryRegistry/Configuration/Settings.yaml @@ -31,9 +31,6 @@ Neos: contentDimensionSource: factoryObjectName: Neos\ContentRepositoryRegistry\Factory\ContentDimensionSource\ConfigurationBasedContentDimensionSourceFactory - projectionCatchUpTrigger: - factoryObjectName: Neos\ContentRepositoryRegistry\Factory\ProjectionCatchUpTrigger\SubprocessProjectionCatchUpTriggerFactory - userIdProvider: factoryObjectName: Neos\ContentRepositoryRegistry\Factory\UserIdProvider\StaticUserIdProviderFactory diff --git a/Neos.Neos/Classes/Fusion/Cache/GraphProjectorCatchUpHookForCacheFlushing.php b/Neos.Neos/Classes/Fusion/Cache/GraphProjectorCatchUpHookForCacheFlushing.php index e3e8bcfe461..19ffd145d04 100644 --- a/Neos.Neos/Classes/Fusion/Cache/GraphProjectorCatchUpHookForCacheFlushing.php +++ b/Neos.Neos/Classes/Fusion/Cache/GraphProjectorCatchUpHookForCacheFlushing.php @@ -49,9 +49,7 @@ * is not needed: * * By calling {@see self::disabled(\Closure)} in your code, all projection updates - * will never trigger catch up hooks. This will only work when - * {@see CatchUpTriggerWithSynchronousOption::synchronously()} is called, - * as otherwise this subprocess won't be called. + * will never trigger catch up hooks. * * * projection update