private bool DeleteInstanceInternal(IComparable instanceId, bool replicate, long evictionVersion)
        {
            Requires.Argument("instanceId", instanceId).NotNull();

            StatefulServiceExecutionContext executionContext = StatefulServiceExecutionContext.Current as StatefulServiceExecutionContext;

            if (executionContext == null || executionContext.Partition == null)
            {
                throw new InvalidOperationException("Program instance cannot be obtained outside context of a partition. Please ensure that StatefulServiceReplicaT.Invoke is called.");
            }

            StatefulProgramInstance instance = null;
            ItemCollection <IComparable, StatefulProgramInstance> instances;

            using (this.instanceManager.GetInstances(LockPermission.Write, out instances))
            {
                if (instances.Contains(instanceId))
                {
                    instance = (StatefulProgramInstance)instances[instanceId];
                    if (evictionVersion != -2 && !instance.CanEvict(evictionVersion))
                    {
                        return(false);
                    }

                    instances.Remove(instanceId);
                    ((IDisposable)instance).Dispose();
                }
            }

            if (instance != null)
            {
                if (replicate)
                {
                    Replicable <StatefulProgramInstance> replicable = new Replicable <StatefulProgramInstance>(instance.Id.ToString(), instance);
                    ReplicationScope replicationScope = new ReplicationScope(new Replicable[] { replicable }, ReplicationOperationType.Evict);
                    replicationScope.ReplicateAsync().ContinueWith(
                        task =>
                    {
                        ReplicationResult result = task.IsFaulted ? ReplicationResult.Failed : task.Result;
                        if (result != ReplicationResult.Success)
                        {
                            AppTrace.TraceMsg(TraceLogEventType.Warning, "StatefulServiceReplicaT.DeleteInstanceInternal", "Replication call to dispose the instance with id {0} failed.", instance.Id);
                        }
                    },
                        TaskContinuationOptions.ExecuteSynchronously);
                }

                return(true);
            }
            else
            {
                return(false);
            }
        }
示例#2
0
        public void Notify()
        {
            ReplicationResult result = new ReplicationResult();

            result.OperatorNodeID    = NotifyingNode;
            result.Description       = null;
            result.LastNodeID        = null;
            result.LastUSN           = 0;
            result.LastChange        = DateTime.Now.Ticks;
            result.ReplicationStatus = ReplicationStatus.Notify;

            result.Save();
        }
