Skip to content

Commit

Permalink
Base on Task instead of ValueTask
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewlock committed Dec 23, 2024
1 parent 96746bd commit 457a93f
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 68 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#if !NETCOREAPP3_1_OR_GREATER
using System;
using System.Runtime.ExceptionServices;
using System.Threading.Tasks;
using Datadog.Trace.DuckTyping;
using Datadog.Trace.Vendors.Serilog.Events;
Expand Down Expand Up @@ -86,39 +87,50 @@ public SyncCallbackHandler(ObjectContinuationMethodDelegate continuation, bool p
return ValueTaskActivator<TReturn>.CreateInstance(secondTask);
}

private async Task ContinuationAction(Task previousValueTask, TTarget? target, CallTargetState state)
private async Task ContinuationAction(Task previousTask, TTarget? target, CallTargetState state)
{
try
if (!previousTask.IsCompleted)
{
await previousValueTask.ConfigureAwait(_preserveContext);
await new NoThrowAwaiter(previousTask, _preserveContext);
}
catch (Exception ex)

Exception? exception = null;

if (previousTask.Status == TaskStatus.Faulted)
{
exception = previousTask.Exception?.GetBaseException();
}
else if (previousTask.Status == TaskStatus.Canceled)
{
try
{
// *
// Calls the CallTarget integration continuation, exceptions here should never bubble up to the application
// *
_continuation(target, default, ex, in state);
// The only supported way to extract the cancellation exception is to await the task
await previousTask.ConfigureAwait(_preserveContext);
}
catch (Exception contEx)
catch (Exception ex)
{
IntegrationOptions<TIntegration, TTarget>.LogException(contEx);
exception = ex;
}

throw;
}

try
{
// *
// Calls the CallTarget integration continuation, exceptions here should never bubble up to the application
// *
_continuation(target, default, default, in state);
_continuation(target, null, exception, in state);
}
catch (Exception contEx)
catch (Exception ex)
{
IntegrationOptions<TIntegration, TTarget>.LogException(contEx);
IntegrationOptions<TIntegration, TTarget>.LogException(ex);
}

// *
// If the original task throws an exception we rethrow it here.
// *
if (exception != null)
{
ExceptionDispatchInfo.Capture(exception).Throw();
}
}
}
Expand Down Expand Up @@ -160,44 +172,48 @@ public override TReturn ExecuteCallback(TTarget? instance, TReturn? returnValue,
return ValueTaskActivator<TReturn>.CreateInstance(secondTask);
}

