From b78ce003a7a8e27f5da8035903c9655415658c34 Mon Sep 17 00:00:00 2001 From: Gary Sharp Date: Sat, 26 Jul 2014 12:25:20 +1000 Subject: [PATCH] Bug Fix: Error when assigning devices The noticeboard listens for updates to user assignments (including who was previously assigned the device), but was requesting data which no longer existed (as updates are delayed and buffered for up to 500ms). --- .../Jobs/Noticeboards/HeldDevices.cs | 178 ++++++++++-------- 1 file changed, 101 insertions(+), 77 deletions(-) diff --git a/Disco.Services/Jobs/Noticeboards/HeldDevices.cs b/Disco.Services/Jobs/Noticeboards/HeldDevices.cs index 09ef3051..e508f414 100644 --- a/Disco.Services/Jobs/Noticeboards/HeldDevices.cs +++ b/Disco.Services/Jobs/Noticeboards/HeldDevices.cs @@ -5,7 +5,9 @@ using Disco.Models.Services.Jobs.Noticeboards; using System; using System.Collections.Generic; using System.Linq; +using System.Reactive.Concurrency; using System.Reactive.Linq; +using System.Reactive.Subjects; namespace Disco.Services.Jobs.Noticeboards { @@ -41,10 +43,19 @@ namespace Disco.Services.Jobs.Noticeboards "DisplayName" }; + private static Subject, List>> BufferedUpdateStream; + static HeldDevices() { + BufferedUpdateStream = new Subject, List>>(); + + BufferedUpdateStream + .DelayBuffer(TimeSpan.FromMilliseconds(500)) + .SubscribeOn(TaskPoolScheduler.Default) + .Subscribe(ProcessUpdates); + // Subscribe to Repository Notifications - RepositoryMonitor.StreamAfterCommit.Where(e => + RepositoryMonitor.StreamBeforeCommit.Where(e => (e.EntityType == typeof(Job) && (e.EventType == RepositoryMonitorEventType.Added || e.EventType == RepositoryMonitorEventType.Deleted || @@ -65,93 +76,105 @@ namespace Disco.Services.Jobs.Noticeboards (e.EventType == RepositoryMonitorEventType.Modified && e.ModifiedProperties.Any(p => MonitorUserProperties.Contains(p))) ) ) - .DelayBuffer(TimeSpan.FromMilliseconds(500)) .Subscribe(RepositoryEvent); } - private static void RepositoryEvent(IEnumerable e) + private static void RepositoryEvent(RepositoryMonitorEvent i) { List deviceSerialNumbers = new List(); List userIds = new List(); - using (DiscoDataContext Database = new DiscoDataContext()) + if (i.EntityType == typeof(Job)) { - foreach (var i in e) + if (i.EventType == RepositoryMonitorEventType.Modified && + i.ModifiedProperties.Contains("DeviceSerialNumber")) { - if (i.EntityType == typeof(Job)) - { - if (i.EventType == RepositoryMonitorEventType.Modified && - i.ModifiedProperties.Contains("DeviceSerialNumber")) - { - var p = i.GetPreviousPropertyValue("DeviceSerialNumber"); - if (p != null) - deviceSerialNumbers.Add(p); - } - - var j = (Job)i.Entity; - if (j.DeviceSerialNumber != null) - deviceSerialNumbers.Add(j.DeviceSerialNumber); - } - else if (i.EntityType == typeof(JobMetaNonWarranty)) - { - var jmnw = (JobMetaNonWarranty)i.Entity; - - if (jmnw.Job != null) - { - if (jmnw.Job.DeviceSerialNumber != null) - deviceSerialNumbers.Add(jmnw.Job.DeviceSerialNumber); - } - else - { - var sn = Database.Jobs.Where(j => j.Id == jmnw.JobId).Select(j => j.DeviceSerialNumber).FirstOrDefault(); - if (sn != null) - deviceSerialNumbers.Add(sn); - } - } - else if (i.EntityType == typeof(Device)) - { - var d = (Device)i.Entity; - deviceSerialNumbers.Add(d.SerialNumber); - - if (i.EventType == RepositoryMonitorEventType.Modified && - i.ModifiedProperties.Contains("AssignedUserId")) - { - var p = i.GetPreviousPropertyValue("AssignedUserId"); - if (p != null) - userIds.Add(p); - } - } - else if (i.EntityType == typeof(DeviceProfile)) - { - var dp = (DeviceProfile)i.Entity; - - deviceSerialNumbers.AddRange( - Database.Jobs - .Where(j => !j.ClosedDate.HasValue && j.Device.DeviceProfileId == dp.Id) - .Select(j => j.DeviceSerialNumber) - ); - } - else if (i.EntityType == typeof(User)) - { - var u = (User)i.Entity; - - deviceSerialNumbers.AddRange( - Database.Jobs - .Where(j => !j.ClosedDate.HasValue && j.Device.AssignedUserId == u.UserId) - .Select(j => j.DeviceSerialNumber) - ); - } + var p = i.GetPreviousPropertyValue("DeviceSerialNumber"); + if (p != null) + deviceSerialNumbers.Add(p); } - deviceSerialNumbers = deviceSerialNumbers.Distinct().ToList(); + var j = (Job)i.Entity; + if (j.DeviceSerialNumber != null) + deviceSerialNumbers.Add(j.DeviceSerialNumber); + } + else if (i.EntityType == typeof(JobMetaNonWarranty)) + { + var jmnw = (JobMetaNonWarranty)i.Entity; + + if (jmnw.Job != null) + { + if (jmnw.Job.DeviceSerialNumber != null) + deviceSerialNumbers.Add(jmnw.Job.DeviceSerialNumber); + } + else + { + var sn = i.Database.Jobs.Where(j => j.Id == jmnw.JobId).Select(j => j.DeviceSerialNumber).FirstOrDefault(); + if (sn != null) + deviceSerialNumbers.Add(sn); + } + } + else if (i.EntityType == typeof(Device)) + { + var d = (Device)i.Entity; + deviceSerialNumbers.Add(d.SerialNumber); + + if (i.EventType == RepositoryMonitorEventType.Modified && + i.ModifiedProperties.Contains("AssignedUserId")) + { + var p = i.GetPreviousPropertyValue("AssignedUserId"); + if (p != null) + userIds.Add(p); + } + } + else if (i.EntityType == typeof(DeviceProfile)) + { + var dp = (DeviceProfile)i.Entity; + + deviceSerialNumbers.AddRange( + i.Database.Jobs + .Where(j => !j.ClosedDate.HasValue && j.Device.DeviceProfileId == dp.Id) + .Select(j => j.DeviceSerialNumber) + ); + } + else if (i.EntityType == typeof(User)) + { + var u = (User)i.Entity; + + deviceSerialNumbers.AddRange( + i.Database.Jobs + .Where(j => !j.ClosedDate.HasValue && j.Device.AssignedUserId == u.UserId) + .Select(j => j.DeviceSerialNumber) + ); + } + + if (deviceSerialNumbers.Count > 0 || userIds.Count > 0) + { + i.ExecuteAfterCommit(e => + { + BufferedUpdateStream.OnNext(Tuple.Create(deviceSerialNumbers, userIds)); + }); + } + } + + private static void ProcessUpdates(IEnumerable, List>> e) + { + using (DiscoDataContext Database = new DiscoDataContext()) + { + var deviceSerialNumbers = e.SelectMany(i => i.Item1).Distinct().ToList(); + var userIds = e.SelectMany(i => i.Item2).Distinct().ToList(); // Determine Held Devices for Users - userIds.AddRange( - Database.Devices - .Where(d => d.AssignedUserId != null && deviceSerialNumbers.Contains(d.SerialNumber)) - .Select(d => d.AssignedUserId) - ); - userIds = userIds.Distinct().ToList(); + if (deviceSerialNumbers.Count > 0) + { + userIds.AddRange( + Database.Devices + .Where(d => d.AssignedUserId != null && deviceSerialNumbers.Contains(d.SerialNumber)) + .Select(d => d.AssignedUserId) + ); + } + if (userIds.Count > 0) + userIds = userIds.Distinct().ToList(); // Notify Held Devices @@ -172,8 +195,9 @@ namespace Disco.Services.Jobs.Noticeboards { var updates = DeviceSerialNumbers .Skip(skipAmount).Take(30) - .ToDictionary(dsn => dsn, - dsn => { + .ToDictionary(dsn => dsn, + dsn => + { IHeldDeviceItem item; items.TryGetValue(dsn, out item); return item;