Skip to content

Merge | TaskToApm - #3263

Merged
benrr101 merged 4 commits into
mainfrom
dev/russellben/merge/tasktoapm
Apr 24, 2025
Merged

Merge | TaskToApm#3263
benrr101 merged 4 commits into
mainfrom
dev/russellben/merge/tasktoapm

Conversation

@benrr101

Copy link
Copy Markdown
Contributor

Description: This PR removes the TaskToApm class. This class was used to take task-based asynchronous operations (TPL) and convert them to the Asynchronous Programming Model (APM) pattern. It was only used in one situation in the SqlSequentialStream class.

MSDN has its own simple guide on how to convert from tasks to callbacks, which seems like it would eliminate the need for this bulky class. Please see https://learn.microsoft.com/en-us/dotnet/standard/parallel-programming/tpl-and-traditional-async-programming#implement-the-apm-pattern-by-using-tasks

Testing: Since this is a fairly significant change, it will definitely need to be tested.

@benrr101benrr101 added the Common Project 🚮 Things that relate to the common project project label Apr 8, 2025
@benrr101
benrr101 requested review from a team and CopilotApril 8, 2025 21:45

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot reviewed 2 out of 3 changed files in this pull request and generated 1 comment.

Files not reviewed (1)
  • src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj: Language not supported
Comments suppressed due to low confidence (1)

src/Microsoft.Data.SqlClient/netcore/src/Common/System/Threading/Tasks/TaskToApm.cs:1

  • [nitpick] Ensure that all dependent code paths have adequate tests to verify that removing TaskToApm did not inadvertently break any APM-related behaviors.
File removal

Task<int> readTask = ReadAsync(array, offset, count, CancellationToken.None);
if (asyncCallback is not null)
{
readTask.ContinueWith(result => asyncCallback(result));

CopilotAIApr 8, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider replacing ContinueWith with GetAwaiter().OnCompleted to better align with asynchronous execution patterns and avoid potential issues with task continuations.

Suggested change
readTask.ContinueWith(result=>asyncCallback(result));
readTask.GetAwaiter().OnCompleted(()=>asyncCallback(readTask));

Copilot uses AI. Check for mistakes.
@ErikEJ

Copy link
Copy Markdown
Contributor

Looking forward to the day when all this effort can be spent on user facing fixes and features.. but nice to see you are getting closer.

@codecov

codecovBot commented Apr 9, 2025

Copy link
Copy Markdown

Codecov Report

Attention: Patch coverage is 0% with 4 lines in your changes missing coverage. Please review.

Project coverage is 73.02%. Comparing base (2bb0dc7) to head (dd0b4cb).
Report is 18 commits behind head on main.

Files with missing linesPatch %Lines
...rc/Microsoft/Data/SqlClient/SqlSequentialStream.cs0.00%4 Missing ⚠️
Additional details and impacted files
@@ Coverage Diff @@## main #3263 +/- ##
==========================================
+ Coverage 72.81% 73.02% +0.20% 
==========================================
Files 297 299 +2 Lines 59661 57216 -2445 ==========================================
- Hits 43444 41782 -1662 + Misses 16217 15434 -783 
FlagCoverage Δ
addons92.58% <ø> (ø)
netcore75.18% <0.00%> (-0.06%)⬇️
netfx71.51% <0.00%> (+0.05%)⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@paulmedynskipaulmedynski self-assigned this Apr 10, 2025
@mdaigle

Copy link
Copy Markdown
Contributor

Task<int> readTask = ReadAsync(array, offset, count, CancellationToken.None);
if (asyncCallback is not null)
{
readTask.ContinueWith(result => asyncCallback(result));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The difference I can see here is that you're returning a reference to the read task, not the callback. So the caller has no way to await the callback completion. See the TAP to APM section here for an example: https://learn.microsoft.com/en-us/dotnet/standard/asynchronous-programming-patterns/interop-with-other-asynchronous-patterns-and-types

In that example, they create a new task completion source that the callback signals to and return the Task associated with that completion source.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm. The example from the link I linked in the description didn't wait for the callback to finish... Not sure why they wouldn't do that.

Either way, I've rewritten it to follow the pattern in the link you provided.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mdaigle is that good enough for you? 😅

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After reading more about the Begin* and End* APIs for Stream, I think my comment here was off base. The expectation from callers is that the returned result does not include the execution of the callback. The callback runs as a fire and forget task. I would say let's stick with the built in implementation for .NET Framework that we were previously using.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mdaigle Ok, I've reverted that change of the netfx implementation. There isn't really a "built-in" implementation like there is for netcore, so I hope this is what you meant.

@edwardneal

Copy link
Copy Markdown
Contributor

Looks like TaskToAPM was pulled from .NET Framework: https://referencesource.microsoft.com/#mscorlib/system/threading/Tasks/TaskToApm.cs,419004d6a72826c7,references

It was also made public in .NET Core, as TaskToAsyncResult. There are some differences in the state management, (code) but I've not checked whether those code paths are ever hit.

@benrr101

Copy link
Copy Markdown
ContributorAuthor

@edwardneal Ok, I've rewritten the netcore implementation to use TaskToAsyncResult.

@benrr101
benrr101 requested a review from mdaigleApril 15, 2025 15:51
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Common Project 🚮Things that relate to the common project project

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@benrr101@ErikEJ@mdaigle@edwardneal@paulmedynski