Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FEATURE: Introduce ContentRepositoryMaintainer and restore projection cli commands #5378

Open
wants to merge 23 commits into
base: feature/4746-rework-catchup-mechanism-3
Choose a base branch
from

Conversation

mhsdesign
Copy link
Member

@mhsdesign mhsdesign commented Nov 24, 2024

Adjustments for the subscription engine: #5321

Introduces a dedicated ContentRepositoryMaintainer as replacement for ContentRepository::setUp and the ProjectionService/ ProjectionCatchupService (from 01f7f8f)

The ContentRepositoryMaintainer

Set up and manage a content repository

Initialisation / Tear down

The method `setUp sets up the content repository like event store and projection database tables.
It is non-destructive.

Resetting a content repository with prune method will purge the event stream and reset all projection states.

Staus information

The status of the content repository e.g. if a setup is required or if all subscriptions are active and their position
can be examined with two methods:

The event store status is available via eventStoreStatus, while the subscription status are returned
via subscriptionStatuses. Further documentation in SubscriptionStatuses.

Replay / Catchup of projections

The methods replayProjection, replayAllProjections and catchupProjection
can be leveraged to interact with the projection catchup. In the happy path no interaction is necessary,
as ContentRepository::handle() triggers the projections after applying the events.

For initialising on a new database - which contains events already - a replay will make sure that the projections
are emptied and reapply the events.

The explicit catchup of a projection is only required when adding new projections after installation, of after fixing a projection error.

use Neos\Error\Messages\Error;

/** @api */
class ContentRepositoryMaintainer
{
    public function setUp(): Error|null;
    public function eventStoreStatus(): EventStoreStatus;
    public function subscriptionStatuses(): SubscriptionStatuses;
    public function replaySubscription(SubscriptionId $subscriptionId, \Closure|null $progressCallback = null): Error|null;
    public function replaySubscriptions(\Closure|null $progressCallback = null): Error|null;
    public function retrySubscription(SubscriptionId $subscriptionId, \Closure|null $progressCallback = null): Error|null;
    public function prune(): Error|null;
}

Also a few naming adjustments were made to the original ProjectionStatus introduced via: #4846

The idea was then that a projection could notice that it needs a replay, which is not possible as it would need access to the event store. Also with the subscription status the ProjectionStatus is more of a setup status or schema / migration status and has been renamed to ProjectionSetupStatus.

Furthermore the ProjectionSubscriptionStatus is now a first level concern like the ProjectionSubscriber in theSubscriptionStatusCollection.
If its extended to allow other subscribers another status type should be introduced.

And a special DetachedSubscriptionStatus was added as the projection setup status cannot be calculated and when extending the system to support multiple subscribers, we cannot know their original classification but have to use a special empty placeholder like: DetachedSubscriptionStatus. This also makes the $projectionStatus === null detached case more explicit when using status.

Lastly the lately added method pruneAllWorkspacesAndContentStreamsFromEventStream has been inlined into CR Maintainer

Upgrade instructions

Review instructions

Checklist

  • Code follows the PSR-2 coding style
  • Tests have been created, run and adjusted as needed
  • The PR is created against the lowest maintained branch
  • Reviewer - PR Title is brief but complete and starts with FEATURE|TASK|BUGFIX
  • Reviewer - The first section explains the change briefly for change-logs
  • Reviewer - Breaking Changes are marked with !!! and have upgrade-instructions

…Status`

Like the `ProjectionSubscription` projections subscribers for projections will have an explicit state: `ProjectionSubscriptionStatus`. If its extended to allow other subscribers another status type should be introduced.

replayRequired todo remove we cannot figurea that out in the status after all!
…status cannot be calculated

... and when extending the system to support multiple subscribers, we cannot know their original classification but have to use a special empty placeholder like: `DetachedSubscriptionStatus`

This also makes the `$projectionStatus === null` detached case more explicit when using status.
Under consideration of the new `ProjectionSubscriptionStatus`
@mhsdesign mhsdesign changed the title FEATURE: Introduce ContentRepositoryMaintainer and restore cr:proje… FEATURE: Introduce ContentRepositoryMaintainer and restore projection cli commands Nov 24, 2024
Neos.Neos/Classes/Domain/Service/SiteImportService.php Outdated Show resolved Hide resolved
Comment on lines 30 to 33
/**
* @api
* @internal public API is the {@see ContentRepository::handle()} and the {@see ContentRepositoryMaintainer}
*/
final class SubscriptionEngine
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the ContentRepositoryMaintainer allows us to make the subscription engine internal which is important to be able to extend it and to not expose too many concepts at first.

@kitsunet
Copy link
Member

I mean looks nice and all, but do we really need this?

@mhsdesign mhsdesign marked this pull request as ready for review November 25, 2024 18:36
@mhsdesign
Copy link
Member Author

mhsdesign commented Nov 25, 2024

I fine tuned the catchupProjection behaviour so it throws if setup was not run for the projection.

On the other-hand #4746 (comment) explicitly defines that setup should not reactivate errored projections and not reattach detached projections as well. But thats just how the original inventors did it:

Detached -> must be reactivated / or reset and then catchup (replay)
Error -> must be reactivated / or replay

Current state:

Detached -> must be setup and then catchup / or replay
Error -> must be setup and then catchup / or replay


Maybe it would be really better to say a detached projection MUST be replayed (because the data is probably stale) -> no a reactivate would be better!.

So i thought of this again, instead of offering catchupProjection we have a dedicated reactivateProjection which is a new subscription engine process like https://github.com/patchlevel/event-sourcing/blob/b8591c56b21b049f46bead8e7ab424fd2afe9917/src/Subscription/Engine/DefaultSubscriptionEngine.php#L624

@mhsdesign
Copy link
Member Author

Okay, regarding the naming discussion for the cli commands

so currently in 9.0 this is the feature set:

./flow cr:projectionreplay
./flow cr:projectionreplayall

which i am about to extend with a new command to retry projections in ERROR

./flow cr:projectionreactivate

the thing is do we want to continue using the projection naming here or as startet by Bastian originally use "subscription::

./flow cr:subscriptionreplay
./flow cr:subscriptionreplayall
./flow cr:subscriptionreactivate

(actually his orignal draft was a little different and low level like this:)

./flow cr:subscriptionsreset && ./flow cr:subscriptionscatchup

and to have it all we could just remove the projection suffix, effectively reverting 3c154a0 again:

./flow cr:replay
./flow cr:replayall
./flow cr:reactivate or even ./flow cr:reactivatesubscriber as its not to be used often

The question is for the future: will the projectionreplayall command then only replay the projections or other subscribers as well? Only replaying the projections would leave the others unactivated in which case the intention is maybe too literal. A general replay just to setup things makes sense right?


After discussing this with christian we opted in for option Drölf: Keep the old projection* commands as deprecated and forward them, but introduce a new subscription controller with shorter namings:

./flow subscription:replay
./flow subscription:replayall
./flow subscription:reactivate

Regarding that the maintainer could just expose reset and boot directly, we argued that this leakes to much implementation outwards for now and in case we find this necessary at some point we can still deprecated replayAll in the maintainer service and implement it differently. A replayAll for cli makes definitely sense especially how often it is needed during the betas.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants