private void DisposeCore() { if (!Disposed) { Disposed = true; if (!ResponseFinished) { // If the response is not finished then cancel any pending actions: // 1. Call HttpClient.SendAsync // 2. Response Stream.ReadAsync // 3. Client stream // - Getting the Stream from the Request.HttpContent // - Holding the Request.HttpContent.SerializeToStream open // - Writing to the client stream CancelCall(); } else { _writeStreamTcs?.TrySetCanceled(); _completeTcs?.TrySetCanceled(); } _ctsRegistration?.Dispose(); _deadlineTimer?.Dispose(); HttpResponse?.Dispose(); ClientStreamReader?.Dispose(); ClientStreamWriter?.Dispose(); // To avoid racing with Dispose, skip disposing the call CTS // This avoid Dispose potentially calling cancel on a disposed CTS // The call CTS is not exposed externally and all dependent registrations // are cleaned up } }
/// <summary> /// Clean up can be called by: /// 1. The user. AsyncUnaryCall.Dispose et al will call this on Dispose /// 2. <see cref="ValidateHeaders"/> will call dispose if errors fail validation /// 3. <see cref="FinishResponseAndCleanUp"/> will call dispose /// </summary> private void Cleanup(Status status) { if (!ResponseFinished) { // If the response is not finished then cancel any pending actions: // 1. Call HttpClient.SendAsync // 2. Response Stream.ReadAsync // 3. Client stream // - Getting the Stream from the Request.HttpContent // - Holding the Request.HttpContent.SerializeToStream open // - Writing to the client stream CancelCall(status); } else { _callTcs.TrySetResult(status); ClientStreamWriter?.WriteStreamTcs.TrySetCanceled(); ClientStreamWriter?.CompleteTcs.TrySetCanceled(); ClientStreamReader?.HttpResponseTcs.TrySetCanceled(); } Channel.FinishActiveCall(this); _ctsRegistration?.Dispose(); _deadlineTimer?.Dispose(); HttpResponse?.Dispose(); ClientStreamReader?.Dispose(); ClientStreamWriter?.Dispose(); // To avoid racing with Dispose, skip disposing the call CTS. // This avoid Dispose potentially calling cancel on a disposed CTS. // The call CTS is not exposed externally and all dependent registrations // are cleaned up. }
/// <summary> /// Clean up can be called by: /// 1. The user. AsyncUnaryCall.Dispose et al will call this on Dispose /// 2. <see cref="ValidateHeaders"/> will call dispose if errors fail validation /// 3. <see cref="FinishResponse"/> will call dispose /// </summary> private void Cleanup(Status status) { if (!ResponseFinished) { // If the response is not finished then cancel any pending actions: // 1. Call HttpClient.SendAsync // 2. Response Stream.ReadAsync // 3. Client stream // - Getting the Stream from the Request.HttpContent // - Holding the Request.HttpContent.SerializeToStream open // - Writing to the client stream CancelCall(status); } else { _writeStreamTcs?.TrySetCanceled(); _writeCompleteTcs?.TrySetCanceled(); // If response has successfully finished then the status will come from the trailers // If it didn't finish then complete with a status _callTcs.TrySetResult(status); } _ctsRegistration?.Dispose(); _deadlineTimer?.Dispose(); HttpResponse?.Dispose(); ClientStreamReader?.Dispose(); ClientStreamWriter?.Dispose(); // To avoid racing with Dispose, skip disposing the call CTS // This avoid Dispose potentially calling cancel on a disposed CTS // The call CTS is not exposed externally and all dependent registrations // are cleaned up }
public virtual async Task Run(string forwardingBatchId, Predicate <MessageContext> filter, CancellationToken cancellationToken, int?expectedMessageCount) { IReceivingRawEndpoint processor = null; CancellationTokenRegistration?registration = null; try { shouldProcess = filter; targetMessageCount = expectedMessageCount; actualMessageCount = 0; if (Log.IsDebugEnabled) { Log.DebugFormat("Starting receiver"); } var config = createEndpointConfiguration(); syncEvent = new TaskCompletionSource <bool>(); stopCompletionSource = new TaskCompletionSource <bool>(); registration = cancellationToken.Register(() => { Task.Run(() => syncEvent.TrySetResult(true), CancellationToken.None).Ignore(); }); processor = await RawEndpoint.Start(config).ConfigureAwait(false); Log.Info($"Forwarder for batch {forwardingBatchId} started receiving messages from {processor.TransportAddress}."); if (!expectedMessageCount.HasValue) { if (Log.IsDebugEnabled) { Log.Debug("Running in timeout mode. Starting timer."); } timer.Change(TimeSpan.FromSeconds(45), Timeout.InfiniteTimeSpan); } } finally { if (Log.IsDebugEnabled) { Log.DebugFormat($"Waiting for forwarder for batch {forwardingBatchId} to finish."); } await syncEvent.Task.ConfigureAwait(false); registration?.Dispose(); if (processor != null) { await processor.Stop().ConfigureAwait(false); } Log.Info($"Forwarder for batch {forwardingBatchId} finished forwarding all messages."); await Task.Run(() => stopCompletionSource.TrySetResult(true), CancellationToken.None).ConfigureAwait(false); } if (endedPrematurely || cancellationToken.IsCancellationRequested) { throw new Exception("We are in the process of shutting down. Safe to ignore."); } }
public Task RunAsync(CancellationToken cancellationToken) { var tcs = new TaskCompletionSource <object>(); CancellationTokenRegistration?cancelTokenReg = null; cancelTokenReg = cancellationToken.Register(async delegate { tcs.TrySetCanceled(cancellationToken); await AbortAsync(); cancelTokenReg?.Dispose(); }); StartAsync().Then(delegate { this.ExecutingTask.Then(delegate { switch (this.Status) { case ProcessStatus.Executed: tcs.TrySetResult(null); break; case ProcessStatus.Compensated: tcs.TrySetCanceled(); break; case ProcessStatus.Aborted: tcs.TrySetException(this.state.Exception); break; } }); }); return(tcs.Task); }
public void Dispose() { var _this = Interlocked.Exchange(ref this._this, null); if (_this == null) { return; } Interlocked.Exchange(ref _isAvail, 0L); _d?.Dispose(); _d = null; if (_this.kvs.TryGetValue(CK, out var lck)) { if (lck.ID == this.ID) { _this.kvs.TryRemove(CK, out _); lck.Dispose(); } else if (!lck.IsAvailable) { lck.Dispose(); } } }
public static async Task <bool> WaitOneAsync(this WaitHandle handle, int millisecondsTimeout, CancellationToken?cancellationToken) { RegisteredWaitHandle? registeredHandle = null; CancellationTokenRegistration?tokenRegistration = null; try { var tcs = new TaskCompletionSource <bool>(); registeredHandle = ThreadPool.RegisterWaitForSingleObject( handle, (state, timedOut) => ((TaskCompletionSource <bool>)state).TrySetResult(!timedOut), tcs, millisecondsTimeout, true); if (cancellationToken.HasValue) { tokenRegistration = cancellationToken.Value.Register( state => ((TaskCompletionSource <bool>)state).TrySetCanceled(), tcs); } return(await tcs.Task.ConfigureAwait(false)); } finally { if (registeredHandle != null) { registeredHandle.Unregister(null); } tokenRegistration?.Dispose(); } }
private async void GracefulTerminationRequested() { if (Interlocked.Exchange(ref _StopAlreadyRequested, 1) == 1) { return; } await Task.Yield(); lock (_Lock) { _CancellationTokenRegistration?.Dispose(); _CancellationTokenRegistration = null; } Stop(); }
protected virtual void ProcessOnExited(object sender, EventArgs e) { if (!_exitedEventPublished) { // this boolean does not seem useful but i have seen weird behaviors where the // exited event is called twice when we WaitForExit(), better safe than sorry _exitedEventPublished = true; _cancelRegistration?.Dispose(); OnProcessExit?.Invoke(sender, e); } }
/// <summary> /// TBD /// </summary> /// <typeparam name="T">TBD</typeparam> /// <param name="self">TBD</param> /// <param name="messageFactory">Factory method that creates a message that can encapsulate the 'Sender' IActorRef</param> /// <param name="timeout">TBD</param> /// <param name="cancellationToken">TBD</param> /// <exception cref="ArgumentException"> /// This exception is thrown if the system can't resolve the target provider. /// </exception> /// <returns>TBD</returns> public static Task <T> Ask <T>(this ICanTell self, Func <IActorRef, object> messageFactory, TimeSpan?timeout, CancellationToken cancellationToken) { IActorRefProvider provider = ResolveProvider(self); if (provider == null) { throw new ArgumentException("Unable to resolve the target Provider", nameof(self)); } var result = TaskEx.NonBlockingTaskCompletionSource <T>(); CancellationTokenSource timeoutCancellation = null; timeout = timeout ?? provider.Settings.AskTimeout; CancellationTokenRegistration?ctr1 = null; CancellationTokenRegistration?ctr2 = null; if (timeout != Timeout.InfiniteTimeSpan && timeout.Value > default(TimeSpan)) { timeoutCancellation = new CancellationTokenSource(); ctr1 = timeoutCancellation.Token.Register(() => { result.TrySetException(new AskTimeoutException($"Timeout after {timeout} seconds")); }); timeoutCancellation.CancelAfter(timeout.Value); } if (cancellationToken.CanBeCanceled) { ctr2 = cancellationToken.Register(() => result.TrySetCanceled()); } var future = provider.CreateFutureRef(result); var path = future.Path; //The future actor needs to be unregistered in the temp container _ = result.Task.ContinueWith(t => { provider.UnregisterTempActor(path); ctr1?.Dispose(); ctr2?.Dispose(); timeoutCancellation?.Dispose(); }, TaskContinuationOptions.ExecuteSynchronously); //The future actor needs to be registered in the temp container provider.RegisterTempActor(future, path); var message = messageFactory(future); self.Tell(message, future); return(result.Task); }
public virtual async Task Run(Predicate <MessageContext> filter, CancellationToken cancellationToken, int?expectedMessageCount = null) { IReceivingRawEndpoint processor = null; CancellationTokenRegistration?registration = null; try { Log.DebugFormat("Started. Expectected message count {0}", expectedMessageCount); if (expectedMessageCount.HasValue && expectedMessageCount.Value == 0) { return; } shouldProcess = filter; targetMessageCount = expectedMessageCount; actualMessageCount = 0; Log.DebugFormat("Starting receiver"); var config = createEndpointConfiguration(); syncEvent = new TaskCompletionSource <bool>(); stopCompletionSource = new TaskCompletionSource <bool>(); registration = cancellationToken.Register(() => { Task.Run(() => syncEvent.TrySetResult(true), CancellationToken.None).Ignore(); }); processor = await RawEndpoint.Start(config).ConfigureAwait(false); if (!expectedMessageCount.HasValue) { Log.Debug("Running in timeout mode. Starting timer"); timer.Change(TimeSpan.FromSeconds(45), Timeout.InfiniteTimeSpan); } Log.InfoFormat("{0} started", GetType().Name); } finally { Log.DebugFormat("Waiting for {0} finish", GetType().Name); await syncEvent.Task.ConfigureAwait(false); registration?.Dispose(); if (processor != null) { await processor.Stop().ConfigureAwait(false); } await Task.Run(() => stopCompletionSource.TrySetResult(true), CancellationToken.None).ConfigureAwait(false); Log.DebugFormat("{0} finished", GetType().Name); } if (endedPrematurelly || cancellationToken.IsCancellationRequested) { throw new Exception("We are in the process of shutting down. Safe to ignore."); } }
void HandleCancel() { if (repeatModeState != null) { repeatModeState = null; engine.StateChanged -= WatchStateChangedForRepeat; } durationCancellationRegistration?.Dispose(); durationCancellationTokenSource?.Dispose(); engine.Cancel(); }
void SetTaskResult(bool result) { if (tcs == null) { return; } ctr?.Dispose(); ctr = null; var stored = tcs; tcs = null; stored.SetResult(result); }
private void DisposeCore() { if (!Disposed) { // Locking on the call because: // 1. Its not exposed publically // 2. Nothing else locks on call // 3. We want to avoid allocating a private lock object lock (this) { if (!Disposed) { Disposed = true; if (!ResponseFinished) { // If the response is not finished then cancel any pending actions: // 1. Call HttpClient.SendAsync // 2. Response Stream.ReadAsync // 3. Client stream // - Getting the Stream from the Request.HttpContent // - Holding the Request.HttpContent.SerializeToStream open // - Writing to the client stream CancelCall(); } else { _writeStreamTcs?.TrySetCanceled(); _writeCompleteTcs?.TrySetCanceled(); } // If response has successfully finished then the status will come from the trailers // If it didn't finish then complete with a Cancelled status _callTcs.TrySetResult(StatusCode.Cancelled); _ctsRegistration?.Dispose(); _deadlineTimer?.Dispose(); HttpResponse?.Dispose(); ClientStreamReader?.Dispose(); ClientStreamWriter?.Dispose(); // To avoid racing with Dispose, skip disposing the call CTS // This avoid Dispose potentially calling cancel on a disposed CTS // The call CTS is not exposed externally and all dependent registrations // are cleaned up } } } }
/// <summary> /// Allows awaiting a <see cref="WaitHandle"/> /// </summary> /// <param name="handle">The handle to await</param> /// <param name="millisecondsTimeout">The timeout period to return false if timed out</param> /// <param name="cancellationToken">The cancellation token to use to throw a <see cref="TaskCanceledException"/> if this token gets canceled</param> /// <returns>Returns true if the handle is free, false if it is not</returns> /// <exception cref="TaskCanceledException">Throws if the cancellation token is canceled</exception> public static async Task <bool> WaitOneAsync(this WaitHandle handle, int millisecondsTimeout, CancellationToken?cancellationToken) { // Create a handle that awaiting the original wait handle RegisteredWaitHandle registeredWaitHandle = null; // Store the token CancellationTokenRegistration?tokenRegistration = null; try { // Create a task completion source to await var tcs = new TaskCompletionSource <bool>(); // Use RegisterWaitForSingleObject so we get a callback // once the wait handle has finished, and set the tcs result in that callback registeredWaitHandle = ThreadPool.RegisterWaitForSingleObject( // The handle to wait on handle, // When it is finished, set the tcs result (state, timedOut) => ((TaskCompletionSource <bool>)state).TrySetResult(!timedOut), // Pass the tcs as the state so we don't have a reference to the parent tcs (optimization) tcs, // Set timeout if passed in millisecondsTimeout, // Run once don't keep resetting timeout true); // Register to run the action and set the tcs as canceled // if the cancellation token itself is canceled // which will throw a TaskCanceledException up to the caller if (cancellationToken.HasValue) { tokenRegistration = cancellationToken.Value.Register(state => ((TaskCompletionSource <bool>)state).TrySetCanceled(), tcs); } // Await the handle or the cancellation token return(await tcs.Task); } finally { // Clean up registered wait handle registeredWaitHandle?.Unregister(null); // Dispose of the token we had to create to register for the cancellation token callback tokenRegistration?.Dispose(); } }
public async Task DisposeAsync() { var client = Interlocked.Exchange(ref this._client, null); if (client == null) { return; } _d?.Dispose(); _d = null; try { await _lck.Release().ConfigureAwait(false); await _lck.Destroy().ConfigureAwait(false); } catch { } }
public void DisableCancellation() { if (_cancellationRegistration == null) { return; } lock (_cancellationSync) { if (_cancellationRegistration == null) { return; } _cancellationRegistration?.Dispose(); _cancellationRegistration = null; } }
// .NET Framework 4.0 an earlier do not have Task.Delay defined public static global::System.Threading.Tasks.Task Delay(int millisecondsDelay, CancellationToken cancellationToken) { TaskCompletionSource <bool> taskCompletionSource = new TaskCompletionSource <bool>(); Timer timer = null; CancellationTokenRegistration?cancellationTokenRegistration = null; timer = new Timer(state => { taskCompletionSource.TrySetResult(true); timer.Dispose(); }, null, millisecondsDelay, Timeout.Infinite); cancellationTokenRegistration = cancellationToken.Register(() => { timer.Change(0, Timeout.Infinite); cancellationTokenRegistration?.Dispose(); }); return(taskCompletionSource.Task); }
public static async Task Timeout(this Task task, TimeSpan timeout, CancellationToken?cts = null) { CancellationTokenRegistration?ctr = null; TaskCompletionSource <bool> tcs = new TaskCompletionSource <bool>(); if (cts.HasValue) { ctr = cts.Value.Register(() => { tcs.TrySetCanceled(); ctr?.Dispose(); }); } if (timeout == TimeSpan.MaxValue) { await task; return; } var delay = Task.Delay(timeout).ContinueWith(d => throw new TimeoutException()); await await Task.WhenAny(task, delay); }
public bool CloseChrome() { if (IsOpenChrome) { if (process?.HasExited == false) { process?.Kill(); } process?.Dispose(); process = null; chromeDriver?.Quit(); chromeDriver = null; service?.Dispose(); service = null; cancellationTokenRegistration?.Dispose(); cancellationTokenRegistration = null; tokenSource?.Dispose(); tokenSource = null; StateChange?.Invoke(IsOpenChrome); return(true); } return(false); }
private static Task <CommandResult> Run(this string command, string workingDirectory, CancellationToken cancellationToken, IProcessOutputClassifier outputClassifier, TimeSpan?timeout = null) { TimeSpan timeOutSpan = timeout ?? TimeSpan.FromMinutes(120); Process process = CreateProcess(command, workingDirectory); var standardOutput = new List <string>(); var standardError = new List <string>(); var standardInfos = new List <string>(); var standardOutputResults = new TaskCompletionSource <List <string> >(); var standardErrorResults = new TaskCompletionSource <List <string> >(); process.OutputDataReceived += (sender, e) => OnOutput(e, standardOutput, standardOutputResults); process.ErrorDataReceived += (sender, e) => OnError(outputClassifier, e, standardError, standardInfos, standardErrorResults); var tcs = new TaskCompletionSource <CommandResult>(); CancellationTokenRegistration registration = default; void OnDispose() { process.Exited -= OnProcessExit; registration.Dispose(); } var stopwatch = new Stopwatch(); async void OnProcessExit(object sender, EventArgs args) { stopwatch.Stop(); var stdout = await standardOutputResults.Task; var stderr = await standardErrorResults.Task; var result = new CommandResult { Command = command, ExitCode = process.ExitCode, IsSuccess = standardError.Count == 0, Output = string.Join(Environment.NewLine, stdout), Errors = string.Join(Environment.NewLine, stderr), Infos = standardInfos, ElapsedMilliseconds = stopwatch.ElapsedMilliseconds }; tcs.TrySetResult(result); OnDispose(); } process.Exited += OnProcessExit; registration = cancellationToken.Register(() => { tcs.TrySetCanceled(); KillProcessAndChilds(process); OnDispose(); }); try { stopwatch.Start(); if (!process.Start()) { tcs.TrySetException(new InvalidOperationException("Failed to start process")); OnDispose(); } else { Task.Run(() => { if (!process.WaitForExit((int)Math.Min(timeOutSpan.TotalMilliseconds, int.MaxValue))) { tcs.TrySetException(new InvalidOperationException("Process timedout")); OnDispose(); } }); } } catch (Exception e) { tcs.TrySetException(e); OnDispose(); } process.BeginOutputReadLine(); process.BeginErrorReadLine(); return(tcs.Task); }
// StepsRunner should never throw exception to caller public async Task RunAsync(IExecutionContext jobContext, IList <IStep> steps) { ArgUtil.NotNull(jobContext, nameof(jobContext)); ArgUtil.NotNull(steps, nameof(steps)); // TaskResult: // Abandoned (Server set this.) // Canceled // Failed // Skipped // Succeeded // SucceededWithIssues CancellationTokenRegistration?jobCancelRegister = null; int stepIndex = 0; jobContext.Variables.Agent_JobStatus = jobContext.Result ?? TaskResult.Succeeded; foreach (IStep step in steps) { Trace.Info($"Processing step: DisplayName='{step.DisplayName}', ContinueOnError={step.ContinueOnError}, Enabled={step.Enabled}"); ArgUtil.Equal(true, step.Enabled, nameof(step.Enabled)); ArgUtil.NotNull(step.ExecutionContext, nameof(step.ExecutionContext)); ArgUtil.NotNull(step.ExecutionContext.Variables, nameof(step.ExecutionContext.Variables)); stepIndex++; // Start. step.ExecutionContext.Start(); var taskStep = step as ITaskRunner; if (taskStep != null) { HostContext.WritePerfCounter($"TaskStart_{taskStep.Task.Reference.Name}_{stepIndex}"); } // Variable expansion. List <string> expansionWarnings; step.ExecutionContext.Variables.RecalculateExpanded(out expansionWarnings); expansionWarnings?.ForEach(x => step.ExecutionContext.Warning(x)); var expressionManager = HostContext.GetService <IExpressionManager>(); try { // Register job cancellation call back only if job cancellation token not been fire before each step run if (!jobContext.CancellationToken.IsCancellationRequested) { // Test the condition again. The job was canceled after the condition was originally evaluated. jobCancelRegister = jobContext.CancellationToken.Register(() => { // mark job as cancelled jobContext.Result = TaskResult.Canceled; jobContext.Variables.Agent_JobStatus = jobContext.Result; step.ExecutionContext.Debug($"Re-evaluate condition on job cancellation for step: '{step.DisplayName}'."); ConditionResult conditionReTestResult; if (HostContext.AgentShutdownToken.IsCancellationRequested) { step.ExecutionContext.Debug($"Skip Re-evaluate condition on agent shutdown."); conditionReTestResult = false; } else { try { conditionReTestResult = expressionManager.Evaluate(step.ExecutionContext, step.Condition, hostTracingOnly: true); } catch (Exception ex) { // Cancel the step since we get exception while re-evaluate step condition. Trace.Info("Caught exception from expression when re-test condition on job cancellation."); step.ExecutionContext.Error(ex); conditionReTestResult = false; } } if (!conditionReTestResult.Value) { // Cancel the step. Trace.Info("Cancel current running step."); step.ExecutionContext.CancelToken(); } }); } else { if (jobContext.Result != TaskResult.Canceled) { // mark job as cancelled jobContext.Result = TaskResult.Canceled; jobContext.Variables.Agent_JobStatus = jobContext.Result; } } // Evaluate condition. step.ExecutionContext.Debug($"Evaluating condition for step: '{step.DisplayName}'"); Exception conditionEvaluateError = null; ConditionResult conditionResult; if (HostContext.AgentShutdownToken.IsCancellationRequested) { step.ExecutionContext.Debug($"Skip evaluate condition on agent shutdown."); conditionResult = false; } else { try { conditionResult = expressionManager.Evaluate(step.ExecutionContext, step.Condition); } catch (Exception ex) { Trace.Info("Caught exception from expression."); Trace.Error(ex); conditionResult = false; conditionEvaluateError = ex; } } // no evaluate error but condition is false if (!conditionResult.Value && conditionEvaluateError == null) { // Condition == false Trace.Info("Skipping step due to condition evaluation."); step.ExecutionContext.Complete(TaskResult.Skipped, resultCode: conditionResult.Trace); continue; } if (conditionEvaluateError != null) { // fail the step since there is an evaluate error. step.ExecutionContext.Error(conditionEvaluateError); step.ExecutionContext.Complete(TaskResult.Failed); } else { // Run the step. await RunStepAsync(step, jobContext.CancellationToken); } } finally { if (jobCancelRegister != null) { jobCancelRegister?.Dispose(); jobCancelRegister = null; } } // Update the job result. if (step.ExecutionContext.Result == TaskResult.SucceededWithIssues || step.ExecutionContext.Result == TaskResult.Failed) { Trace.Info($"Update job result with current step result '{step.ExecutionContext.Result}'."); jobContext.Result = TaskResultUtil.MergeTaskResults(jobContext.Result, step.ExecutionContext.Result.Value); jobContext.Variables.Agent_JobStatus = jobContext.Result; } else { Trace.Info($"No need for updating job result with current step result '{step.ExecutionContext.Result}'."); } if (taskStep != null) { HostContext.WritePerfCounter($"TaskCompleted_{taskStep.Task.Reference.Name}_{stepIndex}"); } Trace.Info($"Current state: job state = '{jobContext.Result}'"); } }
public override void PostStop() { _registration?.Dispose(); base.PostStop(); }
public void Dispose() { _cancellationTokenRegistration.Dispose(); _timeoutCancellationTokenSource.Dispose(); }
/// <summary> /// Receive a single frame from <paramref name="socket"/>, asynchronously, and decode as a string using <paramref name="encoding"/>. /// </summary> /// <param name="socket">The socket to receive from.</param> /// <param name="encoding">The encoding used to convert the frame's data to a string.</param> /// <param name="cancellationToken">The token used to propagate notification that this operation should be canceled.</param> /// <returns>The content of the received message frame as a string and boolean indicate if another frame of the same message follows..</returns> public static Task <(string, bool)> ReceiveFrameStringAsync( this NetMQSocket socket, Encoding encoding, CancellationToken cancellationToken = default(CancellationToken)) { if (NetMQRuntime.Current == null) { throw new InvalidOperationException("NetMQRuntime must be created before calling async functions"); } socket.AttachToRuntime(); var msg = new Msg(); msg.InitEmpty(); if (socket.TryReceive(ref msg, TimeSpan.Zero)) { var str = msg.Size > 0 ? msg.GetString(encoding) : string.Empty; msg.Close(); return(Task.FromResult((str, msg.HasMore))); } TaskCompletionSource <(string, bool)> source = new TaskCompletionSource <(string, bool)>(); CancellationTokenRegistration?registration = null; if (cancellationToken.CanBeCanceled) { registration = cancellationToken.Register(PropagateCancel); } void Listener(object sender, NetMQSocketEventArgs args) { if (socket.TryReceive(ref msg, TimeSpan.Zero)) { var str = msg.Size > 0 ? msg.GetString(encoding) : string.Empty; bool more = msg.HasMore; msg.Close(); socket.ReceiveReady -= Listener; registration?.Dispose(); source.TrySetResult((str, more)); } } void PropagateCancel() { socket.ReceiveReady -= Listener; registration?.Dispose(); source.TrySetCanceled(); } socket.ReceiveReady += Listener; return(source.Task); }
// StepsRunner should never throw exception to caller public async Task RunAsync(IExecutionContext jobContext) { ArgUtil.NotNull(jobContext, nameof(jobContext)); ArgUtil.NotNull(jobContext.JobSteps, nameof(jobContext.JobSteps)); // TaskResult: // Abandoned (Server set this.) // Canceled // Failed // Skipped // Succeeded CancellationTokenRegistration?jobCancelRegister = null; jobContext.JobContext.Status = (jobContext.Result ?? TaskResult.Succeeded).ToActionResult(); var scopeInputs = new Dictionary <string, PipelineContextData>(StringComparer.OrdinalIgnoreCase); bool checkPostJobActions = false; while (jobContext.JobSteps.Count > 0 || !checkPostJobActions) { if (jobContext.JobSteps.Count == 0 && !checkPostJobActions) { checkPostJobActions = true; while (jobContext.PostJobSteps.TryPop(out var postStep)) { jobContext.JobSteps.Add(postStep); } continue; } var step = jobContext.JobSteps[0]; jobContext.JobSteps.RemoveAt(0); Trace.Info($"Processing step: DisplayName='{step.DisplayName}'"); ArgUtil.NotNull(step.ExecutionContext, nameof(step.ExecutionContext)); ArgUtil.NotNull(step.ExecutionContext.Variables, nameof(step.ExecutionContext.Variables)); // Start step.ExecutionContext.Start(); // Expression functions step.ExecutionContext.ExpressionFunctions.Add(new FunctionInfo <AlwaysFunction>(PipelineTemplateConstants.Always, 0, 0)); step.ExecutionContext.ExpressionFunctions.Add(new FunctionInfo <CancelledFunction>(PipelineTemplateConstants.Cancelled, 0, 0)); step.ExecutionContext.ExpressionFunctions.Add(new FunctionInfo <FailureFunction>(PipelineTemplateConstants.Failure, 0, 0)); step.ExecutionContext.ExpressionFunctions.Add(new FunctionInfo <SuccessFunction>(PipelineTemplateConstants.Success, 0, 0)); step.ExecutionContext.ExpressionFunctions.Add(new FunctionInfo <HashFilesFunction>(PipelineTemplateConstants.HashFiles, 1, byte.MaxValue)); step.ExecutionContext.ExpressionValues["steps"] = step.ExecutionContext.StepsContext.GetScope(step.ExecutionContext.ScopeName); // Populate env context for each step Trace.Info("Initialize Env context for step"); #if OS_WINDOWS var envContext = new DictionaryContextData(); #else var envContext = new CaseSensitiveDictionaryContextData(); #endif // Global env foreach (var pair in step.ExecutionContext.EnvironmentVariables) { envContext[pair.Key] = new StringContextData(pair.Value ?? string.Empty); } // Stomps over with outside step env if (step.ExecutionContext.ExpressionValues.TryGetValue("env", out var envContextData)) { #if OS_WINDOWS var dict = envContextData as DictionaryContextData; #else var dict = envContextData as CaseSensitiveDictionaryContextData; #endif foreach (var pair in dict) { envContext[pair.Key] = pair.Value; } } step.ExecutionContext.ExpressionValues["env"] = envContext; bool evaluateStepEnvFailed = false; if (step is IActionRunner actionStep) { // Set GITHUB_ACTION step.ExecutionContext.SetGitHubContext("action", actionStep.Action.Name); try { // Evaluate and merge action's env block to env context var templateEvaluator = step.ExecutionContext.ToPipelineTemplateEvaluator(); var actionEnvironment = templateEvaluator.EvaluateStepEnvironment(actionStep.Action.Environment, step.ExecutionContext.ExpressionValues, step.ExecutionContext.ExpressionFunctions, VarUtil.EnvironmentVariableKeyComparer); foreach (var env in actionEnvironment) { envContext[env.Key] = new StringContextData(env.Value ?? string.Empty); } } catch (Exception ex) { // fail the step since there is an evaluate error. Trace.Info("Caught exception from expression for step.env"); evaluateStepEnvFailed = true; step.ExecutionContext.Error(ex); CompleteStep(step, TaskResult.Failed); } } if (!evaluateStepEnvFailed) { try { // Register job cancellation call back only if job cancellation token not been fire before each step run if (!jobContext.CancellationToken.IsCancellationRequested) { // Test the condition again. The job was canceled after the condition was originally evaluated. jobCancelRegister = jobContext.CancellationToken.Register(() => { // mark job as cancelled jobContext.Result = TaskResult.Canceled; jobContext.JobContext.Status = jobContext.Result?.ToActionResult(); step.ExecutionContext.Debug($"Re-evaluate condition on job cancellation for step: '{step.DisplayName}'."); var conditionReTestTraceWriter = new ConditionTraceWriter(Trace, null); // host tracing only var conditionReTestResult = false; if (HostContext.RunnerShutdownToken.IsCancellationRequested) { step.ExecutionContext.Debug($"Skip Re-evaluate condition on runner shutdown."); } else { try { var templateEvaluator = step.ExecutionContext.ToPipelineTemplateEvaluator(conditionReTestTraceWriter); var condition = new BasicExpressionToken(null, null, null, step.Condition); conditionReTestResult = templateEvaluator.EvaluateStepIf(condition, step.ExecutionContext.ExpressionValues, step.ExecutionContext.ExpressionFunctions, step.ExecutionContext.ToExpressionState()); } catch (Exception ex) { // Cancel the step since we get exception while re-evaluate step condition. Trace.Info("Caught exception from expression when re-test condition on job cancellation."); step.ExecutionContext.Error(ex); } } if (!conditionReTestResult) { // Cancel the step. Trace.Info("Cancel current running step."); step.ExecutionContext.CancelToken(); } }); } else { if (jobContext.Result != TaskResult.Canceled) { // mark job as cancelled jobContext.Result = TaskResult.Canceled; jobContext.JobContext.Status = jobContext.Result?.ToActionResult(); } } // Evaluate condition. step.ExecutionContext.Debug($"Evaluating condition for step: '{step.DisplayName}'"); var conditionTraceWriter = new ConditionTraceWriter(Trace, step.ExecutionContext); var conditionResult = false; var conditionEvaluateError = default(Exception); if (HostContext.RunnerShutdownToken.IsCancellationRequested) { step.ExecutionContext.Debug($"Skip evaluate condition on runner shutdown."); } else { try { var templateEvaluator = step.ExecutionContext.ToPipelineTemplateEvaluator(conditionTraceWriter); var condition = new BasicExpressionToken(null, null, null, step.Condition); conditionResult = templateEvaluator.EvaluateStepIf(condition, step.ExecutionContext.ExpressionValues, step.ExecutionContext.ExpressionFunctions, step.ExecutionContext.ToExpressionState()); } catch (Exception ex) { Trace.Info("Caught exception from expression."); Trace.Error(ex); conditionEvaluateError = ex; } } // no evaluate error but condition is false if (!conditionResult && conditionEvaluateError == null) { // Condition == false Trace.Info("Skipping step due to condition evaluation."); CompleteStep(step, TaskResult.Skipped, resultCode: conditionTraceWriter.Trace); } else if (conditionEvaluateError != null) { // fail the step since there is an evaluate error. step.ExecutionContext.Error(conditionEvaluateError); CompleteStep(step, TaskResult.Failed); } else { // Run the step. await RunStepAsync(step, jobContext.CancellationToken); CompleteStep(step); } } finally { if (jobCancelRegister != null) { jobCancelRegister?.Dispose(); jobCancelRegister = null; } } } // Update the job result. if (step.ExecutionContext.Result == TaskResult.Failed) { Trace.Info($"Update job result with current step result '{step.ExecutionContext.Result}'."); jobContext.Result = TaskResultUtil.MergeTaskResults(jobContext.Result, step.ExecutionContext.Result.Value); jobContext.JobContext.Status = jobContext.Result?.ToActionResult(); } else { Trace.Info($"No need for updating job result with current step result '{step.ExecutionContext.Result}'."); } Trace.Info($"Current state: job state = '{jobContext.Result}'"); } }
public Task StopAsync(CancellationToken cancellationToken) { _stopped.Cancel(); _stoppedRegistration?.Dispose(); return(Task.CompletedTask); }
public Task SendMailAsync(MailMessage message, CancellationToken cancellationToken) { if (cancellationToken.IsCancellationRequested) { return(Task.FromCanceled(cancellationToken)); } // Create a TaskCompletionSource to represent the operation var tcs = new TaskCompletionSource(); CancellationTokenRegistration ctr = default; // Indicates whether the CTR has been set - captured in handler int state = 0; // Register a handler that will transfer completion results to the TCS Task SendCompletedEventHandler?handler = null; handler = (sender, e) => { if (e.UserState == tcs) { try { ((SmtpClient)sender).SendCompleted -= handler; if (Interlocked.Exchange(ref state, 1) != 0) { // A CTR has been set, we have to wait until it completes before completing the task ctr.Dispose(); } } catch (ObjectDisposedException) { } // SendAsyncCancel will throw if SmtpClient was disposed finally { if (e.Error != null) { tcs.TrySetException(e.Error); } else if (e.Cancelled) { tcs.TrySetCanceled(); } else { tcs.TrySetResult(); } } } }; SendCompleted += handler; // Start the async operation. try { SendAsync(message, tcs); } catch { SendCompleted -= handler; throw; } ctr = cancellationToken.Register(s => { ((SmtpClient)s !).SendAsyncCancel(); }, this); if (Interlocked.Exchange(ref state, 1) != 0) { // SendCompleted was already invoked, ensure the CTR completes before returning the task ctr.Dispose(); } // Return the task to represent the asynchronous operation return(tcs.Task); }
protected override void Dispose() => _registration.Dispose();
/// <summary> /// Registers a continuation for the task that will run when the task is complete. /// </summary> /// <typeparam name="T">The type returned by the continuation.</typeparam> /// <param name="p_continuation">The continuation to run after the task completes. /// The function takes the completed task as an argument and can return a value.</param> /// <param name="p_cancellationToken">The cancellation token.</param> /// <returns>A new Task that returns the value returned by the continuation after both /// the task and the continuation are complete.</returns> public UnityTask <UnityTask> ContinueWith(Func <UnityTask, UnityTask> p_continuation, System.Threading.Tasks.CancellationToken p_cancellationToken) { bool completed = false; UnityTaskCompletionSource <UnityTask> utcs = new UnityTaskCompletionSource <UnityTask>(); CancellationTokenRegistration cancelToken = p_cancellationToken.Register(() => utcs.TrySetCanceled()); // 此处防止判断为false之后正好执行完毕 completed = IsCompleted; if (!completed) { m_continuationActions.Add(t => { //if (t.IsFaulted) //{ // utcs.TrySetException(t.Exception); // cancelToken.Dispose(); //} //else //{ try { UnityTask result = p_continuation(t); utcs.TrySetResult(result); cancelToken.Dispose(); } catch (Exception ex) { utcs.TrySetException(ex); cancelToken.Dispose(); } //} }); } else { ForegroundInvoker.Invoke(() => { //if (this.IsFaulted) //{ // utcs.TrySetException(this.Exception); // cancelToken.Dispose(); //} //else //{ try { UnityTask result = p_continuation(this); utcs.TrySetResult(result); cancelToken.Dispose(); } catch (Exception ex) { utcs.TrySetException(ex); cancelToken.Dispose(); } //} }); } return(utcs.Task); }