private async Task ContinuationAction(Task previousValueTask, TTarget? target, CallTargetState state, Exception? exception)
private async Task ContinuationAction(Task previousTask, TTarget? target, CallTargetState state, Exception? exception)
{
if (exception != null)
if (!previousTask.IsCompleted)
{
await _asyncContinuation(target, default, exception, in state).ConfigureAwait(_preserveContext);
await new NoThrowAwaiter(previousTask, _preserveContext);
}

try
if (previousTask.Status == TaskStatus.Faulted)
{
await previousValueTask.ConfigureAwait(_preserveContext);
exception ??= previousTask.Exception?.GetBaseException();
}
catch (Exception ex)
else if (previousTask.Status == TaskStatus.Canceled)
{
try
{
// *
// Calls the CallTarget integration continuation, exceptions here should never bubble up to the application
// *
await _asyncContinuation(target, default, ex, in state).ConfigureAwait(_preserveContext);
// The only supported way to extract the cancellation exception is to await the task
await previousTask.ConfigureAwait(_preserveContext);
}
catch (Exception contEx)
catch (Exception ex)
{
IntegrationOptions<TIntegration, TTarget>.LogException(contEx);
exception ??= ex;
}

throw;
}

try
{
// *
// Calls the CallTarget integration continuation, exceptions here should never bubble up to the application
// *
await _asyncContinuation(target, default, default, in state).ConfigureAwait(_preserveContext);
await _asyncContinuation(target, null, exception, in state).ConfigureAwait(_preserveContext);
}
catch (Exception contEx)
catch (Exception ex)
{
IntegrationOptions<TIntegration, TTarget>.LogException(ex);
}

// *
// If the original task throws an exception we rethrow it here.
// *
if (exception != null)
{
IntegrationOptions<TIntegration, TTarget>.LogException(contEx);
ExceptionDispatchInfo.Capture(exception).Throw();
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#if !NETCOREAPP3_1_OR_GREATER
using System;
using System.Runtime.ExceptionServices;
using System.Threading.Tasks;
using Datadog.Trace.DuckTyping;
using Datadog.Trace.Vendors.Serilog.Events;
Expand Down Expand Up @@ -89,43 +90,59 @@ public SyncCallbackHandler(ContinuationMethodDelegate continuation, bool preserv
return ValueTaskActivator<TReturn, TResult?>.CreateInstance(secondTask);
}

private async Task<TResult?> ContinuationAction(Task<TResult?> previousValueTask, TTarget? target, CallTargetState state)
private async Task<TResult?> ContinuationAction(Task<TResult?> previousTask, TTarget? target, CallTargetState state)
{
TResult? result = default;
try
if (!previousTask.IsCompleted)
{
result = await previousValueTask.ConfigureAwait(_preserveContext);
await new NoThrowAwaiter(previousTask, _preserveContext);
}
catch (Exception ex)

TResult? taskResult = default;
Exception? exception = null;
TResult? continuationResult = default;

if (previousTask.Status == TaskStatus.RanToCompletion)
{
taskResult = previousTask.Result;
}
else if (previousTask.Status == TaskStatus.Faulted)
{
exception = previousTask.Exception?.GetBaseException();
}
else if (previousTask.Status == TaskStatus.Canceled)
{
try
{
// *
// Calls the CallTarget integration continuation, exceptions here should never bubble up to the application
// *
_continuation(target, result, ex, in state);
// The only supported way to extract the cancellation exception is to await the task
await previousTask.ConfigureAwait(_preserveContext);
}
catch (Exception contEx)
catch (Exception ex)
{
IntegrationOptions<TIntegration, TTarget>.LogException(contEx);
exception = ex;
}

throw;
}

try
{
// *
// Calls the CallTarget integration continuation, exceptions here should never bubble up to the application
// *
return _continuation(target, result, null, in state);
continuationResult = _continuation(target, taskResult, exception, in state);
}
catch (Exception contEx)
catch (Exception ex)
{
IntegrationOptions<TIntegration, TTarget>.LogException(contEx);
IntegrationOptions<TIntegration, TTarget>.LogException(ex);
}

return result;
// *
// If the original task throws an exception we rethrow it here.
// *
if (exception != null)
{
ExceptionDispatchInfo.Capture(exception).Throw();
}

return continuationResult;
}
}

Expand Down Expand Up @@ -166,48 +183,57 @@ public override TReturn ExecuteCallback(TTarget? instance, TReturn? returnValue,
return ValueTaskActivator<TReturn, TResult?>.CreateInstance(secondTask);
}

private async Task<TResult?> ContinuationAction(Task<TResult?> previousValueTask, TTarget? target, CallTargetState state, Exception? exception)
private async Task<TResult?> ContinuationAction(Task<TResult?> previousTask, TTarget? target, CallTargetState state, Exception? exception)
{
if (exception != null)
TResult? taskResult = default;
if (!previousTask.IsCompleted)
{
return await _asyncContinuation(target, default, exception, in state).ConfigureAwait(_preserveContext);
await new NoThrowAwaiter(previousTask, _preserveContext);
}

TResult? result = default;
try
if (previousTask.Status == TaskStatus.RanToCompletion)
{
result = await previousValueTask.ConfigureAwait(_preserveContext);
taskResult = previousTask.Result;
}
catch (Exception ex)
else if (previousTask.Status == TaskStatus.Faulted)
{
exception ??= previousTask.Exception?.GetBaseException();
}
else if (previousTask.Status == TaskStatus.Canceled)
{
try
{
// *
// Calls the CallTarget integration continuation, exceptions here should never bubble up to the application
// *
await _asyncContinuation(target, result, ex, in state).ConfigureAwait(_preserveContext);
// The only supported way to extract the cancellation exception is to await the task
await previousTask.ConfigureAwait(_preserveContext);
}
catch (Exception contEx)
catch (Exception ex)
{
IntegrationOptions<TIntegration, TTarget>.LogException(contEx);
exception ??= ex;
}

throw;
}

TResult? continuationResult = default;
try
{
// *
// Calls the CallTarget integration continuation, exceptions here should never bubble up to the application
// *
return await _asyncContinuation(target, result, null, in state).ConfigureAwait(_preserveContext);
continuationResult = await _asyncContinuation(target, taskResult, exception, in state).ConfigureAwait(_preserveContext);
}
catch (Exception ex)
{
IntegrationOptions<TIntegration, TTarget>.LogException(ex);
}
catch (Exception contEx)

// *
// If the original task throws an exception we rethrow it here.
// *
if (exception != null)
{
IntegrationOptions<TIntegration, TTarget>.LogException(contEx);
ExceptionDispatchInfo.Capture(exception).Throw();
}

return result;
return continuationResult;
}
}

Expand Down

0 comments on commit 457a93f

Please sign in to comment.