fix-continuation-leakage
Skill739 starsChanged 6 days agoApache-2.0View on GitHub
Diagnose and fix scope or continuation lifecycle failures in dd-trace-java instrumentation tests. Use when a test reports a continuation leak, double resolution, activation after resolve, or an unclosed scope. Reads the automatic diagnostic timeline, finds the broken lifecycle edge, fixes it, and explains it with a compact Mermaid diagram.
In this repository17 other files it gives its agents.
- AGENTS.mdAGENTS.md
- build-logic/AGENTS.mdAGENTS.md
- buildSrc/AGENTS.mdAGENTS.md
- build-logic/CLAUDE.mdCLAUDE.md
- buildSrc/CLAUDE.mdCLAUDE.md
- .claude/CLAUDE.mdCLAUDE.md
- apm-integrationsSkill
- clarify-java-commentsSkill
- java-lintSkill
- migrate-groovy-to-javaSkill
- migrate-junit-source-to-tabletestSkill
- perf-reviewSkill
- reproduce-ci-flakinessSkill
- resolve-muzzle-ciSkill
- review-groovy-migrationSkill
- techdebtSkill
- fix-continuation-leakageSkill
The file
We split this skill into the rules it gives an agent
9 rules. About 0 are common, 4 are distinctive, and 5 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈4
Distinctive · estimate
This author's own choices. Worth a look.
5
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 29
Run the smallest failing test with full output:
- Very specific: line 36
Verify the selected test ran in that task's XML results.
- Distinctive: line 39
Follow the failing record from its first event:
- Distinctive: line 51
If the test started the work, wait for its terminal event and dispose or close it before the test ends.
- Very specific: line 53
If a framework initializer creates a permanent sentinel with no context consumer, disable propagation only around that creation boundary.
- Very specific: line 56
Check static initialization (<clinit>): first use under an active request can capture its context in singleton tasks, including shaded …
- Distinctive: line 59
If an executor replaces a task before delegating, avoid capturing the discarded task while preserving capture for the task actually …
- Very specific: line 65
Prefer a test-lifecycle fix when production behavior is correct.
- Very specific: line 91
Use @TrackScopeContinuations(enabled = false, reason = "...") only when the diagnostic itself is incompatible with the test, not when it …
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Fix continuation leakage
Instrumentation tests run the diagnostic automatically. A failure includes the capture, resume, resolution, scope, thread, timing, and callsite data needed to find the missing lifecycle edge.
Work the failure
- Resolve the actual Gradle module path and failing suite from CI or the module's tasks. Nesting
varies (for example,
netty:netty-4.1versuskotlin-coroutines-1.3). UseforkedTestfor*ForkedTest*classes, or the suite-specific forked task such aslatestDepForkedTest. Run the smallest failing test with full output:
set -o pipefail
./gradlew :dd-java-agent:instrumentation:<module-path>:<test-task> --tests '<FQCN-or-pattern>' --info 2>&1 | tee /tmp/scopediag-run.txt- Verify the selected test ran in that task's XML results; a successful build with no discovered
tests is not validation. Find
Scope/continuation timelinein the output. If Gradle hides it, inspect the test XML's<system-out>under the module'sbuild/test-resultsdirectory. - Follow the failing record from its first event:
LEAKED/NEVER_CLOSED: find the success, error, cancellation, and rejection exits that skippedrelease()orclose().DOUBLE_FINISH: find two owners of the same cleanup.ACTIVATE_AFTER_RESOLVE: find work scheduled after ownership ended.LATE_FINISH/CLOSE_WRONG_THREAD: advisory evidence; verify whether ordering is valid.[deferred-cleanup]: a root iteration scope transferred cleanup to the bounded iteration cleaner. It may remain open at the test boundary and is not a leak. Do not generalize this to otherITERATIONscopes; an unregistered iteration scope must still close normally.
- Classify the captured work before changing code:
- For a real asynchronous operation, repair success, failure, cancellation, and rejection cleanup.
- If the test started the work, wait for its terminal event and dispose or close it before the test ends.
- If a framework initializer creates a permanent sentinel with no context consumer, disable
propagation only around that creation boundary. Match the exact type and method, and update
knownMatchingTypes()when shortcut matching is used. Check static initialization (<clinit>): first use under an active request can capture its context in singleton tasks, including shaded NettyGlobalEventExecutorsentinels. Reproduce first use in a fresh JVM; prewarming can hide the bug. Do not suppress all class initializers. - If an executor replaces a task before delegating, avoid capturing the discarded task while preserving capture for the task actually submitted.
- For intentionally delayed work, wait for its documented terminal event rather than suppressing propagation.
- For a context swap, verify both restoration and resource cleanup. Restore or close the
returned ownership object in
finally; do not ignore every swap.
- Prefer a test-lifecycle fix when production behavior is correct. Otherwise fix ownership where
it breaks, with one owner and
try/finallycleanup across every exit. - Rerun the failing test, then its module. Validate the leaked record and root-trace publication separately from trace-count or arrival-order assertions; fixing a leak may expose an unrelated flaky assertion.
Fixture failures
Automatic recording covers Spock setupSpec() / cleanupSpec() and JUnit @BeforeAll /
@AfterAll, in addition to per-test setup and cleanup. The failure output identifies whether the
problem belongs to suite setup, one test, or suite cleanup. Code that runs before the
instrumentation-test harness initializes the tracer remains outside this window.
Apply process-wide configuration before starting servers, actor systems, executors, or other long-lived fixtures. Use a forked test or recreate the fixture when its static state cannot be reset safely.
Do not hide evidence
Instrumentation tests always use strict trace writes; there is no harness opt-out. Do not replace the harness tracer or add a new escape hatch to weaken that invariant.
Fix the continuation lifecycle when possible. If it cannot be fixed in the current change,
quarantine the test with @Flaky and a useful reason or tracked issue instead of weakening strict
trace writes. Keep continuation tracking enabled so the failure remains diagnosable.
Use @TrackScopeContinuations(enabled = false, reason = "...") only when the diagnostic itself is
incompatible with the test, not when it has found a real unresolved leak. Scope the opt-out as
narrowly as possible. The reason must describe the incompatibility and when the opt-out can be
removed; strict trace writes remain enabled.
Assess production impact
An unresolved continuation blocks normal reference-count completion, not necessarily publication.
The production PendingTrace buffer can still write finished spans; strict tests remove that
delayed-write fallback, but partial flush remains possible. Do not infer lost traces or a fixed
UI delay from a diagnostic failure. Check the collector and configuration; see
continuation effects.
Memory retention requires a reachable owner of the continuation/context; it does not prove the whole trace remains retained or memory grows without bound. Wrong parentage requires activation of unrelated context or a leaked active scope. Separate the observed lifecycle defect from its possible production effects and from test-only cleanup failures.
Explain it to a human
Lead with one sentence: what was captured, which cleanup edge was missing, and where. Cite the
timeline callsites. Then include a small Mermaid flowchart LR; use green for healthy edges, red
for the broken edge, and label thread handoffs. Use a Gantt only when timing itself caused the bug.
End with the code fix and the exact tests that passed.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

