示例#1
0
        void P_LogAttemptContinuation(Task <IRunControlAttemptSuccess> completion)
        {
            completion.EnsureNotNull(nameof(completion));
            //
            RunControlAttemptLoggingData loggingData;

            if (completion.IsCanceled || completion.IsFaulted)
            {
                var endTimestamp = StopwatchUtilities.GetTimestampAsTimeSpan();
                var attemptState = itrlck.Get(location: ref _attemptState);
                if (!(attemptState is null))
                {
                    // Если состояние попытки не было установлено операцией запуска/остановки, то такая попытка считается "пустой". См. код Start/Stop.
                    //
                    if (completion.IsCanceled)
                    {
                        loggingData = new RunControlAttemptLoggingData(runControl: RunControl, isStart: attemptState.IsStart, attemptNumber: attemptState.AttemptNumber, succeededAttemptCountBefore: attemptState.SucceededAttemptCountBefore, status: OperationCompletionStatusCode.Cancel, duration: endTimestamp.Subtract(ts: BeginTimestamp), correlationId: attemptState.CorrelationId);
                    }
                    else
                    {
                        Exception completionException = default;
                        try {
                            completion.GetAwaiter().GetResult();
                        }
                        catch (Exception locException) {
                            completionException = locException;
                        }
                        loggingData = new RunControlAttemptLoggingData(runControl: RunControl, isStart: attemptState.IsStart, attemptNumber: attemptState.AttemptNumber, succeededAttemptCountBefore: attemptState.SucceededAttemptCountBefore, status: OperationCompletionStatusCode.Fault, exception: completionException, duration: endTimestamp.Subtract(ts: BeginTimestamp), correlationId: attemptState.CorrelationId);
                    }
                }
                else
                {
                    loggingData = null;
                }
            }
示例#2
0
        // TODO: Put strings into the resources.
        //
        public RunControlAttemptSuccess SetSucceeded(bool isMaster)
        {
            var success = new RunControlAttemptSuccess(duration: StopwatchUtilities.GetTimestampAsTimeSpan().Subtract(ts: BeginTimestamp), isMaster: isMaster, props: AttemptState);

            if (_completionProxy.TrySetResult(result: success))
            {
                return(success);
            }
            else
            {
                throw new EonException(message: $"Final state has already been set earlier.{Environment.NewLine}\tComponent:{RunControl.FmtStr().GNLI2()}");
            }
        }
示例#3
0
        // TODO: Put strings into the resources.
        //
        Task <IRunControlAttemptSuccess> P_StopAsync(IContext ctx = default, bool finiteStop = default, AsyncOperationCallOption option = default)
        {
            try {
                if (!(option == AsyncOperationCallOption.ExistingOrNew || option == AsyncOperationCallOption.DefaultOrNew))
                {
                    throw new ArgumentOutOfRangeException(paramName: nameof(option));
                }
                //
                return(TaskUtilities.RunOnDefaultScheduler(factory: doStopAsync));
            }
            catch (Exception exception) {
                return(TaskUtilities.FromError <IRunControlAttemptSuccess>(exception));
            }
            //
            async Task <IRunControlAttemptSuccess> doStopAsync()
            {
                ctx.ThrowIfCancellationRequested();
                finiteStop = finiteStop || (Options & RunControlOptions.SingleStart) == RunControlOptions.SingleStart;
                var correlationId  = ctx?.FullCorrelationId;
                var ctxCt          = ctx.Ct();
                var existingStopOp = default(RunControlStopOperationState <TComponent>);
                var newStopOp      = default(RunControlStopOperationState <TComponent>);
                var component      = TryReadDA(ref _component);
                var beginTimestamp = StopwatchUtilities.GetTimestampAsTimeSpan();
                var tryCatchFinallyAffectsNewStopOp = true;

                try {
                    var setStopOpResult =
                        itrlck
                        .Update(
                            location: ref _existingStopOp,
                            transform:
                            (locCurrent, locPrevious) => {
                        if (locCurrent is null || (finiteStop && !locCurrent.FiniteStop))
                        {
                            return(locPrevious ?? (newStopOp = new RunControlStopOperationState <TComponent>(runControl: this, beginTimestamp: locCurrent?.BeginTimestamp ?? beginTimestamp, ct: ctxCt, finiteStop: finiteStop)));
                        }
                        else
                        {
                            return(locCurrent);
                        }
                    });
示例#4
0
        // TODO: Put strings into the resources.
        //
        public Task <IRunControlAttemptSuccess> StartAsync(IContext ctx = default)
        {
            try {
                var component = Component;
                if ((Options & RunControlOptions.ForbidStart) == RunControlOptions.ForbidStart)
                {
                    throw new EonException(message: $"Опциями элемента управления запуском/остановкой компонента, запрещено выполнение операции запуска.{Environment.NewLine}\tКомпонент:{component.FmtStr().GNLI2()}");
                }
                else
                {
                    return(TaskUtilities.RunOnDefaultScheduler(factory: doStartAsync));
                }
            }
            catch (Exception exception) {
                return(Task.FromException <IRunControlAttemptSuccess>(exception: exception));
            }
            //
            async Task <IRunControlAttemptSuccess> doStartAsync()
            {
                ctx.ThrowIfCancellationRequested();
                var ctxCt           = ctx.Ct();
                var existingStartOp = default(RunControlStartOperationState <TComponent>);
                var newStartOp      = default(RunControlStartOperationState <TComponent>);
                var component       = Component;
                var begimTimestamp  = StopwatchUtilities.GetTimestampAsTimeSpan();

                try {
                    UpdDABool(
                        location: ref _existingStartOp,
                        transform:
                        (locCurrent, locPrevious) => {
                        if (locCurrent is null)
                        {
                            return(locPrevious ?? (newStartOp = new RunControlStartOperationState <TComponent>(runControl: this, beginTimestamp: begimTimestamp, ct: ctxCt)));
                        }
                        else
                        {
                            return(locCurrent);
                        }
                    },
                        current: out existingStartOp);
                    if (ReferenceEquals(newStartOp, existingStartOp))
                    {
                        // Поток (задача), который непосредственно выполняет запуск.
                        //
                        if (!itrlck.IncrementBool(location: ref _startOpAttemptNumber, maxInclusive: int.MaxValue, result: out var attemptNumber))
                        {
                            throw
                                new EonException(message: $"Невозможно присвоить операции последовательный номер попытки. Счётчик попыток достиг предельного значения.{Environment.NewLine}\tКомпонент:{component.FmtStr().GNLI2()}");
                        }
                        // Если выполняется операция остановки, то дождаться её завершения.
                        //
                        var existingStopOp = itrlck.Get(ref _existingStopOp);
                        if (!(existingStopOp is null))
                        {
                            try {
                                await existingStopOp.Completion.WaitCompletionAsync(ct : ctxCt).ConfigureAwait(false);
                            }
                            catch (Exception exception) {
                                if (exception.HasSingleBaseExceptionOf <OperationCanceledException>(out var operationCancellationException))
                                {
                                    itrlck.SetNullBool(ref _existingStartOp, comparand: newStartOp);
                                    newStartOp.TrySetCanceled(ct: operationCancellationException.CancellationToken);
                                }
                                throw;
                            }
                            try {
                                await existingStopOp.Completion.ConfigureAwait(false);
                            }
                            catch (Exception exception) when(exception.HasSingleBaseExceptionOf <OperationCanceledException>())
                            {
                                throw
                                    new EonException(
                                        message: $"Невозможно выполнить запуск компонента, так как ранее для компонента была инициирована операция остановки, которая была прервана или отменена.{Environment.NewLine}\tКомпонент:{component.FmtStr().GNLI2()}");
                            }
                            catch (Exception exception) {
                                throw
                                    new EonException(
                                        message: $"Невозможно выполнить запуск компонента, так как ранее для компонента была инициирована операция остановки, которая завершилась сбоем. Детали сбоя см. во внутреннем стеке данного исключения.{Environment.NewLine}\tКомпонент:{component.FmtStr().GNLI2()}",
                                        innerException: exception);
                            }
                            if ((Options & RunControlOptions.MultipleStart) == RunControlOptions.MultipleStart)
                            {
                                if (existingStopOp.FiniteStop)
                                {
                                    newStartOp.TrySetCanceled();
                                    throw
                                        new OperationCanceledException(
                                            message: $"Запуск компонента отменён, так как ранее поступил запрос остановки компонента без возможности перезапуска.{Environment.NewLine}\tКомпонент:{component.FmtStr().GNLI2()}");
                                }
                                else if (!itrlck.SetNullBool(ref _existingStopOp, comparand: existingStopOp))
                                {
                                    throw
                                        new EonException(
                                            message: $"Не удалось привести управляющий элемент запуска/остановки компонента к предстартовому состоянию.{Environment.NewLine}\tКомпонент:{component.FmtStr().GNLI2()}");
                                }
                            }
                            else
                            {
                                newStartOp.TrySetCanceled();
                                throw
                                    new OperationCanceledException(
                                        message: $"Запуск компонента отменён, так как ранее поступил запрос остановки компонента и опциями элемента, управляющего запуском/остановкой компонента, не определена возможность многократного запуска компонента.{Environment.NewLine}\tКомпонент:{component.FmtStr().GNLI2()}");
                            }
                        }
                        // Запуск.
                        //
                        IContext locCtx = default;
                        try {
                            try {
                                locCtx = P_CreateStartCtx(startOp: newStartOp, outerCtx: ctx);
                                newStartOp.AttemptState =
                                    ReadDA(ref _attemptStateFactory)
                                        (args:
                                        new RunControlAttemptStateFactoryArgs(
                                            runControl: this,
                                            completion: newStartOp.Completion,
                                            context: locCtx,
                                            isStart: true,
                                            attemptNumber: attemptNumber,
                                            succeededAttemptCountBefore: vlt.Read(ref _startOpSucceededCount)));
                            }
                            catch (Exception exception) {
                                if (exception.HasSingleBaseExceptionOf <OperationCanceledException>(baseException: out var operationCancellationException))
                                {
                                    itrlck.SetNullBool(location: ref _existingStartOp, comparand: newStartOp);
                                    newStartOp.TrySetCanceled(ct: operationCancellationException.CancellationToken);
                                }
                                throw;
                            }
                            // Процедура предзапуска.
                            //
                            try {
                                locCtx.ThrowIfCancellationRequested();
                                await P_BeforeStartAsync(state : newStartOp.AttemptState).ConfigureAwait(false);
                            }
                            catch (Exception exception) {
                                itrlck.SetNullBool(ref _existingStartOp, comparand: newStartOp);
                                if (exception.HasSingleBaseExceptionOf <OperationCanceledException>(out var operationCancellationException))
                                {
                                    newStartOp.TrySetCanceled(ct: operationCancellationException.CancellationToken);
                                    throw;
                                }
                                else
                                {
                                    throw new EonException(message: $"Сбой во время процедуры предзапуска компонента.{Environment.NewLine}\tКомпонент:{component.FmtStr().GNLI2()}", innerException: exception);
                                }
                            }
                            // Процедура запуска.
                            //
                            try {
                                locCtx.ThrowIfCancellationRequested();
                                var startTask = ReadDA(ref _startTaskFactory)(arg : newStartOp.AttemptState);
                                if (startTask is null)
                                {
                                    throw new EonException(message: $"Невозможно выполнить операцию запуска компонента, так как функция создания задачи выполнения запуска возвратила недопустимый результат '{startTask.FmtStr().G()}'.{Environment.NewLine}\tКомпонент:{component.FmtStr().GNLI2()}");
                                }
                                await startTask.ConfigureAwait(false);
                            }
                            catch (Exception exception) {
                                if (exception.HasSingleBaseExceptionOf <OperationCanceledException>(out var operationCancellationException))
                                {
                                    itrlck.SetNullBool(ref _existingStartOp, comparand: newStartOp);
                                    newStartOp.TrySetCanceled(ct: operationCancellationException.CancellationToken);
                                    throw;
                                }
                                else
                                {
                                    throw new EonException(message: $"Сбой во время запуска компонента.{Environment.NewLine}\tКомпонент:{component.FmtStr().GNLI2()}", innerException: exception);
                                }
                            }
                            itrlck.IncrementBool(location: ref _startOpSucceededCount, maxInclusive: int.MaxValue);
                            var result = newStartOp.SetSucceeded(isMaster: true);
                            P_TryFireAfterStartAsynchronously(result: result);
                            return(result);
                        }
                        finally {
                            locCtx?.Dispose();
                        }
                    }
                    else
                    {
                        newStartOp?.TrySetCanceled(synchronously: true);
                        // TODO_HIGH: Возможно, нужно обрабатывать такую ситуацию, когда данный вызов получит результат в виде отменённой операции, потому что уже выполняющий другой вызов был отменён. Такая ситуация с точки зрения вызывающий стороны не совсем очевидна и предсказуема.
                        // + нужно реализовать трансляцию хода выполнения из уже выполняющегося вызова в данный.
                        //
                        if (ctxCt == existingStartOp.Ct)
                        {
                            // Один и тот же токен отмены из разных вызовов.
                            //
                            return(new RunControlAttemptSuccess(other: await existingStartOp.Completion.ConfigureAwait(false), isMaster: false));
                        }
                        else
                        {
                            return(new RunControlAttemptSuccess(other: await existingStartOp.Completion.WaitResultAsync(ct: ctxCt).ConfigureAwait(false), isMaster: false));
                        }
                    }
                }
                catch (Exception exception) {
                    if (ReferenceEquals(existingStartOp, newStartOp) && !(newStartOp is null))
                    {
                        if (newStartOp.TrySetException(exception: exception, synchronously: true))
                        {
                            // Здесь будет вызвано исключение.
                            //
                            await newStartOp.Completion;
                        }
                        throw;
                    }
                    else
                    {
                        throw;
                    }
                }
                finally {
                    if (!ReferenceEquals(existingStartOp, newStartOp))
                    {
                        newStartOp?.TrySetCanceled(synchronously: true);
                    }
                }
            }
        }
示例#5
0
 public void OnCompleted()
 {
     Interlocked.CompareExchange(ref _completeTimestamp, StopwatchUtilities.GetTimestampAsTicks(), -1L);
     _worker.P_OnLoopPostingCompleted(operation: this);
 }
示例#6
0
        // TODO: Put strings into the resources.
        //
        Task <IXAppScopeInstance> P_ResetComponentAsync(Func <IContext, bool> breakCondition = default, ITriggerSignalProperties triggerSignalProps = default, bool doFailureResponse = default, IContext ctx = default)
        {
            try {
                if (breakCondition is null)
                {
                    breakCondition =
                        (locContext) => {
                        locContext.ThrowIfCancellationRequested();
                        return(!IsActive || HasDeactivationRequested);
                    }
                }
                ;
                //
                var      startTimestamp = StopwatchUtilities.GetTimestampAsTimeSpan();
                IContext locCtx         = default;
                try {
                    var resetNumber        = Interlocked.Increment(ref _resetCounter);
                    var failureResponseDlg = ReadIA(ref _resetFailureResponseDelegate, isNotRequired: true, locationName: nameof(_resetFailureResponseDelegate));
                    var state = new P_ResetState();
                    locCtx = CreateScopedContext(outerCtx: ctx, localTag: state);
                    var logMessagePrologue = $"{(resetNumber == 0 ? "Установка компонента." : $"Замена (переустановка) компонента. Порядковый номер замены: {resetNumber:d}.")} ИД корреляции: {locCtx.FullCorrelationId}.{(triggerSignalProps is null ? string.Empty : $"{Environment.NewLine}\tСобытие-инициатор:{triggerSignalProps.FmtStr().GNLI2()}")}";
                    if (locCtx.IsCancellationRequested())
                    {
                        return(Task.FromCanceled <IXAppScopeInstance>(cancellationToken: locCtx.Ct()));
                    }
                    var resetTask = TaskUtilities.RunOnDefaultScheduler(factory: async() => await doResetAsync(locCtx: locCtx).ConfigureAwait(false));
                    // Вывод результатов ресета в лог.
                    //
#if !DO_NOT_USE_EON_LOGGING_API
                    resetTask
                    .ContinueWith(
                        continuationAction:
                        locTask => {
                        var locDuration = StopwatchUtilities.GetTimestampAsTimeSpan().Subtract(ts: startTimestamp);
                        if (locTask.IsFaulted)
                        {
                            this
                            .IssueError(
                                messagePrologue: logMessagePrologue,
                                message: $"Длительность:{locDuration.ToString("c").FmtStr().GNLI()}{Environment.NewLine}Сбой.",
                                error: locTask.Exception,
                                includeErrorInIssueFaultException: true,
                                severityLevel: locTask.Exception.GetMostHighSeverityLevel(baseLevel: SeverityLevel.Medium));
                            locTask.Exception.MarkAsObserved();
                        }
                        else if (locTask.IsCanceled)
                        {
                            this
                            .IssueWarning(
                                messagePrologue: logMessagePrologue,
                                message: $"Длительность:{locDuration.ToString("c").FmtStr().GNLI()}{Environment.NewLine}Отменено или прервано.",
                                severityLevel: SeverityLevel.Medium);
                        }
                        else
                        {
                            this
                            .IssueInformation(
                                messagePrologue: logMessagePrologue,
                                message: $"Длительность:{locDuration.ToString("c").FmtStr().GNLI()}{Environment.NewLine}Успешно выполнено.{Environment.NewLine}\tНовый экземпляр компонента:{locTask.Result.FmtStr().GNLI2()}",
                                severityLevel: SeverityLevel.Medium);
                        }
                    },
                        continuationOptions: TaskContinuationOptions.ExecuteSynchronously);
#endif
                    // Обработка сбоя ресета.
                    //
                    Task failureResponseTask;
                    if (doFailureResponse && !(failureResponseDlg is null))
                    {
                        failureResponseTask =
                            resetTask
                            .ContinueWith(
                                continuationFunction:
                                locTask => {
                            if (!(state.PreviousComponent is null))
                            {
                                // Корректирующие действие сбоя ресета выполняется только в случае именно замены компонента.
                                //
                                return
                                (doFailureCorrectiveAsync(
                                     locFailure: locTask.Exception,
                                     responseDlg: failureResponseDlg,
                                     locCtx: locCtx,
                                     logMessagePrologue: logMessagePrologue));
                            }
                            else
                            {
                                return(TaskUtilities.FromCanceled());
                            }
                        },
                                continuationOptions: TaskContinuationOptions.PreferFairness | TaskContinuationOptions.OnlyOnFaulted)
                            .Unwrap();
                        // Вывод результатов обработки сбоя в лог.
                        //
#if !DO_NOT_USE_EON_LOGGING_API
                        failureResponseTask
                        .ContinueWith(
                            continuationAction:
                            locTask => {
                            if (locTask.IsFaulted)
                            {
                                this
                                .IssueError(
                                    messagePrologue: logMessagePrologue,
                                    message: $"Корректирующее действие при сбое замены (переустановки) компонента.{Environment.NewLine}Сбой корректирующего действия.",
                                    error: locTask.Exception,
                                    includeErrorInIssueFaultException: true,
                                    severityLevel: locTask.Exception.GetMostHighSeverityLevel(baseLevel: SeverityLevel.High));
                            }
                            else
                            {
                                this
                                .IssueInformation(
                                    messagePrologue: logMessagePrologue,
                                    message: $"Корректирующее действие при сбое замены (переустановки) компонента.{Environment.NewLine}Корректирующее действие успешно выполнено.",
                                    severityLevel: SeverityLevel.Medium);
                            }
                        },
                            continuationOptions: TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.NotOnCanceled);
#endif
                    }