/// <summary>
        /// Выполнить действие в отдельном потоке и транзакции
        /// ---
        ///  объекты должны быть независимы в действии, можно передавать Id сущности и после выполнения в исходном потоке вызвать Refresh
        /// </summary>
        /// <param name="action"> действие </param>
        /// <param name="name">название операции</param>
        /// <param name="errorCallback">обработка ошибки</param>
        /// <param name="successCallback">действие после успеха</param>
        /// <param name="minutes">количество минут выделенное на операцию (максимум 9)</param>
        public static void InNewThread(
            this Action action,
            string name,
            Action <Exception> errorCallback,
            Action successCallback,
            int minutes = 2)
        {
            Exception exception = null;
            Thread    thread    = null;

            try
            {
                thread = ThreadStarter.StartNewThread((ThreadStart) delegate
                {
                    var backgroundTask = new BackgroundTask(() =>
                    {
                        var securityService = Locator.GetService <ISecurityService>();
                        securityService.RunByUser(UserManager.Instance.Load(SecurityConstants.AdminUserUid),
                                                  () =>
                        {
                            var unitOfWorkManager = Locator.GetServiceNotNull <IUnitOfWorkManager>();
                            using (var unitOfWork = unitOfWorkManager.Create(string.Empty, true, System.Data.IsolationLevel.ReadCommitted))
                            {
                                try
                                {
                                    action.Invoke();
                                    unitOfWork.Commit();
                                }
                                catch (Exception ex)
                                {
                                    unitOfWork.Rollback();
                                    exception = ex;
                                }
                            }
                        });
                    }, typeof(Action), action.Method.Name, name);
                    backgroundTask.Execute();
                });
                thread.IsBackground = true;
                if (!thread.Join(TimeSpan.FromMinutes(minutes)))
                {
                    thread.Abort();
                    var message = $"Действие \"{name}\" выполнялось более {minutes} минут и было прервано";
                    exception = exception != null ? new Exception(message, exception) : new Exception(message);
                }
                if (exception != null)
                {
                    if (errorCallback != null)
                    {
                        errorCallback.Invoke(exception);
                    }
                    else
                    {
                        throw exception;
                    }
                }
                else
                {
                    successCallback?.Invoke();
                }
            }
            catch (ThreadAbortException)
            {
                thread?.Abort();
                throw;
            }
        }
        /// <summary>
        /// Heartbeat thread, waits for signal that something has been queued for processing.
        /// </summary>
        protected virtual void Heartbeat()
        {
            Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");

            do
            {
                if (shutdown)
                {
                    return;
                }

                Trace.WriteLine("Processor idle, waiting for signal...");

                // Wait for the signal to be set
                signal.WaitOne();

                Trace.WriteLine("Got signal, processing task");

                // Exit heartbeat
                if (shutdown)
                {
                    return;
                }

                try
                {
                    queuedBackgroundTask.OnStarted();

                    queuedBackgroundTask.Execute();

                    queuedBackgroundTask.OnSuccess();
                }
                //catch (ThreadAbortException)
                //{
                //    Thread.ResetAbort();
                //}
                catch (Exception ex)
                {
                    try
                    {
                        Logger.Error("An error has occured while executing the task {0}, Exception = {1}", LogSource.TaskQueue, this, ex);

                        queuedBackgroundTask.OnFailure();
                    }
                    catch (Exception ex1)
                    {
                        Logger.Error("A fatal background task exception has occured. Exception = {0}", LogSource.TaskQueue, ex1);
                    }
                }
                finally
                {
                    try
                    {
                        queuedBackgroundTask.OnCompleted();

                        ToggleStatus(true);

                        queuedBackgroundTask = null;
                        OnPropertyChanged("QueuedBackgroundTask");
                    }
                    catch (Exception ex)
                    {
                        Logger.Error("A fatal background task exception has occured. Exception = {0}", LogSource.TaskQueue, ex);
                    }
                }
            }while (true);
        }