public async Task <IActionResult> InvokeGrouper(bool ignoreChangelimit) { GrouperDocument document = await Helper.MakeDocumentAsync(Request); GroupMemberDiff diff = await _grouperBackend.GetMemberDiffAsync(document); await _grouperBackend.UpdateGroupAsync(diff, ignoreChangelimit); var changes = new List <OperationalLogItem>(); foreach (GroupMember member in diff.Add) { changes.Add(new OperationalLogItem(document, GroupMemberOperations.Add, member)); } foreach (GroupMember member in diff.Remove) { changes.Add(new OperationalLogItem(document, GroupMemberOperations.Remove, member)); } return(Ok(changes)); }
private void InvokeGrouper(object source, ElapsedEventArgs e) { Timer timer = (Timer)source; List <GrouperDocumentEntry> entries = new List <GrouperDocumentEntry>(); bool processAllDocuments = ShouldProcessAllDocuments(); if (processAllDocuments) { _lastFullProcessHour = DateTime.Now.Hour; entries.AddRange(_documentDb.GetAllEntriesAsync().GetAwaiter().GetResult()); } else { // Get documents that changed since the last timer event. // It doesn't matter if we miss a document. It will be processed in the next full run DateTime start = DateTime.Now.AddMilliseconds(-_workInterval); entries.AddRange(_documentDb.GetEntriesByAgeAsync(start).GetAwaiter().GetResult()); // Get documents that have a processing interval hint and // where the interval has passed. IEnumerable <GrouperDocumentEntry> entriesWithInterval = _documentDb.GetEntriesByProcessingInterval(min: 1).GetAwaiter().GetResult(); foreach (GrouperDocumentEntry entry in entriesWithInterval) { if (_lastProcessedDictionary.TryGetValue(entry.Document.Id, out DateTime lastProcessed)) { if (lastProcessed.AddMinutes(entry.Document.ProcessingInterval) < DateTime.Now) { entries.Add(entry); } // If it's not in the dictionary, process interval was added to the document // after the service started and the document should be picked up by the // document age check above (this includes both new and changed documents) } } } foreach (GrouperDocumentEntry entry in entries) { DebugPrint("Processing group {0}", entry.GroupName); if (_stopRequested) { return; } try { GroupMemberDiff diff = _grouper.GetMemberDiffAsync(entry.Document).GetAwaiter().GetResult(); _grouper.UpdateGroupAsync(diff).GetAwaiter().GetResult(); if (entry.Document.ProcessingInterval > 0) { _lastProcessedDictionary[entry.Document.Id] = DateTime.Now; } DebugPrint("Processed group {0}. {1} added, {2} removed.", entry.GroupName, diff.Add.Count(), diff.Remove.Count()); } catch (Exception ex) { string message = ex.Message; if (ex.InnerException != null) { message = ex.InnerException.Message; } WriteToLogDb(entry.Document, message, LogLevels.Error); if (!(ex is GroupNotFoundException || ex is MemberNotFoundException || ex is ChangeRatioException)) { WriteToEventLog(message, EventLogEntryType.Error); } } } // There is a memory leak somewhere. Likely in Exo. So we tear down Grouper and build a new one after // every full run and see if that helps narrow down the leak. if (processAllDocuments) { SetupGrouper(); } if (!_stopRequested) { timer.Enabled = true; } }