Skip to content

Commit

Permalink
Workspace aware simulation
Browse files Browse the repository at this point in the history
  • Loading branch information
kitsunet committed Oct 23, 2024
1 parent 96e58ea commit 31cfcc5
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
use Neos\ContentRepository\Core\ContentRepository;
use Neos\ContentRepository\Core\EventStore\EventNormalizer;
use Neos\ContentRepository\Core\EventStore\EventsToPublish;
use Neos\ContentRepository\Core\Feature\Common\RebasableToOtherWorkspaceInterface;
use Neos\ContentRepository\Core\Projection\ContentGraph\ContentGraphProjectionInterface;
use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName;
use Neos\EventStore\Helper\InMemoryEventStore;
use Neos\EventStore\Model\Event\SequenceNumber;
use Neos\EventStore\Model\Events;
Expand All @@ -35,7 +37,8 @@ public function __construct(
private readonly ContentGraphProjectionInterface $contentRepositoryProjection,
private readonly EventNormalizer $eventNormalizer,
private readonly array $handlers,
private readonly InMemoryEventStore $inMemoryEventStore
private readonly InMemoryEventStore $inMemoryEventStore,
private readonly WorkspaceName $workspaceNameToSimulateIn,
) {
}

Expand All @@ -54,13 +57,24 @@ public function run(\Closure $fn): mixed
}
}

public function handle(CommandInterface $command): void
/**
* Handle a command within a running simulation, otherwise throw.
*
* We will automatically copy given commands to the workspace this simulation
* is running in to ensure consistency in the simulations constraint checks.
*
* @see __construct()
*/
public function handle(RebasableToOtherWorkspaceInterface $command): void
{
if ($this->inSimulation === false) {
throw new \RuntimeException('Simulation is not running');
}

$eventsToPublish = $this->handleCommand($command, $this->commandHandlingDependencies);
// FIXME: Check if workspace already matches and skip this
$commandInWorkspace = $command->createCopyForWorkspace($this->workspaceNameToSimulateIn);

$eventsToPublish = $this->handleCommand($commandInWorkspace, $this->commandHandlingDependencies);

if ($eventsToPublish->events->isEmpty()) {
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,32 +7,34 @@
use Neos\ContentRepository\Core\CommandHandlingDependencies;
use Neos\ContentRepository\Core\EventStore\EventNormalizer;
use Neos\ContentRepository\Core\Projection\ContentGraph\ContentGraphProjectionInterface;
use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName;
use Neos\EventStore\Helper\InMemoryEventStore;

/**
* @internal
*/
final class CommandSimulatorFactory
final readonly class CommandSimulatorFactory
{
/**
* @param array<CommandHandlerInterface> $handlers
*/
public function __construct(
private readonly CommandHandlingDependencies $commandHandlingDependencies,
private readonly ContentGraphProjectionInterface $contentRepositoryProjection,
private readonly EventNormalizer $eventNormalizer,
private readonly array $handlers
private CommandHandlingDependencies $commandHandlingDependencies,
private ContentGraphProjectionInterface $contentRepositoryProjection,
private EventNormalizer $eventNormalizer,
private array $handlers
) {
}

public function createSimulator(): CommandSimulator
public function createSimulator(WorkspaceName $workspaceNameToSimulateIn): CommandSimulator
{
return new CommandSimulator(
$this->commandHandlingDependencies,
$this->contentRepositoryProjection,
$this->eventNormalizer,
$this->handlers,
new InMemoryEventStore()
new InMemoryEventStore(),
$workspaceNameToSimulateIn,
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@
*
* @internal used internally for the rebasing mechanism of content streams
*/
interface RebasableToOtherWorkspaceInterface
interface RebasableToOtherWorkspaceInterface extends CommandInterface
{
public function createCopyForWorkspace(
WorkspaceName $targetWorkspaceName,
): CommandInterface;
): self;

/**
* called during deserialization from metadata
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -394,18 +394,16 @@ private function handleRebaseWorkspace(
return;
}

$commandSimulator = $this->commandSimulatorFactory->createSimulator();
$commandSimulator = $this->commandSimulatorFactory->createSimulator($baseWorkspace->workspaceName);

$commandsThatFailed = $commandSimulator->run(
function () use ($commandSimulator, $originalCommands, $baseWorkspace): CommandsThatFailedDuringRebase {
static function () use ($commandSimulator, $originalCommands): CommandsThatFailedDuringRebase {
$commandsThatFailed = new CommandsThatFailedDuringRebase();
foreach ($originalCommands as $sequenceNumber => $originalCommand) {
// We no longer need to adjust commands as the workspace stays the same
try {
// We rebase here, but we apply the commands in the simulation on the base workspace so the constraint checks work
$commandSimulator->handle($originalCommand->createCopyForWorkspace(
$baseWorkspace->workspaceName
));
$commandSimulator->handle($originalCommand);
// if we came this far, we know the command was applied successfully.
} catch (\Exception $e) {
$commandsThatFailed = $commandsThatFailed->add(
Expand Down Expand Up @@ -558,24 +556,20 @@ private function handlePublishIndividualNodesFromWorkspace(
}

// TODO if $remainingCommands === [] try to do a full publish, but we need to rebase if the workspace is outdated!
$commandSimulator = $this->commandSimulatorFactory->createSimulator();
$commandSimulator = $this->commandSimulatorFactory->createSimulator($baseWorkspace->workspaceName);

try {
// 4) using the new content stream, apply the matching commands
$highestVersionForMatching = $commandSimulator->run(
function () use ($commandSimulator, $matchingCommands, $remainingCommands, $baseWorkspace): SequenceNumber {
static function () use ($commandSimulator, $matchingCommands, $remainingCommands): SequenceNumber {
foreach ($matchingCommands as $matchingCommand) {
$commandSimulator->handle($matchingCommand->createCopyForWorkspace(
$baseWorkspace->workspaceName,
));
$commandSimulator->handle($matchingCommand);
}

$highestVersionForMatching = $commandSimulator->currentSequenceNumber();

foreach ($remainingCommands as $remainingCommand) {
$commandSimulator->handle($remainingCommand->createCopyForWorkspace(
$baseWorkspace->workspaceName,
));
$commandSimulator->handle($remainingCommand);
}

return $highestVersionForMatching;
Expand Down Expand Up @@ -721,16 +715,14 @@ private function handleDiscardIndividualNodesFromWorkspace(
return;
}

$commandSimulator = $this->commandSimulatorFactory->createSimulator();
$commandSimulator = $this->commandSimulatorFactory->createSimulator($baseWorkspace->workspaceName);

// 4) using the new content stream, apply the commands to keep
try {
$commandSimulator->run(
function () use ($commandSimulator, $commandsToKeep, $baseWorkspace): void {
static function () use ($commandSimulator, $commandsToKeep): void {
foreach ($commandsToKeep as $matchingCommand) {
$commandSimulator->handle($matchingCommand->createCopyForWorkspace(
$baseWorkspace->workspaceName,
));
$commandSimulator->handle($matchingCommand);
}
}
);
Expand Down

0 comments on commit 31cfcc5

Please sign in to comment.