示例#3
0
        protected override bool Run(object parameters)
        {
#if DEBUG
            Shared.EventLog.Debug("RepThread " + System.Reflection.MethodBase.GetCurrentMethod().Name);
#endif
            DatabaseConnection connection = (DatabaseConnection)parameters;
            bool tableUpdated             = false;

            TimeSpan ts = new TimeSpan(0, 2, 0);

            if (!_IsRunning && (DateTime.Now - _lastCheckUpdates) >= ts)
            {
                try
                {
                    _lastCheckUpdates = DateTime.Now;

                    // are we looking for remote updates to the database
                    if (connection.RemoteUpdate)
                    {
                        AddToLogFile(String.Format("{0} Checking Version", ConnectionName));

                        API api = new API();
                        try
                        {
                            DatabaseRemoteUpdate remoteUpdate = new DatabaseRemoteUpdate();
                            try
                            {
                                remoteUpdate.OnNewMessage += DatabaseRemoteUpdate_OnNewMessage;
                                int version = Version;

                                if (remoteUpdate.CheckForDatabaseUpdates(connection.Name,
                                                                         connection.ChildDatabase,
                                                                         connection.RemoteUpdateXML, connection.RemoteUpdateLocation,
                                                                         ref version, ref tableUpdated))
                                {
                                    Version = version;

                                    if (api.UpdateCurrentDatabaseVersion(connection, version))
                                    {
                                        string fileName = String.Empty;

                                        if (connection.ReplicateDatabase && connection.ReplicateUpdateTriggers && tableUpdated)
                                        {
                                            if (connection.ReplicationType == ReplicationType.Child)
                                            {
                                                //create replication triggers if needed and new database users
                                                ReplicationPrepareChildDatabase repEng = new ReplicationPrepareChildDatabase();
                                                try
                                                {
                                                    if (tableUpdated)
                                                    {
                                                        AddToLogFile(String.Format("{0} Rebuilding Child Replication Triggers", ConnectionName));
                                                    }

                                                    if (repEng.PrepareDatabaseForReplication(_databaseConnection.ChildDatabase,
                                                                                             tableUpdated, false, ref fileName, remoteUpdate))
                                                    {
                                                        AddToLogFile(String.Format("{0} Replication Child Triggers Rebuilt", ConnectionName));
                                                    }
                                                }
                                                finally
                                                {
                                                    repEng = null;
                                                }
                                            }
                                            else if (connection.ReplicationType == ReplicationType.Master)
                                            {
                                                //create replication triggers if needed and new database users
                                                ReplicationPrepareMasterDatabase repEng = new ReplicationPrepareMasterDatabase();
                                                try
                                                {
                                                    if (tableUpdated)
                                                    {
                                                        AddToLogFile(String.Format("{0} Rebuilding Master Replication Triggers", ConnectionName));
                                                    }

                                                    if (repEng.PrepareDatabaseForReplication(_databaseConnection.ChildDatabase,
                                                                                             tableUpdated, false, ref fileName, remoteUpdate))
                                                    {
                                                        AddToLogFile(String.Format("{0} Replication Master Triggers Rebuilt", ConnectionName));
                                                    }
                                                }
                                                finally
                                                {
                                                    repEng = null;
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                            finally
                            {
                                remoteUpdate.OnNewMessage -= DatabaseRemoteUpdate_OnNewMessage;
                                remoteUpdate = null;
                            }
                        }
                        finally
                        {
                            api = null;
                        }
                    }

                    // are we backing up the database
                    if (connection.BackupDatabase)
                    {
                        DateTime compare = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day,
                                                        connection.BackupAfterTime.Hour, connection.BackupAfterTime.Minute, 0);
                        TimeSpan spanLastBackup = DateTime.Now - connection.LastBackupTime;

                        if (
                            (
                                (!connection.BackupAfterTimeEnabled ||
                                 (connection.BackupAfterTimeEnabled && DateTime.Now.Subtract(compare).TotalMinutes >= 0)
                                ) ||
                                (spanLastBackup.TotalDays >= 1.0)
                            ))
                        {
                            AddToLogFile(String.Format("{0} Checking Backup", ConnectionName));
                            CheckLatestDBBackup();
                        }
                        else
                        {
                        }
                    }
                }
                catch (Exception errUB)
                {
                    Shared.EventLog.Add(errUB);
                }
            }

            int missingRecordCount = 0;

            try
            {
                if (CanReplicate && connection.ReplicationType == ReplicationType.Child)
                {
                    ts = new TimeSpan(0, _runInterval, 0); // xx minute increments

                    // has it been xx minutes since last run?
                    if (!_IsRunning && (DateTime.Now - LastRunReplication) >= ts)
                    {
                        AddToLogFile(String.Format("Run Replication {0}", ConnectionName));

                        _IsRunning = true;

                        //properties
                        _replicationEngine = new ReplicationEngine(
                            ConnectionName,
                            _databaseConnection.ReplicateDatabase,
                            _databaseConnection.ChildDatabase,
                            _databaseConnection.MasterDatabase);
                        try
                        {
                            _replicationEngine.Validate = true;

                            // settings
                            _replicationEngine.VerifyAllDataInterval = (int)_databaseConnection.VerifyDataInterval;
                            _replicationEngine.VerifyTableCounts     = 20;
#if ERROR_LIMIT_30000
                            _replicationEngine.ForceRestartErrorCount = 30000;
#else
                            _replicationEngine.ForceRestartErrorCount = (int)_databaseConnection.VerifyErrorReset;
#endif
                            _replicationEngine.MaximumDownloadCount = (int)_databaseConnection.MaximumDownloadCount;
                            _replicationEngine.MaximumUploadCount   = (int)_databaseConnection.MaximumUploadCount;
                            _replicationEngine.TimeOutMinutes       = (int)_databaseConnection.TimeOut;
                            _replicationEngine.RequireUniqueAccess  = _databaseConnection.RequireUniqueAccess;

                            // event hookups
                            _replicationEngine.OnProgress += new ReplicationPercentEventArgs(rep_OnProgress);
                            _replicationEngine.OnReplicationTextChanged += new ReplicationProgress(rep_OnReplicationTextChanged);
                            _replicationEngine.BeginReplication         += new ReplicationEventHandler(rep_BeginReplication);
                            _replicationEngine.EndReplication           += new ReplicationEventHandler(rep_EndReplication);
                            _replicationEngine.OnReplicationError       += new ReplicationError(rep_OnReplicationError);
                            _replicationEngine.OnIDChanged   += rep_OnIDChanged;
                            _replicationEngine.OnCheckCancel += _replicationEngine_OnCheckCancel;

                            //are we forcing hard confirm between certain hours?
                            if (!ForceVerifyRecords)
                            {
                                ForceVerifyRecords = ForceConfirmBasedOnHoursOrIterations();
                            }

                            _replicationError = _replicationEngine.Run(_allowConfirmCounts, ForceVerifyRecords);

                            missingRecordCount = _replicationEngine.MissingRecordCount;

                            switch (_replicationError)
                            {
                            case ReplicationResult.ThresholdExceeded:
                                _runInterval = 0;
                                break;

                            case ReplicationResult.UniqueAccessDenied:
                                // we do not reset force hard confirm here as it was set before the run
                                //_forceHardConfirm = _forceHardConfirm;
                                _runInterval = (int)_databaseConnection.ReplicateInterval;
                                break;
                            }

                            if (ForceVerifyRecords && (missingRecordCount >= _databaseConnection.VerifyErrorReset))
                            {
                                AddToLogFile(String.Format("{0} Force Verify Records Missing Records Exceeded", ConnectionName));
                                ForceVerifyRecords = true;
                                _runInterval       = 0;

                                // get list of confirmed tables so we don't scan them next time
                                //_confirmedTables = _replicationEngine.TablesConfirmedCorrect;
                            }
                            else
                            {
                                switch (_replicationError)
                                {
                                case ReplicationResult.TimeOutExceeded:
                                    //_confirmedTables = _replicationEngine.TablesConfirmedCorrect;
                                    _runInterval = (int)_databaseConnection.ReplicateInterval;
                                    AddToLogFile(String.Format("{0} Time out exceeded, restarting", ConnectionName));

                                    break;

                                case ReplicationResult.ThresholdExceeded:
                                    //_confirmedTables = _replicationEngine.TablesConfirmedCorrect;

                                    // we do not reset force hard confirm here as it was set before the run
                                    //_forceHardConfirm = _forceHardConfirm;
                                    _runInterval = 0;
                                    break;

                                case ReplicationResult.UniqueAccessDenied:
                                    //_confirmedTables = _replicationEngine.TablesConfirmedCorrect;
                                    _runInterval = (int)_databaseConnection.ReplicateInterval;
                                    AddToLogFile(String.Format("{0} Unique access for deep scan not allowed, retry next time...", ConnectionName));
                                    break;

                                case ReplicationResult.Error:
                                case ReplicationResult.DeepScanInitialised:
                                    //_confirmedTables = _replicationEngine.TablesConfirmedCorrect;
                                    _runInterval = 0;
                                    break;

                                case ReplicationResult.NotInitialised:
                                case ReplicationResult.Cancelled:
                                case ReplicationResult.Completed:
                                case ReplicationResult.DeepScanCompleted:
                                    ForceVerifyRecords = false;
                                    //_confirmedTables = String.Empty;
                                    _replicationEngine.Statuses.Clear();
                                    _runInterval = (int)_databaseConnection.ReplicateInterval;
                                    break;
                                }
                            }
                        }
                        finally
                        {
                            _replicationEngine.Dispose();
                            _replicationEngine = null;
                        }

                        _IsRunning         = false;
                        LastRunReplication = DateTime.Now;
                        _replicationCount++;

                        //log management
                        Shared.EventLog.ArchiveOldLogFiles();
                    }
                }

                TimeSpan t = LastRunReplication.AddMinutes(_runInterval) - DateTime.Now;
                SendToTCPClients(String.Format("Sleeping, time until next run {0}", t.ToString().Substring(0, 8)));
            }
            catch (Exception err)
            {
                Shared.EventLog.Add(err);
                _IsRunning = false;
                AddToLogFile(String.Format("{0} {1}", ConnectionName, err.Message));
                AddToLogFile(err.StackTrace.ToString());
                LastRunReplication = DateTime.Now;
            }
            finally
            {
                IndicateNotHanging();
            }

            return(true);
        }
示例#4
0
        // 启动一般监控任务
        public static void StartMonitorTask()
        {
            if (_monitorTask != null)
            {
                return;
            }

            PerdayTask.StartPerdayTask();

            CancellationToken token = _cancel.Token;

            // bool download_complete = false;

            token.Register(() =>
            {
                _eventMonitor.Set();
            });

            _monitorTask = Task.Factory.StartNew(async() =>
            {
                WpfClientInfo.WriteInfoLog("书柜监控专用线程开始");
                try
                {
                    while (token.IsCancellationRequested == false)
                    {
                        // await Task.Delay(TimeSpan.FromSeconds(10));
                        _eventMonitor.WaitOne(_monitorIdleLength);

                        token.ThrowIfCancellationRequested();

                        // ***
                        // 关闭天线射频
                        if (_tagAdded)
                        {
                            _ = Task.Run(async() =>
                            {
                                try
                                {
                                    await SelectAntennaAsync();
                                }
                                catch (Exception ex)
                                {
                                    WpfClientInfo.WriteErrorLog($"关闭天线射频 SelectAntennaAsync() 时出现异常: {ExceptionUtil.GetDebugText(ex)}");
                                }
                            });
                            _tagAdded = false;
                        }

                        if (DateTime.Now - _lastDetectTime > _detectPeriod)
                        {
                            DetectLibraryNetwork();

                            _lastDetectTime = DateTime.Now;
                        }

                        // 提醒关门
                        WarningCloseDoor();

                        // 下载或同步读者信息
                        string startDate = LoadStartDate();
                        if (/*download_complete == false || */
                            string.IsNullOrEmpty(startDate) &&
                            _replicatePatronError == 0)
                        {
                            // 如果 Config 中没有记载断点位置,说明以前从来没有首次同步过。需要进行一次首次同步
                            if (string.IsNullOrEmpty(startDate))
                            {
                                // SaveStartDate("");

                                var repl_result = await PatronReplication.DownloadAllPatronRecordAsync(
                                    (text) =>
                                {
                                    WpfClientInfo.WriteInfoLog(text);
                                    PageShelf.TrySetMessage(null, text);
                                },
                                    token);
                                if (repl_result.Value == -1)
                                {
                                    // TODO: 判断通讯出错的错误码。如果是通讯出错,则稍后需要重试下载
                                    _replicatePatronError++;
                                }
                                else
                                {
                                    SaveStartDate(repl_result.StartDate);
                                }

                                // 立刻允许接着做一次零星同步
                                ActivateMonitor();
                            }
                            // download_complete = true;
                        }
                        else
                        {
                            // 进行零星同步
                            if (DateTime.Now - _lastReplicateTime > _replicatePeriod)
                            {
                                // string startDate = LoadStartDate();

                                // testing
                                // startDate = "20200507:0-";

                                if (string.IsNullOrEmpty(startDate) == false)
                                {
                                    string endDate = DateTimeUtil.DateTimeToString8(DateTime.Now);

                                    // parameters:
                                    //      strLastDate   处理中断或者结束时返回最后处理过的日期
                                    //      last_index  处理或中断返回时最后处理过的位置。以后继续处理的时候可以从这个偏移开始
                                    // return:
                                    //      -1  出错
                                    //      0   中断
                                    //      1   完成
                                    ReplicationResult repl_result = await PatronReplication.DoReplication(
                                        startDate,
                                        endDate,
                                        LogType.OperLog,
                                        token);
                                    if (repl_result.Value == -1)
                                    {
                                        WpfClientInfo.WriteErrorLog($"同步出错: {repl_result.ErrorInfo}");
                                    }
                                    else if (repl_result.Value == 1)
                                    {
                                        string lastDate = repl_result.LastDate + ":" + repl_result.LastIndex + "-";    // 注意 - 符号不能少。少了意思就会变成每次只获取一条日志记录了
                                        SaveStartDate(lastDate);
                                    }

                                    _lastReplicateTime = DateTime.Now;
                                }
                            }
                        }
                    }
                    _monitorTask = null;
                }
                catch (OperationCanceledException)
                {
                }
                catch (Exception ex)
                {
                    WpfClientInfo.WriteErrorLog($"书柜监控专用线程出现异常: {ExceptionUtil.GetDebugText(ex)}");
                    App.SetError("shelf_monitor", $"书柜监控专用线程出现异常: {ex.Message}");
                }
                finally
                {
                    WpfClientInfo.WriteInfoLog("书柜监控专用线程结束");
                }
            },
                                                 token,
                                                 TaskCreationOptions.LongRunning,
                                                 TaskScheduler.Default);
        }
        protected internal sealed override IEnumerable <Replicable> ReplicationOperationComplete(StatefulServiceExecutionContext executionContext, ReplicationResult result, ReplicationOperation replicationOperation)
        {
            if (this.IsDisposed)
            {
                AppTrace.TraceMsg(TraceLogEventType.Information, "StatefulServiceReplicaT.ReplicationOperationComplete", "ReplicationOperationComplete called after service was disposed");
                return(Enumerable.Empty <Replicable>());
            }

            StatefulProgramInstance instance = null;
            Replicable <StatefulProgramInstance> replicableToCommit = replicationOperation.Replicables.FirstOrDefault() as Replicable <StatefulProgramInstance>;

            if (replicableToCommit != null)
            {
                instance = this.instanceManager.GetInstance(replicableToCommit.Value.Id) as StatefulProgramInstance;
                if (instance != null)
                {
                    instance.SetContextInstanceId();
                }
                else if (replicableToCommit.Value != null)
                {
                    Debug.Assert(replicationOperation.Type == ReplicationOperationType.Evict, "Unexpected operation type");
                    replicableToCommit.Value.SetContextInstanceId();
                }
                else
                {
                    Debug.Assert(false, "replicableToCommit.Value is null");
                }
            }

            AppTrace.TraceMsg(
                TraceLogEventType.Information,
                "StatefulComponent.ReplicationOperationComplete",
                "replicationOperation.Type={0}, result={1}, replicables.Count={2}, replicableToCommit={3}, programInstance={4}",
                replicationOperation.Type,
                result,
                replicationOperation.Replicables.Count(),
                replicableToCommit != null ? replicableToCommit.Name : "Null",
                instance != null ? instance.Id : "Null");

            IEnumerable <Replicable> replicablesToCommit = null;

            if (replicationOperation.Type == ReplicationOperationType.Replicate)
            {
                if (result == ReplicationResult.Success)
                {
                    List <Replicable> changes = new List <Replicable>();

                    if (replicableToCommit.IsDisposed)
                    {
                        foreach (Replicable replicable in replicableToCommit.Value.DataContractReplicables)
                        {
                            changes.Add(replicable);
                        }
                    }
                    else
                    {
                        ItemCollection <string, Replicable> replicables;
                        using (instance.GetReplicables(LockPermission.Write, out replicables))
                        {
                            foreach (Replicable replicable in replicableToCommit.Value.DataContractReplicables)
                            {
                                if (replicables.Contains(replicable.Name))
                                {
                                    replicables.Remove(replicable.Name);
                                    replicables.Add(replicable);
                                }
                                else
                                {
                                    replicables.Add(replicable);
                                }

                                changes.Add(replicable);
                            }
                        }
                    }

                    replicablesToCommit = changes;
                }
                else
                {
                    if (instance != null)
                    {
                        AppTrace.TraceMsg(TraceLogEventType.Error, "StatefulServiceReplicaT.ReplicationOperationComplete", "Recycling StatefulProgramInstance with id '{0}'", instance.Id);
                        instance.RecycleInstance();
                    }

                    replicablesToCommit = base.ReplicationOperationComplete(executionContext, result, replicationOperation);
                }
            }

            if (replicablesToCommit == null)
            {
                replicablesToCommit = base.ReplicationOperationComplete(executionContext, result, replicationOperation);
            }

            return(replicablesToCommit);
        }
示例#6
0
        static void Main(string[] args)
        {
            Console.WriteLine("Microsoft (R) UDDI Monitor Utility");
            Console.WriteLine("Copyright (C) Microsoft Corp. 2002. All rights reserved.\r\n");

            try
            {
                ProcessCommandLine(args);

                ArrayList results = new ArrayList();

                ConnectionManager.Open(false, false);

                //
                // Get the list of known operatorNodes.
                //
                OperatorNodeCollection operatorNodes = new OperatorNodeCollection();
                operatorNodes.Get();

                //
                // Get the last notification message status for each operator.
                //
                foreach (OperatorNode operatorNode in operatorNodes)
                {
                    ReplicationResult result = new ReplicationResult();

                    result.GetLast(operatorNode.OperatorNodeID, true);

                    results.Add(result);
                }

                //
                // Monitor changes to operator status every 5 seconds.
                //
                while (true)
                {
                    Console.WriteLine("Polling for new notifications: {0}.  Press Ctrl+C to stop.", DateTime.Now);

                    for (int i = 0; i < operatorNodes.Count; i++)
                    {
                        ReplicationResult lastResult = (ReplicationResult)results[i];
                        ReplicationResult result     = new ReplicationResult();

                        result.GetLast(operatorNodes[i].OperatorNodeID, true);

                        //
                        // Check to see if a notification message has been received
                        //
                        if (result.LastChange > lastResult.LastChange)
                        {
                            DateTime time = new DateTime(result.LastChange);

                            Console.WriteLine(
                                "\r\n\tnotify_changeRecordsAvailable detected\r\n\t\tNode: {0}\r\n\t\tTime: {1}",
                                result.OperatorNodeID,
                                time);

                            //
                            // Execute the specified file.
                            //
                            Console.WriteLine(
                                "\t\tStarting: {0} -o {1}",
                                Program,
                                result.OperatorNodeID);

                            Process process = Process.Start(Program, "-o " + result.OperatorNodeID);

                            process.WaitForExit();

                            Console.WriteLine(
                                "\t\tReturn code: {0}\r\n",
                                process.ExitCode);

                            //
                            // Save the current notify result so that we don't
                            // reprocess.
                            //
                            results[i] = result;
                        }
                    }

                    System.Threading.Thread.Sleep(PollInterval);
                }
            }
            catch (CommandLineException e)
            {
                if (null != e.Message && e.Message.Length > 0)
                {
                    Console.WriteLine(e.Message);
                    Console.WriteLine();
                }
                else
                {
                    DisplayUsage();
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("Exception: {0}", e.ToString());
            }
            finally
            {
                ConnectionManager.Close();
            }

            return;
        }
示例#7
0
        // 启动一般监控任务
        public static void StartMonitorTask()
        {
            if (_monitorTask != null)
            {
                return;
            }

            CancellationToken token = _cancel.Token;
            bool download_complete  = false;

            token.Register(() =>
            {
                _eventMonitor.Set();
            });

            _monitorTask = Task.Factory.StartNew(async() =>
            {
                WpfClientInfo.WriteInfoLog("监控专用线程开始");
                try
                {
                    while (token.IsCancellationRequested == false)
                    {
                        // await Task.Delay(TimeSpan.FromSeconds(10));
                        _eventMonitor.WaitOne(_monitorIdleLength);

                        token.ThrowIfCancellationRequested();

                        // ***
                        // 关闭天线射频
                        if (_tagAdded)
                        {
                            _ = Task.Run(async() =>
                            {
                                try
                                {
                                    await SelectAntennaAsync();
                                }
                                catch (Exception ex)
                                {
                                    WpfClientInfo.WriteErrorLog($"关闭天线射频 SelectAntennaAsync() 时出现异常: {ExceptionUtil.GetDebugText(ex)}");
                                }
                            });
                            _tagAdded = false;
                        }

                        if (DateTime.Now - _lastDetectTime > _detectPeriod)
                        {
                            DetectLibraryNetwork();

                            _lastDetectTime = DateTime.Now;
                        }

                        // 提醒关门
                        WarningCloseDoor();

                        // 下载或同步读者信息
                        string startDate = LoadStartDate();
                        if (/*download_complete == false || */
                            string.IsNullOrEmpty(startDate))
                        {
                            // 如果 Config 中没有记载断点位置,说明以前从来没有首次同步过。需要进行一次首次同步
                            if (string.IsNullOrEmpty(startDate))
                            {
                                // SaveStartDate("");

                                var repl_result = await PatronReplication.DownloadAllPatronRecordAsync(token);
                                if (repl_result.Value == -1)
                                {
                                    // TODO: 判断通讯出错的错误码。如果是通讯出错,则稍后需要重试下载
                                }
                                else
                                {
                                    SaveStartDate(repl_result.StartDate);
                                }

                                // 立刻允许接着做一次零星同步
                                ActivateMonitor();
                            }
                            // download_complete = true;
                        }
                        else
                        {
                            // 进行零星同步
                            if (DateTime.Now - _lastReplicateTime > _replicatePeriod)
                            {
                                // string startDate = LoadStartDate();

                                // testing
                                // startDate = "20200507:0-";

                                if (string.IsNullOrEmpty(startDate) == false)
                                {
                                    string endDate = DateTimeUtil.DateTimeToString8(DateTime.Now);

                                    // parameters:
                                    //      strLastDate   处理中断或者结束时返回最后处理过的日期
                                    //      last_index  处理或中断返回时最后处理过的位置。以后继续处理的时候可以从这个偏移开始
                                    // return:
                                    //      -1  出错
                                    //      0   中断
                                    //      1   完成
                                    ReplicationResult repl_result = PatronReplication.DoReplication(
                                        startDate,
                                        endDate,
                                        LogType.OperLog,
                                        token);
                                    if (repl_result.Value == -1)
                                    {
                                        WpfClientInfo.WriteErrorLog($"同步出错: {repl_result.ErrorInfo}");
                                    }
                                    else if (repl_result.Value == 1)
                                    {
                                        string lastDate = repl_result.LastDate + ":" + repl_result.LastIndex + "-";    // 注意 - 符号不能少。少了意思就会变成每次只获取一条日志记录了
                                        SaveStartDate(lastDate);
                                    }

                                    _lastReplicateTime = DateTime.Now;
                                }
                            }
                        }

                        // 检查升级 dp2ssl
                        if (_updated == false
                            // && StringUtil.IsDevelopMode() == false
                            && ApplicationDeployment.IsNetworkDeployed == false &&
                            DateTime.Now - _lastUpdateTime > _updatePeriod)
                        {
                            WpfClientInfo.WriteInfoLog("开始自动检查升级");
                            // result.Value:
                            //      -1  出错
                            //      0   经过检查发现没有必要升级
                            //      1   成功
                            //      2   成功,但需要立即重新启动计算机才能让复制的文件生效
                            var update_result = await GreenInstaller.InstallFromWeb("http://dp2003.com/dp2ssl/v1_dev",
                                                                                    "c:\\dp2ssl",
                                                                                    "delayExtract,updateGreenSetupExe",
                                                                                    //true,
                                                                                    //true,
                                                                                    token,
                                                                                    null);
                            if (update_result.Value == -1)
                            {
                                WpfClientInfo.WriteErrorLog($"自动检查升级出错: {update_result.ErrorInfo}");
                            }
                            else
                            {
                                WpfClientInfo.WriteInfoLog($"结束自动检查升级 update_result:{update_result.ToString()}");
                            }

                            if (update_result.Value == 1 || update_result.Value == 2)
                            {
                                App.TriggerUpdated("重启可使用新版本");
                                _updated = true;
                                PageShelf.TrySetMessage(null, "dp2SSL 升级文件已经下载成功,下次重启时可自动升级到新版本");
                            }
                            _lastUpdateTime = DateTime.Now;
                        }
                    }
                    _monitorTask = null;
                }
                catch (OperationCanceledException)
                {
                }
                catch (Exception ex)
                {
                    WpfClientInfo.WriteErrorLog($"监控专用线程出现异常: {ExceptionUtil.GetDebugText(ex)}");
                    App.SetError("monitor", $"监控专用线程出现异常: {ex.Message}");
                }
                finally
                {
                    WpfClientInfo.WriteInfoLog("监控专用线程结束");
                }
            },
                                                 token,
                                                 TaskCreationOptions.LongRunning,
                                                 TaskScheduler.Default);
        }