Note: This is issue is part of #2721129: Workflow Initiative and is only meant for planning and governance sign-offs. Work will happen in child issues of this plan.
Target version: Drupal 8.7+
This phase intend to extend the work done in #2732071: WI: Workspace module roadmap by introducing a richer replication API with conflict management.
Initial plan for a plugin framework: #2688567: Co-maintaining Conflict module for Drupal 8 Assigned to: drumm
The merge algorithms needed will use lots of work from this Google Summer of Code project: Solving content conflicts with merge algorithms in Drupal 8. This project resulted in these very useful libraries:
Existing and related issues in core:
See the Replication, Conflict and Workspace modules for the current reference implementation in contrib.
| Comment | File | Size | Author |
|---|---|---|---|
| #33 | interdiff.2867707.32-33.txt | 1.12 KB | pmelab |
| #33 | 2867707-33.drupal.WI-Phase-H-Conflict-management-and-local-workspace-merging-support.patch | 41.73 KB | pmelab |
| #32 | conflict_api-2867707-1.patch | 41.72 KB | pmelab |
Comments
Comment #2
dixon_Comment #6
amateescu commentedComment #7
webchickWe're a little past 8.5 at this point, so changing the target version in the issue summary. :)
When the Workflow roadmap was run past core committers last week, the feedback was that what's desired, at least as an "MVP" here, is a conflict detection mechanism, which can stop a user from making irreversible data loss mistakes. But the full shebang of conflict resolution system could come later.
Comment #8
amateescu commented@webchick, Workspaces already provides a conflict detection mechanism, with a constraint validator and a form alter which displays a message instead of showing the entity form if that entity has been edited in a different workspace.
Or do you mean something more like the conflict detection mechanism used by d.o for project issue nodes?
Comment #9
hchonovI've moved the Conflict module forward, but some help for the UI is still welcome :).
I had a session about it at Drupal Europe - https://www.youtube.com/watch?v=ixlLskzT9c4 , which is worth watching to see the current pretty advanced state of the module.
Comment #10
hchonovAs a summary - it currently detects changes and conflicts and performs auto-merges wherever possible. If an auto-merge is impossible, which is considered a conflict, then the form with an overview of each conflict is returned to the user.
Comment #11
plach@amateescu and I started to discuss how to structure the core bits of this functionality so that it is not too opinionated and leaves contrib the ability to freely implement it without core getting in the way. The main takeaway point for core is that we want to provide conflict management without an actual implementation for conflict resolution. This is an approach that was discussed with @catch at various times and it seemed the most promising to achieve a balance between core stability and extensibility.
The bulk of the discussion revolved around
EntityChangedConstraintValidator: we need to keep its behavior when the default revision is being updated, but in any other case, since we want to support concurrent editing properly, we need to rely on a more advanced logic to detect conflicts.The outcome of our brainstorming is summarized by this diagram (hi-res version):
Basically we would have two distinct services for conflict detection and resolution and core would provide a (working) implementation only for the former.
@hchonov:
I was planning to have a look at the Conflict module to figure out whether this approach could problematic for it, but I noticed there were two 8.x branches so I thought it would be easier to just ask your opinion about this. Would it be easy to make 8.x-2.x leverage such an approach? And would it be a problem for 8.x-1.x if 8.7 were released implementing something along these lines?
Comment #12
hchonov@plach, the conflict module has two branches - 1.x and 2.x. 1.x has zero functionality, but for some unknown reasons to me multiversion depends on that branch.
I've implemented the whole functionality for conflict management in the 2.x branch. The good news are that the module looks pretty similar to your graph :). The only missing part is that context thing, which I don't understand what it is for, but we can talk further about it.
I would suggest, that you watch my session https://www.youtube.com/watch?v=ixlLskzT9c4 and that we schedule a call to discuss everything in more details. Probably you could also test the concurrent editing feature as shown on the video and play a bit with it and see if it looks good :).
Comment #13
hchonovUnfortunately I cannot speak for the 1.x branch.
Comment #14
plachYay!
That was only a way to visually differentiate between a form workflow and a REST one: if
$entity->save()is invoked in an entity form submit handler, context = FORM; if it's invoked in the scope of a REST API endpoint, context = REST :)I'll have a look, however my main goal here is to ensure that no contrib blockers are introduced by this issue, so I'm fine even if the functionality that Conflict provides doesn't fully match my expectations :)
I had a quick look and it seems to only expose some APIs, so it shouldn't be affected by these changes.
Comment #15
wim leers#11: The diagram makes sense to me. There's one thing that I'd like to see more explicitly in there: how could a decoupled UI provide all the same capabilities as the built-in form-based UI? The 409 response would need to contain metadata, so that the client knows what caused the conflict, where to get the conflicting data, etc. Because the conflict resolver may be implemented on the client.
#12: the arrows starting in that "Context" thing are "Form" and "REST". So in other words: "is the entity being saved via a form or via REST?" is what it's about.
Comment #16
plachDefinitely, this is exactly what I had in mind. However all that functionality will be provided by a contrib module. I imagine that it would leverage the conflict detection service to retrieve a list of conflicts and represent them in the HTTP response in any way it sees fit.
Comment #17
hchonov@Wim Leers, the
ContentEntityConflictHandlerfrom the conflict module 2.x branch already has such an API:And the conflict types that might be returned are:
CONFLICT_TYPE_SERVER_ONLYconflicts are being merged automatically by the conflict module in order to prevent reverts. This is however valid only when talking about concurrent editing :).Comment #18
wim leersI think having those PHP APIs is not a strong enough guarantee that a conflict resolution UI can be implemented on top of a REST API too.
I think this would need at least one functional test where a 409 response is sent, and its body includes metadata to resolve the conflict. The conflicts to resolve should already be in there — otherwise the 409 response would need to link to some other URL where that information can be fetched, this seems unnecessary.
Comment #19
plachWell, actually judging by the diagram above, we could make conflict info part of the validation error, this way they can be sent along with the 409 body even with core alone. Contrib can improve on that if more info is needed to actually build a conflict management UI on the client-side.
Comment #20
wim leersThat seems like a fine MVP :)
But Symfony’s validation errors only allow strings. Meaning it’s very hard to convey complex structures that way: they’d have to be parsed out again by an API client. Still, that’s not this issue’s fault obviously!
Comment #21
amateescu commented@hchonov:
Please refrain from mocking other people's work.
Comment #22
hchonov@amateescu, can you differentiate between mocking and stating the facts? There is absolutely no way to perform any conflict resolution with the 1.x branch. But feel free to prove me wrong.
I fully respect the work on the couple of interfaces in the 1.x branch! But interfaces and functionality is something different.
Comment #23
timmillwoodIn Conflict 1.x there are 4 services, so zero functionality is not a fact, it's your opinion.
Multiversion does depend on it, yes, that is a fact. However the "for some unknown reasons to me" does sounds like mocking. As if you're saying "WTF would anyone want to depend on that stupid version of this module for".
That is correct, but Multiversion, and the deploy suite of modules still uses these 4 services to map, track, and handle conflicts.
Anyway, this is digressing from the discussion here. I think the diagram in #11 is really good, and helps explain the plan, especially around what is in and out of core.
Comment #24
hchonovHow and what for can we use those 4 services?
Did I say that or it is just you putting words in my mouth? If I wanted to say that then I would've said it, but instead I very specifically said "unknown reasons". If it suits you to interpret it differently only to start a big and meaningless discussion, then this is your own decision.
I've never said those words and it is up to you to choose how to interpret them. But there was absolutely no hidden meaning.
Comment #25
timmillwoodI don't think this is a conversation for this issue, I'm just correcting your "fact" of no functionality.
No, sorry, but that is how it came across, that's how I felt. I felt mocked.
Where you said "Unfortunately I cannot speak for the 1.x branch." it was perfect, I wish you'd said this in #12.
Comment #26
hchonovWhy you? In which way did I offended you? If I did, then apologize and I can ensure you that it was not on purpose.
When I wrote "unknown reasons" I meant unknown to me because I thought it was clear that I cannot speak for anyone else.
Also note despite our previous conflicts I only brought up the 1.x branch because @plach explicitly asked about this, not because I wanted to cause any conflict here (no pun intended).
So I hope we can return to actually discussing the contents of this issue which is actually the reason why I came to this issue, before you two started this unnecessary conflict. As always, I look forward to your input on the actual subject and hope we can find agreement here.
Comment #27
pmelab commentedAfter a long and productive call with @hchonov, we came up with a common interface for the different requirements against a conflict detection / auto-resolution interface in core.
Requirements to take into consideration:
Based on this we drafted a first suggestion for an event based approach. There would be one new event type in core called
EntityConflictEvent:ParameterBagof arbitrary contexts used by specific implementations.Ways listeners can act on this event:
stopPropagationto make sure nobody else auto-resolves it.The different components that require conflict resolution would just fire the event and use the result information in a way they seem fit. The event propagation itself should just result in a list of conflicts and an automatic merge result (that may be used or not), but no persistent changes. How and when the conflicts and the merge result are used is up to the implementation.
In our drafted scenario, field level conflict resolution would not happen in Drupal core, but the conflict 2.0 module would provide a listener to this event, that itself would use a similar pattern to invoke different resolvers for all conflicted fields.
Comment #28
pmelab commentedAfter a little more discussion we refined the approach:
The event should be split in two. The first one to detect conflicts, the second one to apply automatic resolution.
Both would contain the Left, Right and Base entities as well as the Context bag. But the first one would collect the list of conflicts, while the second one assembles the resulting entity.
Comment #29
wim leersWoah, exciting to see this much progress! 👏
Comment #31
hchonovI've posted a patch based on #27 and #28 in conflict 2.x - #3043782: Conflict discovery and conflict resolution through pub/sub.
Reviews are welcome :).
When we have something we agree on, then we could extract some parts to the core.
Comment #32
pmelab commentedImplemented the first patch by porting @hchonov's work in the conflict module and adding some test cases.
Comment #33
pmelab commentedFixed test namespaces.
Comment #34
dixon_@pmelab @hchonov I've taken a brief look at the patch and it looks great! Would love to see this land in 8.8! However, I think we should break out this patch into a new issue but keep it part of this current plan/meta issue.
Comment #43
amateescu commentedHere's the initial implementation issue: #3553775: Add a conflict management API
Comment #44
geek-merlin