refactor latched background tasks, now use a task for xml
This commit is contained in:
@@ -4,6 +4,7 @@ using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using umbraco;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Web.Scheduling;
|
||||
@@ -19,22 +20,120 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
/// if multiple threads are performing publishing tasks that the file will be persisted in accordance with the final resulting
|
||||
/// xml structure since the file writes are queued.
|
||||
/// </remarks>
|
||||
internal class XmlCacheFilePersister : DisposableObject, IBackgroundTask
|
||||
internal class XmlCacheFilePersister : ILatchedBackgroundTask
|
||||
{
|
||||
private readonly XmlDocument _xDoc;
|
||||
private readonly IBackgroundTaskRunner<XmlCacheFilePersister> _runner;
|
||||
private readonly string _xmlFileName;
|
||||
private readonly ProfilingLogger _logger;
|
||||
private readonly content _content;
|
||||
private readonly ManualResetEventSlim _latch = new ManualResetEventSlim(false);
|
||||
private readonly object _locko = new object();
|
||||
private bool _released;
|
||||
private Timer _timer;
|
||||
private DateTime _initialTouch;
|
||||
|
||||
public XmlCacheFilePersister(XmlDocument xDoc, string xmlFileName, ProfilingLogger logger)
|
||||
private const int WaitMilliseconds = 4000; // save the cache 4s after the last change (ie every 4s min)
|
||||
private const int MaxWaitMilliseconds = 10000; // save the cache after some time (ie no more than 10s of changes)
|
||||
|
||||
// save the cache when the app goes down
|
||||
public bool RunsOnShutdown { get { return true; } }
|
||||
|
||||
public XmlCacheFilePersister(IBackgroundTaskRunner<XmlCacheFilePersister> runner, content content, string xmlFileName, ProfilingLogger logger, bool touched = false)
|
||||
{
|
||||
_xDoc = xDoc;
|
||||
_runner = runner;
|
||||
_content = content;
|
||||
_xmlFileName = xmlFileName;
|
||||
_logger = logger;
|
||||
|
||||
if (touched == false) return;
|
||||
|
||||
LogHelper.Debug<XmlCacheFilePersister>("Create new touched, start.");
|
||||
|
||||
_initialTouch = DateTime.Now;
|
||||
_timer = new Timer(_ => Release());
|
||||
|
||||
LogHelper.Debug<XmlCacheFilePersister>("Save in {0}ms.", () => WaitMilliseconds);
|
||||
_timer.Change(WaitMilliseconds, 0);
|
||||
}
|
||||
|
||||
public XmlCacheFilePersister Touch()
|
||||
{
|
||||
lock (_locko)
|
||||
{
|
||||
if (_released)
|
||||
{
|
||||
LogHelper.Debug<XmlCacheFilePersister>("Touched, was released, create new.");
|
||||
|
||||
// released, has run or is running, too late, add & return a new task
|
||||
var persister = new XmlCacheFilePersister(_runner, _content, _xmlFileName, _logger, true);
|
||||
_runner.Add(persister);
|
||||
return persister;
|
||||
}
|
||||
|
||||
if (_timer == null)
|
||||
{
|
||||
LogHelper.Debug<XmlCacheFilePersister>("Touched, was idle, start.");
|
||||
|
||||
// not started yet, start
|
||||
_initialTouch = DateTime.Now;
|
||||
_timer = new Timer(_ => Release());
|
||||
LogHelper.Debug<XmlCacheFilePersister>("Save in {0}ms.", () => WaitMilliseconds);
|
||||
_timer.Change(WaitMilliseconds, 0);
|
||||
return this;
|
||||
}
|
||||
|
||||
// set the timer to trigger in WaitMilliseconds unless we've been touched first more
|
||||
// than MaxWaitMilliseconds ago and then release now
|
||||
|
||||
if (DateTime.Now - _initialTouch < TimeSpan.FromMilliseconds(MaxWaitMilliseconds))
|
||||
{
|
||||
LogHelper.Debug<XmlCacheFilePersister>("Touched, was waiting, wait.", () => WaitMilliseconds);
|
||||
LogHelper.Debug<XmlCacheFilePersister>("Save in {0}ms.", () => WaitMilliseconds);
|
||||
_timer.Change(WaitMilliseconds, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogHelper.Debug<XmlCacheFilePersister>("Save now, release.");
|
||||
ReleaseLocked();
|
||||
}
|
||||
|
||||
return this; // still available
|
||||
}
|
||||
}
|
||||
|
||||
private void Release()
|
||||
{
|
||||
lock (_locko)
|
||||
{
|
||||
ReleaseLocked();
|
||||
}
|
||||
}
|
||||
|
||||
private void ReleaseLocked()
|
||||
{
|
||||
LogHelper.Debug<XmlCacheFilePersister>("Timer: save now, release.");
|
||||
if (_timer != null)
|
||||
_timer.Dispose();
|
||||
_timer = null;
|
||||
_released = true;
|
||||
_latch.Set();
|
||||
}
|
||||
|
||||
public WaitHandle Latch
|
||||
{
|
||||
get { return _latch.WaitHandle; }
|
||||
}
|
||||
|
||||
public bool IsLatched
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
public async Task RunAsync()
|
||||
{
|
||||
await PersistXmlToFileAsync(_xDoc);
|
||||
LogHelper.Debug<XmlCacheFilePersister>("Run now.");
|
||||
var doc = _content.XmlContentInternal;
|
||||
await PersistXmlToFileAsync(doc);
|
||||
}
|
||||
|
||||
public bool IsAsync
|
||||
@@ -91,14 +190,12 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
}
|
||||
}
|
||||
|
||||
protected override void DisposeResources()
|
||||
{
|
||||
}
|
||||
public void Dispose()
|
||||
{ }
|
||||
|
||||
public void Run()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user