static Task P_BeforeDisposeAsync(P_Lifecycle lifecycle, Action continuation) { try { if (lifecycle is null) { throw new ArgumentNullException(paramName: nameof(lifecycle)); } // if (lifecycle.Disposing || lifecycle.IsDisposed) { return(TaskUtilities.FromVoidResult()); } else { return(doDisposeAsync()); } } catch (Exception exception) { return(TaskUtilities.FromError(error: exception)); } // async Task doDisposeAsync() { lifecycle.SetDisposeRequested(); var acquisition = lifecycle._acquisition; if (!(acquisition is null)) { await acquisition.ReleaseAsync().ConfigureAwait(false); } continuation?.Invoke(); } }
public Task StopAsync() { try { return(ReadDA(ref _runControl).StopAsync()); } catch (Exception firstException) { return(TaskUtilities.FromError(error: firstException)); } }
static Task P_DefaultRelease(IVh <T> instance) { try { instance?.Dispose(); return(TaskUtilities.FromVoidResult()); } catch (Exception exception) { return(TaskUtilities.FromError(exception)); } }
static Func <IVh <T>, Task> P_GetReleaseDelegate(Action <IVh <T> > release) { release.EnsureNotNull(nameof(release)); // return ((locInstance) => { try { release(locInstance); return TaskUtilities.FromVoidResult(); } catch (Exception exception) { return TaskUtilities.FromError(error: exception); } }); }
public Task <TriggerSignalEventArgs> NextSignalAwaitable() { try { var existingAwaitable = TryReadDA(ref _nextSignalAwaitable, considerDisposeRequest: true); if (existingAwaitable is null) { if (HasDeactivationRequested) { return(TaskUtilities.FromCanceled <TriggerSignalEventArgs>()); } else { AsyncTaskCompletionSource <TriggerSignalEventArgs> newAwaitable = default; try { try { UpdDAIfNullBool(location: ref _nextSignalAwaitable, factory: () => newAwaitable = new AsyncTaskCompletionSource <TriggerSignalEventArgs>(), current: out existingAwaitable); } catch (ObjectDisposedException) { if (IsDisposeRequested) { return(TaskUtilities.FromCanceled <TriggerSignalEventArgs>()); } else { throw; } } } finally { if (!ReferenceEquals(existingAwaitable, newAwaitable)) { newAwaitable?.TrySetCanceled(ct: CancellationToken.None); } } } } return(existingAwaitable.Task); } catch (Exception exception) { return(TaskUtilities.FromError <TriggerSignalEventArgs>(error: exception)); } }
// 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); } });
// TODO: Put strings into the resources. // protected override Task DoActivateAsync(IRunControlAttemptState state) { try { state.EnsureNotNull(nameof(state)); // CancellationTokenSource cts = default; try { cts = CancellationTokenSource.CreateLinkedTokenSource(tokens: new CancellationToken[] { App.AppShutdownToken }); var ct = cts.Token; if (UpdDAIfNullBool(ref _currentActivationCts, cts)) { P_ScheduleNextSignal(period: P_SelectNextPeriod(), ct: ct); } else { throw new EonException( message: $"Недопустимый вызов операции. Операция уже была выполнена ранее. Для повторного выполнения необходимо сначала выполнить операцию '{nameof(DoDeactivateAsync)}'.{Environment.NewLine}\tКомпонент:{this.FmtStr().GNLI2()}"); } } catch (Exception exception) { if (!(cts is null)) { ExceptionUtilities .TryCatch( op: () => { cts.Cancel(throwOnFirstException: false); itrlck.SetNullBool(location: ref _currentActivationCts, comparand: cts); cts.Dispose(); }, exception: exception); } throw; } return(TaskUtilities.FromVoidResult()); } catch (Exception exception) { return(TaskUtilities.FromError(error: exception)); } }
public static Task DisposeAsync(P_Lifecycle lifecycle) { try { if (lifecycle is null) { throw new ArgumentNullException(paramName: nameof(lifecycle)); } // if (lifecycle.Disposing || lifecycle.IsDisposed) { return(TaskUtilities.FromVoidResult()); } else { return(P_BeforeDisposeAsync(lifecycle: lifecycle, continuation: lifecycle.Dispose)); } } catch (Exception exception) { return(TaskUtilities.FromError(error: exception)); } }
Task P_DoStopAsync() { try { var cancellationTokenSource = ReadDA(ref _cancellationTokenSource); if (!cancellationTokenSource.IsCancellationRequested) { cancellationTokenSource.Cancel(); } var loopTask = ReadDA(ref _loopTask); if (loopTask == null) { return(TaskUtilities.FromVoidResult()); } else { return(loopTask); } } catch (Exception firstException) { return(TaskUtilities.FromError(error: firstException)); } }
public Task <bool> WaitAsync(CancellationToken ct, TimeoutDuration timeout, bool treatCancellationAsTimeoutExpiry) { SignalAwaitable signalAwaitable = null; try { timeout.EnsureNotNull(nameof(timeout)); // if (ct.IsCancellationRequested) { return(treatCancellationAsTimeoutExpiry ? TaskUtilities.FromFalse() : TaskUtilities.FromCanceled <bool>(ct: ct)); } else { var timeoutCts = default(CancellationTokenSource); var timeoutCtRegistration = default(CancellationTokenRegistration?); try { signalAwaitable = new SignalAwaitable(); // if (ct.CanBeCanceled) { var ctRegistration = default(CancellationTokenRegistration); try { signalAwaitable .Task .ContinueWith( continuationAction: (locTask) => { ctRegistration.Dispose(); }, continuationOptions: TaskContinuationOptions.ExecuteSynchronously); ctRegistration = ct .Register( callback: () => { if (treatCancellationAsTimeoutExpiry) { signalAwaitable.TrySetResult(result: false); } else { signalAwaitable.TrySetCanceled(ct: ct); } }); } catch { ctRegistration.Dispose(); throw; } } // if (!timeout.IsInfinite) { timeoutCts = new CancellationTokenSource(millisecondsDelay: timeout.Milliseconds); timeoutCtRegistration = timeoutCts .Token .Register(callback: () => signalAwaitable.TrySetResult(result: false)); } // var queue = ReadDA(ref _queue); var queueSpinLock = ReadDA(ref _queueSpinLock, considerDisposeRequest: true); queueSpinLock .Invoke( action: () => { if (ct.IsCancellationRequested) { if (treatCancellationAsTimeoutExpiry) { signalAwaitable.TrySetResult(result: false); } else { signalAwaitable.TrySetCanceled(ct: ct); } } else { EnsureNotDisposeState(considerDisposeRequest: true); // if (queue.Count == 1 && ReferenceEquals(queue.Peek(), __Signaled)) { if (signalAwaitable.TrySetResult(result: true)) { queue.Dequeue(); } } else if (timeout.Milliseconds == 0) { signalAwaitable.TrySetResult(result: false); } else { queue.Enqueue(signalAwaitable); } } }); return(signalAwaitable.Task); } catch { timeoutCtRegistration?.Dispose(); timeoutCts?.Dispose(); throw; } } } catch (Exception exception) { if (signalAwaitable?.TrySetException(exception) == true) { return(signalAwaitable.Task); } else { return(TaskUtilities.FromError <bool>(error: exception)); } } }
// TODO: Put strings into the resources. // public Task <ILocalSubscription> SubscribeAsync(ILocalSubscription subscription) { try { subscription.EnsureNotNull(nameof(subscription)); if (!ReferenceEquals(subscription.Publisher, this)) { throw new ArgumentOutOfRangeException( paramName: nameof(subscription), message: $"Subscription is not associated with this publisher.{Environment.NewLine}\tSubscription:{subscription.FmtStr().GNLI2()}{Environment.NewLine}\tPublisher:{this.FmtStr().GNLI2()}"); } // var spinLock = ReadDA(ref _subscriptionsSpinLock); var subscriptionsDictionary = ReadDA(ref _subscriptionsDictionary); var subscriptionsList = ReadDA(ref _subscriptionsList); var existingSubscriptionRegistration = default(P_NewSubscriptionRegistrationState); // if (!spinLock.Invoke(() => subscriptionsDictionary.TryGetValue(subscription, out existingSubscriptionRegistration))) { var newSubscriptionRegistration = default(P_NewSubscriptionRegistrationState); try { newSubscriptionRegistration = new P_NewSubscriptionRegistrationState(subscription); spinLock .Invoke( () => { EnsureNotDisposeState(); // if (subscriptionsDictionary.ContainsKey(subscription)) { existingSubscriptionRegistration = subscriptionsDictionary[subscription]; } else { subscriptionsDictionary.Add(subscription, newSubscriptionRegistration); existingSubscriptionRegistration = newSubscriptionRegistration; subscriptionsList.Add(newSubscriptionRegistration.Subscription); } }); if (existingSubscriptionRegistration == newSubscriptionRegistration) { subscription .ActivateAsync() .ContinueWith( locActivateTask => { if (locActivateTask.IsCanceled) { newSubscriptionRegistration.SubscribeTaskProxy.TrySetCanceled(); } else if (locActivateTask.IsFaulted) { if (!newSubscriptionRegistration.SubscribeTaskProxy.TrySetException(locActivateTask.Exception)) { throw new AggregateException(locActivateTask.Exception); } } else { newSubscriptionRegistration.SubscribeTaskProxy.TrySetResult(newSubscriptionRegistration.Subscription); } }, TaskContinuationOptions.ExecuteSynchronously); } } catch (Exception firstException) { newSubscriptionRegistration?.SubscribeTaskProxy.TrySetException(firstException); throw; } finally { if (newSubscriptionRegistration != existingSubscriptionRegistration) { newSubscriptionRegistration?.SubscribeTaskProxy.TrySetCanceled(); } } } // return(existingSubscriptionRegistration.SubscribeTaskProxy.Task); } catch (Exception firstException) { return(TaskUtilities.FromError <ILocalSubscription>(firstException)); } }
// TODO: Put strings into the resources. // protected override Task DoActivateAsync(IRunControlAttemptState state) { #if !DO_NOT_USE_EON_LOGGING_API const string logMessagePrologue = "Активация."; #endif // try { state.EnsureNotNull(nameof(state)); // if (HasDeactivationRequested) { return(TaskUtilities.FromCanceled()); } else { return(TaskUtilities.RunOnDefaultScheduler(action: doActivateParallel, cancellationToken: CancellationToken.None, state: state)); } } catch (Exception exception) { return(TaskUtilities.FromError(error: exception)); } // void doActivateParallel(IRunControlAttemptState locState) { locState.EnsureNotNull(nameof(locState)); // var locActivatedItems = new List <IActivatableXAppScopeInstance>(); try { foreach (var locActivatable in ActivatableItems) { // Мониторинг запроса отмены операции. // if (HasDeactivationRequested) { throw new OperationCanceledException(); } // Активация компонента. // try { #if !DO_NOT_USE_EON_LOGGING_API this .IssueInformation( messagePrologue: logMessagePrologue, message: $"Активация компонента.{Environment.NewLine}\tКомпонент:{Environment.NewLine}{locActivatable.ToString().IndentLines2()}", severityLevel: SeverityLevel.Lowest); #endif if (!locActivatable.IsAutoActivationEnabled) { #if !DO_NOT_USE_EON_LOGGING_API this .IssueWarning( messagePrologue: logMessagePrologue, message: $"Активация компонента не выполнена, так как активация отключена самим компонентом (см. '{nameof(locActivatable.IsAutoActivationEnabled)}').{Environment.NewLine}\tОбъект:{locActivatable.FmtStr().GNLI2()}", severityLevel: SeverityLevel.Lowest); #endif continue; } locActivatable .ActivateControl .StartAsync(options: TaskCreationOptions.AttachedToParent) #if !DO_NOT_USE_EON_LOGGING_API .ContinueWith( continuationAction: locItemActivationTask => { if (locItemActivationTask.IsFaulted) { this .IssueError( messagePrologue: logMessagePrologue, message: $"Ошибка активации компонента.{Environment.NewLine}\tКомпонент:{Environment.NewLine}{locActivatable.ToString().IndentLines2()}", error: locItemActivationTask.Exception, includeErrorInIssueFaultException: true, severityLevel: locItemActivationTask.Exception.GetMostHighSeverityLevel(baseLevel: SeverityLevel.Lowest)); } else if (locItemActivationTask.IsCanceled) { this .IssueWarning( messagePrologue: logMessagePrologue, message: $"Активация компонента была прервана или отменена.{Environment.NewLine}\tКомпонент:{locActivatable.FmtStr().GNLI2()}", severityLevel: SeverityLevel.Lowest); } else { this .IssueInformation( messagePrologue: logMessagePrologue, message: $"Активация компонента успешно выполнена.{Environment.NewLine}\tКомпонент:{locActivatable.FmtStr().GNLI2()}", severityLevel: SeverityLevel.Lowest); } }, continuationOptions: TaskContinuationOptions.AttachedToParent | TaskContinuationOptions.ExecuteSynchronously) #endif ; // locActivatedItems.Add(locActivatable); } catch { #if !DO_NOT_USE_EON_LOGGING_API this .IssueError( messagePrologue: logMessagePrologue, message: $"Ошибка активации компонента.{Environment.NewLine}\tКомпонент:{locActivatable.FmtStr().GNLI2()}", error: exception, severityLevel: exception.GetMostHighSeverityLevel(baseLevel: SeverityLevel.Lowest), includeErrorInIssueFaultException: true); #endif throw; } } WriteDA(ref _activatedItems, locActivatedItems.ToArray()); } catch (Exception exception) { var caughtExceptions = new List <Exception>(); foreach (var activatedItem in locActivatedItems) { try { activatedItem.ActivateControl.StopAsync(TaskCreationOptions.AttachedToParent); } catch (Exception secondException) { caughtExceptions.Add(secondException); } } // if (caughtExceptions.Count > 0) { throw new AggregateException(exception.Sequence().Concat(caughtExceptions)); } else { throw; } } } }
// TODO: Put strings into the resources. // Task P_DoStartAsync(IRunControlAttemptState state) { // TODO_HIGH: Этот таймаут должен браться из контекста запуска (когда будет реализован) как время оставшееся для выполнения операции запуска. // const int loopStartMillisecondsTimeout = 10000; try { state.EnsureNotNull(nameof(state)); // var ct = ReadDA(ref _cancellationTokenSource).Token; ManualResetEventSlim loopStartedEvent = default; try { loopStartedEvent = new ManualResetEventSlim(initialState: false); Task loopTask; Interlocked .Exchange( location1: ref _loopTask, value: loopTask = TaskUtilities .RunOnDefaultScheduler( action: P_Loop, state: new P_LoopStartState(worker: this, loopStartedEvent: loopStartedEvent), cancellationToken: ct, options: TaskCreationOptions.PreferFairness | TaskCreationOptions.LongRunning)); if (!loopStartedEvent.Wait(millisecondsTimeout: loopStartMillisecondsTimeout)) { loopStartedEvent.Dispose(); // if (loopTask.IsCompleted) { throw new EonException( message: "Цикл обработки очереди рабочих элементов не запустился в отведённое для запуска время. Время ожидания запуска истекло." + (loopTask.IsCanceled ? $"{Environment.NewLine}Задача цикла была отменена." : string.Empty), innerException: loopTask.IsFaulted ? loopTask.Exception : null); } else { throw new TimeoutException( message: $"Цикл обработки очереди рабочих элементов не запустился в отведённое для запуска время. Время ожидания запуска истекло.{Environment.NewLine}Статус задачи цикла:{loopTask.Status.FmtStr().GNLI()}"); } } // loopTask .ContinueWith( continuationAction: P_OnLoopTaskCompleted, cancellationToken: CancellationToken.None, continuationOptions: TaskContinuationOptions.PreferFairness, scheduler: TaskScheduler.Default); } finally { loopStartedEvent?.Dispose(); } // return(TaskUtilities.FromVoidResult()); } catch (Exception firstException) { return(TaskUtilities.FromError(error: firstException)); } }
// TODO: Put strings into the resources. // public Task <IVh <T> > AcquireAsync(IContext context = default) { try { var existingTask = itrlck.Get(ref _acquireTask); var ct = context?.Ct() ?? CancellationToken.None; if (existingTask is null) { var newTaskProxy = default(TaskCompletionSource <IVh <T> >); try { newTaskProxy = new TaskCompletionSource <IVh <T> >(creationOptions: TaskCreationOptions.RunContinuationsAsynchronously); if (itrlck.UpdateIfNullBool(location: ref _acquireTask, value: newTaskProxy.Task, current: out existingTask)) { if (itrlck.Get(ref _releaseTask) is null) { existingTask .ContinueWith( continuationAction: t => itrlck.SetNull(location: ref _acquireTask, comparand: t), continuationOptions: TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.NotOnRanToCompletion); doAcquireAsync(locContext: context).ContinueWithTryApplyResultTo(taskProxy: newTaskProxy); } else { newTaskProxy.TrySetException(exception: new EonException(message: $"Invalid acquisition attempt. Release operation has been attempted already.{Environment.NewLine}\tLease ID:{_id.FmtStr().GNLI2()}")); } return(existingTask); } else { return(existingTask.WaitResultAsync(ct: ct)); } } catch (Exception exception) { if (newTaskProxy?.TrySetException(exception) == true) { return(newTaskProxy.Task); } else { throw; } } finally { if (!ReferenceEquals(newTaskProxy.Task, existingTask)) { newTaskProxy.TrySetCanceled(); } } } else { return(existingTask.WaitResultAsync(ct: ct)); } } catch (Exception exception) { return(TaskUtilities.FromError <IVh <T> >(exception)); } // async Task <IVh <T> > doAcquireAsync(IContext locContext) { var locAcquire = itrlck.Get(ref _acquire); var locRelease = itrlck.Get(ref _release); if (itrlck.Get(ref _releaseTask) is null) { try { IVh <T> locAcquired = default; try { locAcquired = await locAcquire(arg : locContext).ConfigureAwait(false); if (locAcquired is null) { throw new EonException(message: $"Instance acquisition method has returned invalid value '{locAcquired.FmtStr().G()}'.{Environment.NewLine}\tLease ID:{_id.FmtStr().GNLI2()}"); } _acquireDateTime = DateTimeOffset.Now; _logger ?.LogDebug( eventId: LeasableEventIds.LeaseStart, message: $"Lease started.{Environment.NewLine}\tLease ID:{Environment.NewLine}\t\t{{lease_id}}{Environment.NewLine}\tCorrelation ID:{Environment.NewLine}\t\t{{correlation_id}}", args: new object[] { _id.ToString(), locContext?.FullCorrelationId.ToString() }); return(locAcquired); } catch (Exception locException) { if (!(locAcquired is null)) { try { await locRelease(arg : locAcquired).ConfigureAwait(false); } catch (Exception locSecondException) { throw new AggregateException(locException, locSecondException); } } throw; } } catch (Exception locException) { try { _logger ?.LogWarning( eventId: LeasableEventIds.LeaseStart, exception: locException, message: $"Lease start error.{Environment.NewLine}\tLease ID:{Environment.NewLine}\t\t{{lease_id}}{Environment.NewLine}\tCorrelation ID:{Environment.NewLine}\t\t{{correlation_id}}", args: new object[] { _id.ToString(), locContext?.FullCorrelationId.ToString() }); } catch (Exception locSecondException) { throw new AggregateException(locException, locSecondException); } throw; } } else { throw new EonException(message: $"Invalid lease start attempt. Lease end has been attempted already.{Environment.NewLine}\tLease ID:{_id.FmtStr().GNLI2()}"); } } }
public Task ReleaseAsync() { try { var existingTask = itrlck.Get(ref _releaseTask); if (existingTask is null) { var newTaskProxy = default(TaskCompletionSource <Nil>); try { newTaskProxy = new TaskCompletionSource <Nil>(creationOptions: TaskCreationOptions.RunContinuationsAsynchronously); if (itrlck.UpdateIfNullBool(ref _releaseTask, newTaskProxy.Task, out existingTask)) { doReleaseAsync().ContinueWithTryApplyResultTo(taskProxy: newTaskProxy); } } catch (Exception exception) { if (newTaskProxy?.TrySetException(exception) == true) { return(newTaskProxy.Task); } else { throw; } } finally { if (!ReferenceEquals(newTaskProxy.Task, existingTask)) { newTaskProxy.TrySetCanceled(); } } } return(existingTask); } catch (Exception exception) { return(TaskUtilities.FromError(exception)); } // async Task doReleaseAsync() { Func <IContext, Task <IVh <T> > > locAcquire = default; Task <IVh <T> > locAcquireTask = default; Func <IVh <T>, Task> locRelease = default; try { locAcquire = itrlck.Get(ref _acquire); locRelease = itrlck.Get(ref _release); locAcquireTask = itrlck.Get(ref _acquireTask); if (!(locAcquireTask is null)) { await locAcquireTask.WaitCompletionAsync().ConfigureAwait(false); if (locAcquireTask.IsSucceeded()) { var locAcquired = locAcquireTask.Result; var locNowDateTime = DateTimeOffset.Now; Exception locCaughtException = default; try { await locRelease(arg : locAcquired).ConfigureAwait(false); } catch (Exception locException) { locCaughtException = locException; throw; } finally { if (locCaughtException is null) { _logger ?.LogDebug( eventId: LeasableEventIds.LeaseEnd, message: $"Lease end.{Environment.NewLine}\tLease ID:{Environment.NewLine}\t\t{{lease_id}}{Environment.NewLine}\tLease duration:{Environment.NewLine}\t\t{{lease_duration}}", args: new object[] { _id.ToString(), locNowDateTime.Subtract(_acquireDateTime).ToString("c") }); } else { try { _logger ?.LogWarning( eventId: LeasableEventIds.LeaseEnd, exception: locCaughtException, message: $"Lease end error.{Environment.NewLine}\tLease ID:{Environment.NewLine}\t\t{{lease_id}}{Environment.NewLine}\tLease duration:{Environment.NewLine}\t\t{{lease_duration}}", args: new object[] { _id.ToString(), locNowDateTime.Subtract(_acquireDateTime).ToString("c") }); } catch (Exception locException) { throw new AggregateException(locCaughtException, locException); } } } } } } finally { itrlck.SetNullBool(ref _acquireTask, locAcquireTask); itrlck.SetNullBool(ref _acquire, locAcquire); itrlck.SetNullBool(ref _release, locRelease); } } }