Hi,
Try this in both your first and second schedule job:
contentRepository.Save(content, SaveAction.ForceCurrentVersion)
It should save only the changes you set.
The only downside is that it won't create a version making it difficult for you to track or rollback the changes...if you even care about it.
Should be easy to create a poc for it.
Thanks Surjit!
I tested this out below (Note the below includes some of our convenience helpers / extensions to retrieve content, get a writeable version or save, should be pretty clear from context what they do).
var threadOneHasWriteable = false;
var threadTwoHasSaved = false;
var threadOne = Task.Run(() =>
{
var content = ContentHelper.SafeGet<ArticlePage>(269614);
var writeable = content.GetWriteable();
threadOneHasWriteable = true;
while (!threadTwoHasSaved)
Thread.Sleep(TimeSpan.FromSeconds(1));
writeable.MetaDescription = "Updated by Thread One";
writeable.Save(SaveAction.ForceCurrentVersion);
});
var threadTwo = Task.Run(() =>
{
while (!threadOneHasWriteable)
Thread.Sleep(TimeSpan.FromSeconds(1));
var content = ContentHelper.SafeGet<ArticlePage>(269614);
var writeable = content.GetWriteable();
writeable.MetaTitle = "Updated by Thread Two";
writeable.Save(SaveAction.ForceCurrentVersion);
threadTwoHasSaved = true;
});
Task.WhenAll(threadOne, threadTwo).GetAwaiter().GetResult();
var finalContent = ContentHelper.SafeGet<ArticlePage>(269614);
WriteLine($"Meta Title - {finalContent.MetaTitle}");
WriteLine($"Meta Description - {finalContent.MetaDescription}");
I found the following -
After you run your code, fire up edit mode and look at the versions its created. You'll find saveaction.publish will create a new version.
But saveaction.forcecurrentversion will save to the current version.
The potential problem you have with your poc is task one may have finished before task two. In other words, the second createwritableclone might be being called after saving of task one. So you might be observing metadescription value is carrying over to the next version...tasks by default are scheduled in the threadpool.
You can be doubly sure by doing the sequence of events without tasks. So call createwritableclone twice one aft the other and experiment with both saveactions and you'll see the difference.
After you run your code, fire up edit mode and look at the versions its created. You'll find saveaction.publish will create a new version.
Apologies for not being clearer there - I only meant that it didn't seem to change the behaviour with regards to the concurrency protection (Or lack therof).
The potential problem you have with your poc is task one may have finished before task two. In other words, the second createwritableclone might be being called after saving of task one
The second thread waits for the first to have called GetWriteableClone() before it attempts to call GetWriteableClone() and Save, and the first waits until the second has saved before it attempts to Save - Trying to replicate a worst-case scenario where the two operations actually overlap by retrieving the same piece of unmodified content and then both performing different edits. In this case, it appears that the writes to the two different fields I used (Apologies, the two fields I picked have pretty similar names) both went through, and neither thread removed the changes the other had done.
Makes sense! Apologies I skimmed over the outer scoped variables. Hopefully this help you with your bigger piece of work.
How time consuming is your 1st scheduled job which syncs to CMS from an API? If this is not lengthy and system can wait then you always can wait for this to be finished first. For instance if you have 2nd scheduled job to perform the new synchronisation, You can check if the first job is still running and put your content as scheduled. So next time when it saves on scheduled time, it again checks for the first job completion.
var firstSyncJob = _scheduledJobRepository.Get(new Guid("8EC257F9-FF22-40EC-9958-C1C5BA8C2A53"));
if (firstSyncJob.IsRunning)
{
"CMS Sync job is running. Leve no actions to perform.";
writeable.StartPublish = futureDate;
_contentRepository.Save(writeable, SaveAction.CheckIn | SaveAction.DelayedPublish, AccessLevel.NoAccess);
}
else{
var secondSyncJob = _scheduledJobRepository.Get(new Guid("9EC257F9-FF22-40ED-9958-C1C5BA8C2A53"));
_scheduledJobExecutor.StartAsync(secondSyncJob);
}
You can add check on content events as Publishing_Content and do above checks.
Gidday,
We currently have a Scheduled Job which synchronises information from a third-party API into several fields on Pages within our CMS.
I'm looking at adding the synchronisation of some more data onto new fields on the same Page Type, but the new synchronisation will be significantly slower than the existing, and I would prefer not to slow down the existing Scheduled Job.
I was considering adding a second Scheduled Job to perform the new synchronisation, leaving the existing Job with only its current responsibilities, but I was concerned that there might be edge cases where both Jobs attempted to update the same Page simultaneously.
Are there any consistency guarantees provided when performing a Save on Writeable Content, or would I need to ensure that the two jobs were not running simultaneously?
I couldn't see anything in a quick dive down the codepath, so my assumption is that any changes made in between calling CreateWritableClone and Save by a parallel process would not be reflected, and the second save would overwrite anything done by the first.
Thanks for any assistance.