-
Notifications
You must be signed in to change notification settings - Fork 132
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: pass through data when network request completes #1696
Conversation
Datadog ReportBranch report: ❌ 3 Failed (0 Known Flaky), 1202 Passed, 0 Skipped, 1m 37.56s Wall Time ❌ Failed Tests (3)
🔻 Code Coverage Decreases vs Default Branch (2) |
adcc669
to
7e761a8
Compare
7e761a8
to
50bf3f5
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
blocking/ On top of in-line comments, I think we're missing the fact that tasks
are pooled in URLSession
and may be reused for succeeding operations. That means the task
state set with task.dd.hasCompletion
must be reset before putting the task back to pool.
Datadog/IntegrationUnitTests/Public/NetworkInstrumentationIntegrationTests.swift
Outdated
Show resolved
Hide resolved
DatadogInternal/Sources/NetworkInstrumentation/NetworkInstrumentationFeature.swift
Show resolved
Hide resolved
DatadogInternal/Sources/NetworkInstrumentation/URLSession/URLSessionTask+Tracking.swift
Show resolved
Hide resolved
/// Note: This is not supported for async-await APIs. | ||
/// |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
question/ Meaning that we don't fully solve #1680 as it was originally reported for async/await APIs. We may need to update the PR description or add more details to the issue, otherwise it will be closed automatically with the merge.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For sure, this is regression fix. There is no path forward I could see which can solve this issue for async-await APIs like I mentioned in the description of the PR.
Yes, we are not going to close the issue but update it with what we did.
What do you mean here? I don't expect same instance of |
…grationTests.swift Co-authored-by: Maciek Grzybowski <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ganeshnj I was wrong, sorry. I always thought that URLSessionTask
is one of these few Apple objects that are reused through pool 🤔💭, like UITouch
or table cells. Interesting 🙂. There is indeed no note on that in URLSession
docs, and I don't observe this behavior in tests.
Looks good 👍. Please make sure it all works correct iOS 13-17, as we have no automated coverage at this moment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good. Some minor nits to consider :)
@@ -139,6 +139,7 @@ open class DatadogURLSessionDelegate: NSObject, URLSessionDataDelegate { | |||
try swizzler.swizzle( | |||
interceptCompletionHandler: { [weak self] task, _, error in | |||
self?.interceptor?.task(task, didCompleteWithError: error) | |||
}, didReceive: { _, _ in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: didReceive param could be optional with default nil
instead
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah but not worth the refactor.
if newValue { | ||
objc_setAssociatedObject(type, &hasCompletionKey, true, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) | ||
} else { | ||
objc_setAssociatedObject(type, &hasCompletionKey, nil, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any benefit to clear it on false? Maybe that is enough:
if newValue { | |
objc_setAssociatedObject(type, &hasCompletionKey, true, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) | |
} else { | |
objc_setAssociatedObject(type, &hasCompletionKey, nil, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) | |
} | |
objc_setAssociatedObject(type, &hasCompletionKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) |
not a big deal - just less code to read
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
more of personal preference, I don't think we would gain or lose either way.
What and why?
Fixes #1680
How?
This PR mimics the old behavior of the instrumentation.
When completion handler is provided in
URLSession
APIs,urlSession(_:dataTask:didReceive:)
is not called, which means we can't buffer the data and in the called the Resource Attribute Provider.This is not only true for the completion handler based APIs but also true for async-await APIs.
Meanwhile we use
urlSession(_:task:didFinishCollecting:)
to mark the completion of the network operation which is the only reliable API at this moment. We use this to mark completion for async-await APIs.How did the regression happen?
For some APIs, both
urlSession(_:task:didFinishCollecting:)
andurlSession(_:task:didCompleteWithError:)
are called. But there is not specific order guaranteed which one comes first, ie the one called first, marks the end of the network operation. In the breaking change,urlSession(_:task:didFinishCollecting:)
and givenurlSession(_:dataTask:didReceive:)
was not called either, Resource Attribute Provider executes with nil data.How does this PR fix it?
With this PR we make sure, if the API has a completion handler given, we are not going to use
urlSession(_:task:didFinishCollecting:)
as end of operation because we are sureurlSession(_:task:didCompleteWithError:)
will be called.Along side, when the operation finishes, we also call handler for registering the data when the operation completes. The APIs guarantees from behavior that either
urlSession(_:dataTask:didReceive:)
is called or the compeltion handler, hence we don't register data two times.Do we support async-await?
No, because they don't have completion handler, so experience remain broken with them.
Tested locally on
Review checklist
Custom CI job configuration (optional)
tools/