silverstripe / silverstripe-framework

Silverstripe Framework, the MVC framework that powers Silverstripe CMS
https://www.silverstripe.org
BSD 3-Clause "New" or "Revised" License
721 stars 821 forks source link

RFC: Better events/tasks for deployment automation (dev/build++), may include event-dispatcher being a core dependency #9688

Open sminnee opened 4 years ago

sminnee commented 4 years ago

Right now we have dev/build as a critical part of the a production deployment.

That's great, but it's incomplete. In particular, it is inappropriate to call this multiple times on a multi-server environment.

It would be helpful if there were a broader range of points to hook into the deployment pipeline, such as:

This would mean

An obvious choice for these hooks would be build tasks. But @unclecheese's work with event-dispatch might also be good base for this.

So the questions are:

Do we want event-dispatcher in core?

If we used event-dispatcher for this, it will make it a core dependency. Are we ready for that?

sminnee commented 4 years ago

For the "what hooks do we want" it would be good to hear from people who are more focused on server-setup and deployment.

chillu commented 4 years ago

Agree this is a good idea, and it paves the way for more deterministic cache creation over time. I think ?flush=1 and ?flush=all have basically broken dev's mental models about what cache is invalidated when over the years. I could not tell you if you still need a dev/build/?flush=1 right now without looking up some intricate use cases, and I'm not 100% sure if ?flush=all still does something different than ?flush=1. It's just gotten so confusing over the years that (like everyone else) I'm doing "superstitious flushes", rather than based on sound understanding of caching. That's quite different to e.g. Laravel's caching, which is basically "no caching in dev, generate caches through tasks during deployment". So I think if we're introducing something like this, it needs to be accompanied with a "caching overview" and a "deployment guide" in our docs.

I'd say BuildTask, but extensible via event-dispatch rather than Extension based. No strong feelings about other points.

unclecheese commented 4 years ago

I love the idea of adding more reactive programming paradigms to the framework, but we're essentially saying the event-dispatcher module becomes a core dependency if we go that route. Have we thought all of that through? Might need a separate RFC.

sminnee commented 4 years ago

I'd say BuildTask, but extensible via event-dispatch rather than Extension based.

Do you mean a build task that basically just goes Dispatcher::dispatch($someEvent)? I could roll with that

I love the idea of adding more reactive programming paradigms to the framework, but we're essentially saying the event-dispatcher module becomes a core dependency if we go that route. Have we thought all of that through?

I'll change the heading of this instead ;)

unclecheese commented 4 years ago

prepares to scratch "write a core module" off bucket list

sminnee commented 4 years ago

Assuming we use event-dispatch for extensibility, which I believe is everyone's preference, I think the main choice is:

robbieaverill commented 4 years ago

I'm not familiar with the event dispatcher module, would someone mind giving a quick summary of how it would solve the problems in this RFC?

sminnee commented 4 years ago

This module in question was https://github.com/silverstripe/silverstripe-event-dispatcher which was originally developed while working on versioned-snapshots.

It's based on Symfony's event system and lets you attach event listeners to a central dispatch service. Notably, listeners are attached to the central dispatch rather than individual objects. This makes it well suited to helping loosely coupled subsystems interact, but less well-suited to connecting the internals of cohesive code within a subsystem. (This is why we opted not to use it for the add/remove callback feature)

For this case you could dispatch events for the various steps in the build cycle. So rather than creating a build task. The event dispatcher provides a way of ensuring that any number of calls can be added to a single extension point.

Triggering an event requires a PHP call, so a simple wrapper would be 1 or more build tasks that do nothing other than trigger the event in question. This could also be a dedicated CLI script, but presenting as a build task probably makes it more findable for Silverstripe devs.

Without event dispatch, you'd probably need a way to, for example, group together a bunch of build tasks and execute them all at once, letting developers add tasks to the pre-existing groups as desired. That's something that event dispatch gives us for free, but if we brought it in solely for this use-case, it'd be a bit weird. So the question is really "would event dispatch be a useful pattern to have in the system" which to me seems like a good idea. I think this was why Aaron initially said "should this be a separate RFC" but I wanted to avoid ticket fragmentation.

As an example of its use, in the case of versioned snapshots, https://github.com/silverstripe/silverstripe-cms-events/ provides a bunch of events around interaction with your content manual that is slightly less granular than individual ORM operations and closer to "individual human button-clicks", while also covering cases such as GraphQL.

One thing that I'm not sure event-dispatch gives us is the ability to tweak the order of the event handlers. This is a bit of a minefield and it's probable that the are better ways of dealing with order-dependency. For example, we could get in the habit of having critical build steps trigger their own before/after events, and developers could attach listeners to those events instead of the parent step. But it needs thought.

chillu commented 3 years ago

@silverstripe/core-team We're moving along the path of core inclusion of silverstripe/cms-events with this new GraphQL v4 PR: https://github.com/silverstripe/silverstripe-graphql/pull/352. GraphQL v4 isn't stable yet, and not required by the core recipe. Once we do that, we'll also take on maintenance of silverstripe/cms-events (as well as a new Symfony dependency). Even with GraphQL v4 stable, I don't believe we need to call silverstripe/cms-events stable, but it should have beta releases. Notably according to our definition of a beta release, while they're targeted at bugfixes we can still change APIs.

Three core committers think that an event dispatcher in core is a good idea in general. Where we struggled before is actually rolling out such a change consistently.

Just for completeness, here's a few unresolved discussion points. Some of those might influence this RFC (given we don't want to split the deployment events from event listener), some of them might become tickets on the module.

unclecheese commented 3 years ago

Quick point of clarification here -- we're not making cms-events a dependency. We're making silverstripe/event-dispathcer a dependency.

The dispatcher provides the backend, and cms-events provides the subscribers to specific events (currently required only by versioned-snapshots).