/// <summary> /// Exhausts the inbound queue /// </summary> public void ExhaustInboundQueue() { bool locked = false; using (AuthenticationContext.EnterSystemContext()) { try { locked = Monitor.TryEnter(this.m_inboundLock, 100); if (!locked) { return; } // Exhaust the queue int remain = SynchronizationQueue.Inbound.Count(); int maxTotal = 0; var remote = ApplicationContext.Current.Configuration.GetSection <SecurityConfigurationSection>()?.Domain; InboundQueueEntry nextPeek = null; IdentifiedData nextDpe = null; while (remain > 0) { InboundQueueEntry queueEntry = null; try { if (remain > maxTotal) { maxTotal = remain; } if (maxTotal > 5) { ApplicationContext.Current.SetProgress(String.Format("{0} - [{1}]", Strings.locale_import, remain), (maxTotal - remain) / (float)maxTotal); } #if PERFMON Stopwatch sw = new Stopwatch(); sw.Start(); #endif IdentifiedData dpe = null; if (nextPeek != null) // Was this loaded before? { { queueEntry = nextPeek; dpe = nextDpe; nextPeek = SynchronizationQueue.Inbound.PeekRaw(1); } else { queueEntry = SynchronizationQueue.Inbound.PeekRaw(); dpe = SynchronizationQueue.Inbound.DeserializeObject(queueEntry); nextPeek = SynchronizationQueue.Inbound.PeekRaw(1); } // Try to peek off the next queue item while we're doing something else Task <IdentifiedData> nextPeekTask = null; if (nextPeek != null) { nextPeekTask = Task <IdentifiedData> .Run(() => SynchronizationQueue.Inbound.DeserializeObject(nextPeek)); } #if PERFMON sw.Stop(); ApplicationContext.Current.PerformanceLog(nameof(QueueManagerService), nameof(ExhaustInboundQueue), "DeQueue", sw.Elapsed); sw.Reset(); sw.Start(); #endif //(dpe as SanteDB.Core.Model.Collection.Bundle)?.Reconstitute(); var bundle = dpe as Bundle; dpe = bundle?.GetFocalObject() ?? dpe; try { //if (bundle?.Item.Count > 1000) //{ // var ofs = 0; // while (ofs < bundle.Item.Count) // { // this.ImportElement(new Bundle() // { // Item = bundle.Item.Skip(ofs).Take(500).ToList() // }); // ofs += 500; // } //} //else this.ImportElement(dpe); AuditUtil.AuditSynchronization(AuditableObjectLifecycle.Import, remote, OutcomeIndicator.Success, dpe); } catch (Exception e) { try { this.m_tracer.TraceError("Error processing inbound queue entry: {0}", e); //this.CreateUserAlert(Strings.locale_importErrorSubject, Strings.locale_importErrorBody, ) SynchronizationQueue.DeadLetter.EnqueueRaw(new DeadLetterQueueEntry(queueEntry, Encoding.UTF8.GetBytes(e.ToString())) { OriginalQueue = "inbound" }); AuditUtil.AuditSynchronization(AuditableObjectLifecycle.Import, remote, OutcomeIndicator.MinorFail, dpe); } catch (Exception) { this.m_tracer.TraceEvent(System.Diagnostics.Tracing.EventLevel.Critical, "Error putting dead item on deadletter queue: {0}", e); throw; } } finally { SynchronizationQueue.Inbound.Delete(queueEntry.Id); } this.QueueExhausted?.Invoke(this, new QueueExhaustedEventArgs("inbound", bundle?.Item.AsParallel().Select(o => o.Key.Value).ToArray() ?? new Guid[] { dpe.Key.Value })); #if PERFMON sw.Stop(); ApplicationContext.Current.PerformanceLog(nameof(QueueManagerService), nameof(ExhaustInboundQueue), "ImportComplete", sw.Elapsed); sw.Reset(); #endif nextPeekTask?.Wait(); nextDpe = nextPeekTask?.Result; } catch (Exception e) { this.m_tracer.TraceError("Error processing inbound queue entry: {0}", e); } remain = SynchronizationQueue.Inbound.Count(); } if (maxTotal > 5) { ApplicationContext.Current.SetProgress(String.Format(Strings.locale_import, String.Empty, String.Empty), 1.0f); } } finally { if (locked) { Monitor.Exit(this.m_inboundLock); } } } }