-
Notifications
You must be signed in to change notification settings - Fork 2.4k
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
Fixes #6008 Update Content Activities #6054
Conversation
@jtkech I got round to doing some testing, below are my findings.
Your changes look great, we just need to address that nested case and i think it could be good to add a |
|
# Conflicts: # src/OrchardCore.Modules/OrchardCore.Contents/Workflows/Activities/UpdateContentTask.cs
@duncanhoggan and @deanmarcussen as you will have to review my changes related to the new Sorry but because of some recent changes that have been merged, now an update content activity may do a session cancel through a new We already saw this case: 1. session save - 2. query + mutation - 3. we need a save to take into account the last mutation. Here, because the cancel can be done earlier, the new one is: 1. session cancel - 2. query - 3. session save => the item is persisted even the session has been canceled in 1. Todo: This use cases need to be supported transparently, but in a separate PR. So we really need to check if the So i did some updates and re-do all the tests that was working on my side.
Maybe i will need to also update other content task activities, but not sure, will see tomorrow. |
Ok, makes sense @jtkech I wanted the But where there is (and there is a need for it), it makes good sense to join these errors into the (The other reason was because it was about validation failures, not successes, so didn't want to list all the succeeded validations, just the errors, or we could have just used a
|
@deanmarcussen when you will have time @agriffard requested a review from you |
@sebastienros and others So we discussed about preventing e.g. a WF infinite loop (#6455) but at another level, but it can't supersede all what is done in this PR specifically for content events / tasks. So here, as a reminder that may be used in another triage meeting, some uses cases to show what i mean.
|
# Conflicts: # src/OrchardCore.Modules/OrchardCore.Contents/Views/Items/UpdateContentTask.Fields.Edit.cshtml
You are still a pending reviewer for this one ;) but only if you have time. I could merge it myself but because we talked about it in a recent triage meeting i prefer that someone else approves it (or not) before merging it (or just closing it). In the meeting it was related to infinite loops but this PR supports many other scenarios. If needed i can help you to understand what i did, and to do some simple repros see my previous comment or the recent related issues i opened. |
@jtkech sorry, took some time to think about this one. For the detecting and cancelling infinite loops all seems to make sense. For the Inline (from driver, and external) it looks like you have changed the shape of this pr for the better. Can you explain though? Previously when I looked at it, you were detecting (with some cleverness) when a workflow event came from a driver, or a controller, from memory to decide whether to save, or not? And for knowing whether to add model state errors etc? From the triage conversation this was the area of concern that was blocking it, as Seb was concerned that workflows should have to know about these things. It looks however you have changed it so that the workflow does not figure it out itself, but is passed some information informing it? Can you just explain how it is operating in those cases? I'm looking but there are so many other scenarios you have fixed with this one, that I'm not quite sure I'm following the logic there |
@deanmarcussen no problem, thanks to look at it again I didn't have any time as #6356 was not so easy to fix ;) but i will give you soon more infos step by step |
If i'm not clear / incomplete as i didn't have enough time we could have a chat / talk on gitter / skipe. So here some more infos as i can in a first step that may indirectly answer to your questions
|
@jtkech I am reading and thinking ;) |
@jtketch I had to leave triage early last night, so we did not get to talk about this. We do need to talk about it before merging, my concern is that we are fixing something, on top of fixing something else, with regard to the inline event, and the workflow acting as a mini controller. All else is fine. It seems to me we have a fatal flaw in the idea of a workflow being a mini controller, and calling these content manager methods. I went to use these a couple of days ago, and they were not adding up to me. Let's talk about a It seems a little weird that a workflow would be it's own initiator, or mini controller. I realise we have recently added some of these tasks, However I did not write these tasks, nor design workflows, so maybe I am wrong here. I would have to look back at O1 to see how the event -> task flow worked better. |
No problem, nothing urgent for me For the other concerns i understand and i have no closed opinion, it only depends on what we allow to do. Here some oher infos / examples The If there is an intermediate activity before, e.g. a timer event or any other waiting event, because when a WF instance is persisted we don't save the whole content item but only the contentItemId as a correlationId, the script can just be In place of saying as a mini controller / initiator maybe better to say as a standalone activity as it has to retrieve the content item by itself. And in the above case this is already the case but here the real initiator is still the content event but the Another exemple is an Finally, the script expression can just be an hard coded string
See the above What i said about the script expression, providing a contenItemId, is the same for the |
@@ -242,6 +242,22 @@ public async Task<ContentItem> GetVersionAsync(string contentItemVersionId) | |||
return await LoadAsync(contentItem); | |||
} | |||
|
|||
public async Task SaveDraftAsync(ContentItem contentItem) | |||
{ | |||
if (!contentItem.Latest || contentItem.Published) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @jtkech - this line doesn't seem right as it prevents handlers being fired when adding a draft to an already published content item.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@sturatcliffe Thanks for the feedback
-
Normally only one content item version can be
Published
and only one version can be theLatest
. -
An active version is
Published
OR theLatest
(so can be both). So a version is not active if it is neitherPublished
nor theLatest
, there is a pending audit trail module to manage these archived versions, otherwise we don't take them into account because they are considered as soft deleted versions. -
So let's only talk about active versions, if a version is
Published
andLatest
it means that there is no active draft version for the related content item. When we publish it again, a new version is created that is marked asPublished
andLatest
, and we set to false thePublished
andLatest
of the previous version that becomes an archived version. -
If we save as a draft this
Published
andLatest
, a new version is created that is only marked asLatest
, the published version is still the same but no more theLatest
and we now have an active draft version. When we edit a content item we always edit theLatest
version, so here it will be the new active draft version. If you save it again as a draft version, we don't create a new version, we just update this version that is still the active draft version.
Sorry for the long story and there are different ways to describe content item versions ;)
So what i can say here is that an active draft version is always the Latest
and of course can't be Published
.
And SaveDraftAsync()
is intended to call the related handlers only if we are saving an active draft version.
I don't know in which context you are using SaveDraftAsync()
but at this point your content item version needs to be the Latest
and you have to take care that you have only one Latest
. For this, e.g. when updating a content item, we first get this content item through the content manager by using the option DraftRequired
, this will use a current active draft version or create a new non published version and that becomes the latest.
@@ -20,6 +20,8 @@ public interface IContentHandler | |||
Task ValidatedAsync(ValidateContentContext context); | |||
Task VersioningAsync(VersionContentContext context); | |||
Task VersionedAsync(VersionContentContext context); | |||
Task DraftSavingAsync(SaveDraftContentContext context); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @jtkech,
Should these 2 be added to IContentPartHandler
too?
Btw, we've been using this branch for a while now and we're very happy with it and had no issues.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@lazcool Good catch, forgot it ;)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done ;)
Btw, we've been using this branch for a while now and we're very happy with it and had no issues.
Cool thanks. If you have time can you add some comments on your own usage of this branch in the main thread? It may help us to decide if it is worth to review this PR again before merging, or just close it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, it's took a week, work's been manic 😅.
We use the new draft saved event, to sync the content item to a preview graph database (we basically replicate content items as nodes and relationships to published and preview graphs).
We'll also be using the new draft saved event to publish external events to Azure Event Grid when a new draft version is saved. (We have micro-service UI apps that listen for the events and then update their local stores with the content from the graphs.)
We currently publish draft events using the existing Orchard Core events, such as updated, but without this PR, we've found it impossible not to publish false-positive events, because the context just isn't there (and we have to do delayed processing of the events, which is complicated, messy and racey).
I have another question for you:
Would it make sense to fire the new draft save events when the user adds or deletes a taxonomy term?
At the moment, as soon as they, for example, add a new term, a new draft version of the taxonomy is saved, but no draft saved event gets fired. That means we don't get an opportunity to sync the new item to our graph or publish an event off the back of it.
Fixes #6008
@duncanhoggan could you re-do some tests by forking this branch or just copy
UpdateContentTask
and the little change inDefaultContentManagerSession
needed in some scenarios.You could retry it when triggered by a
ContentCreatedEvent
. We useDraftRequired
so that the content manager returns a new draft version or not by checking if the type isVersionable
. Most of the time after a content event we retrieved a cached instance, but not here.So here, after having mutated this version this is not our responsability to publish it, it will be done or not by the "caller" that triggered the WF, e.g the admin controller => content handler =>
ContentCreatedEvent
=> the item is published or not by the controller.Then if related to an existing item and not triggered by a content event, e.g an
HttpRequestEvent
, as in your last WF sample in Fixed content create event order #6009, after theUpdateContentTask
it's up to you to use or not aPublishContentTask
.Then when using an
UserTaskEvent
edit action that adds a button when editing the related content item, when clicking on it this is always asubmit.save
that is posted, not asubmit.publish
, so the draft version is just saved, so here also it is up to you to use or not aPublishContentTask
.So in your last WF sample in Fixed content create event order #6009 you would have to not use
PublishContentTask
after theUpdateContentTask
but after theUserTaskEvent
. Otherwise, after clicking the edit user button, it will always use the existing draft or create new one but without publishing it, as you saw.Then, if you didn't see any update, i think that there is another problem, maybe with your
ContentProperties
expression as i tried quite the same WF on my side and it was working