Release typespec-ts emitter singleton state after $onEmit#4787
Conversation
Clear the context manager and module-level SDK-type collections at the end of $onEmit so the previously emitted program graph can be collected between emits instead of lingering until the next emit overwrites it. This is bounded-to-one-program hygiene, not a fix for an unbounded leak (the real leak tracked in microsoft/typespec#11120 is upstream in the compiler's experimental mutators). Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
All changed packages have been documented.
Show changes
|
commit: |
|
You can try these changes here
|
⚡ Benchmark Results
Full details – comparing
|
| Metric | Baseline | Current | Change |
|---|---|---|---|
| total | 🔴 678.0ms | 🔴 1.05s | +55.5% 🔴 |
| loader | 🟢 191.6ms | 🟡 328.0ms | +71.2% 🔴 |
| resolver | 🟢 19.4ms | 🟢 40.9ms | +111.2% 🔴 |
| checker | 🟡 213.9ms | 🟡 375.8ms | +75.6% 🔴 |
| validation | 🟢 47.6ms | 🟢 87.0ms | +82.5% 🔴 |
| ↳ validation/@azure-tools/typespec-azure-core | 🟢 7.0ms | 🟡 13.3ms | +90.6% 🔴 |
| ↳ validation/@typespec/http | 🟢 6.4ms | 🟡 16.2ms | +152.9% 🔴 |
| ↳ validation/@typespec/rest | 🟢 0.7ms | 🟢 1.7ms | +148.5% |
| ↳ validation/@typespec/versioning | 🔴 31.3ms | 🔴 51.7ms | +65.2% 🔴 |
| ↳ validation/compiler | 🟢 1.8ms | 🟢 4.0ms | +119.7% 🔴 |
| linter | 🟢 149.6ms | 🟡 222.9ms | +49.0% 🔴 |
| ↳ linter/@azure-tools/typespec-azure-core/auth-required | 🟢 0.0ms | 🟢 0.1ms | +382.6% |
| ↳ linter/@azure-tools/typespec-azure-core/bad-record-type | 🟢 0.2ms | 🟢 0.6ms | +140.6% |
| ↳ linter/@azure-tools/typespec-azure-core/byos | 🟢 6.3ms | 🟢 8.5ms | +35.8% 🔴 |
| ↳ linter/@azure-tools/typespec-azure-core/casing-style | 🟢 0.7ms | 🟢 1.5ms | +119.7% |
| ↳ linter/@azure-tools/typespec-azure-core/composition-over-inheritance | 🟢 0.1ms | 🟢 0.2ms | +133.2% |
| ↳ linter/@azure-tools/typespec-azure-core/documentation-required | 🟢 0.9ms | 🟢 2.0ms | +117.7% 🔴 |
| ↳ linter/@azure-tools/typespec-azure-core/friendly-name | 🟢 0.7ms | 🟢 1.4ms | +114.0% |
| ↳ linter/@azure-tools/typespec-azure-core/key-visibility-required | 🟢 0.2ms | 🟢 0.4ms | +113.4% |
| ↳ linter/@azure-tools/typespec-azure-core/known-encoding | 🟢 0.3ms | 🟢 0.5ms | +69.9% |
| ↳ linter/@azure-tools/typespec-azure-core/long-running-polling-operation-required | 🟢 0.3ms | 🟢 0.8ms | +151.4% |
| ↳ linter/@azure-tools/typespec-azure-core/no-case-mismatch | 🟢 0.3ms | 🟢 0.7ms | +163.3% |
| ↳ linter/@azure-tools/typespec-azure-core/no-closed-literal-union | 🟢 0.3ms | 🟢 1.0ms | +216.2% |
| ↳ linter/@azure-tools/typespec-azure-core/no-enum | 🟢 0.1ms | 🟢 0.3ms | +366.7% |
| ↳ linter/@azure-tools/typespec-azure-core/no-error-status-codes | 🟢 0.1ms | 🟢 0.3ms | +161.6% |
| ↳ linter/@azure-tools/typespec-azure-core/no-explicit-routes-resource-ops | 🟢 0.1ms | 🟢 0.2ms | +67.8% |
| ↳ linter/@azure-tools/typespec-azure-core/no-format | 🟢 0.6ms | 🟢 0.8ms | +44.7% |
| ↳ linter/@azure-tools/typespec-azure-core/no-generic-numeric | 🟢 0.5ms | 🟢 0.8ms | +84.7% |
| ↳ linter/@azure-tools/typespec-azure-core/no-header-explode | 🔴 20.4ms | 🔴 27.9ms | +36.7% 🔴 |
| ↳ linter/@azure-tools/typespec-azure-core/no-legacy-usage | 🟢 1.2ms | 🟢 2.0ms | +68.4% |
| ↳ linter/@azure-tools/typespec-azure-core/no-multiple-discriminator | 🟢 0.1ms | 🟢 0.2ms | +163.7% |
| ↳ linter/@azure-tools/typespec-azure-core/no-nullable | 🟢 0.3ms | 🟢 0.4ms | +61.1% |
| ↳ linter/@azure-tools/typespec-azure-core/no-offsetdatetime | 🟢 1.3ms | 🟢 2.0ms | +60.9% |
| ↳ linter/@azure-tools/typespec-azure-core/no-openapi | 🟢 2.0ms | 🟢 2.3ms | +14.3% |
| ↳ linter/@azure-tools/typespec-azure-core/no-private-usage | 🟢 2.0ms | 🟢 3.1ms | +52.4% 🔴 |
| ↳ linter/@azure-tools/typespec-azure-core/no-query-explode | 🔴 21.7ms | 🔴 29.2ms | +34.4% 🔴 |
| ↳ linter/@azure-tools/typespec-azure-core/no-response-body | 🔴 25.4ms | 🔴 34.6ms | +36.2% 🔴 |
| ↳ linter/@azure-tools/typespec-azure-core/no-rest-library-interfaces | 🟢 0.0ms | 🟢 0.1ms | +314.7% |
| ↳ linter/@azure-tools/typespec-azure-core/no-route-parameter-name-mismatch | 🟢 5.4ms | 🟢 8.2ms | +50.0% 🔴 |
| ↳ linter/@azure-tools/typespec-azure-core/no-rpc-path-params | 🟢 0.2ms | 🟢 0.4ms | +98.0% |
| ↳ linter/@azure-tools/typespec-azure-core/no-string-discriminator | 🟢 0.1ms | 🟢 0.2ms | +189.8% |
| ↳ linter/@azure-tools/typespec-azure-core/no-unknown | 🟢 0.2ms | 🟢 0.4ms | +76.8% |
| ↳ linter/@azure-tools/typespec-azure-core/no-unnamed-union | 🟢 0.4ms | 🟢 0.8ms | +103.0% |
| ↳ linter/@azure-tools/typespec-azure-core/operation-missing-api-version | 🟢 0.2ms | 🟢 0.4ms | +91.3% |
| ↳ linter/@azure-tools/typespec-azure-core/request-body-problem | 🟢 0.3ms | 🟢 0.5ms | +47.5% |
| ↳ linter/@azure-tools/typespec-azure-core/require-versioned | 🟢 0.0ms | 🟢 0.1ms | +467.0% |
| ↳ linter/@azure-tools/typespec-azure-core/response-schema-problem | 🔴 23.6ms | 🔴 34.5ms | +46.4% 🔴 |
| ↳ linter/@azure-tools/typespec-azure-core/rpc-operation-request-body | 🟢 0.3ms | 🟢 0.8ms | +123.7% |
| ↳ linter/@azure-tools/typespec-azure-core/spread-discriminated-model | 🟢 0.3ms | 🟢 0.5ms | +68.2% |
| ↳ linter/@azure-tools/typespec-azure-core/use-standard-names | 🟢 5.9ms | 🟢 7.9ms | +34.6% 🔴 |
| ↳ linter/@azure-tools/typespec-azure-core/use-standard-operations | 🟢 0.1ms | 🟢 0.3ms | +100.2% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-agent-base-type-child-resources | 🟢 4.7ms | 🔴 21.6ms | +355.1% 🔴 |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-agent-base-type-lifecycle-operations | 🟢 0.0ms | 🟢 0.3ms | +1319.3% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-common-types-version | 🟢 4.6ms | 🟡 12.4ms | +168.8% 🔴 |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-custom-resource-no-key | 🟢 0.1ms | 🟢 0.2ms | +134.8% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-custom-resource-usage-discourage | 🟢 0.1ms | 🟢 0.1ms | +97.0% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-delete-operation-response-codes | 🟢 1.6ms | 🟢 4.6ms | +181.7% 🔴 |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-no-path-casing-conflicts | 🟡 10.5ms | 🟡 17.1ms | +63.4% 🔴 |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-no-record | 🟢 0.4ms | 🟢 0.7ms | +78.7% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-post-operation-response-codes | 🟢 0.6ms | 🟢 1.5ms | +157.7% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-put-operation-response-codes | 🟢 0.0ms | 🟢 0.2ms | +651.2% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-action-no-segment | 🟢 0.2ms | 🟢 0.4ms | +73.5% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-duplicate-property | 🟢 0.1ms | 🟢 0.4ms | +190.2% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-interface-requires-decorator | 🟢 0.0ms | 🟢 0.1ms | +399.5% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-invalid-action-verb | 🟢 0.1ms | 🟢 0.2ms | +87.9% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-invalid-envelope-property | 🟢 0.1ms | 🟢 0.3ms | +174.7% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-invalid-version-format | 🟢 0.1ms | 🟢 0.2ms | +321.9% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-key-invalid-chars | 🟢 0.3ms | 🟢 0.5ms | +99.2% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-name-pattern | 🟢 0.0ms | 🟢 0.1ms | +661.8% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-operation | 🟢 0.2ms | 🟢 0.5ms | +193.8% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-operation-response | 🟢 5.3ms | 🟢 9.2ms | +75.0% 🔴 |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-patch | 🟢 0.3ms | 🟢 0.8ms | +137.9% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-path-segment-invalid-chars | 🟢 0.2ms | 🟢 0.4ms | +93.2% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-provisioning-state | 🟢 0.1ms | 🟢 0.4ms | +238.8% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/beyond-nesting-levels | 🟢 0.1ms | 🟢 0.2ms | +154.9% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/empty-updateable-properties | 🟢 0.2ms | 🟢 0.4ms | +162.8% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/improper-subscription-list-operation | 🟢 0.0ms | 🟢 0.1ms | +1078.4% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/lro-location-header | 🟡 14.6ms | 🔴 20.7ms | +42.0% 🔴 |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/missing-operations-endpoint | 🟢 0.0ms | 🟢 0.1ms | +384.3% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/missing-x-ms-identifiers | 🟢 0.3ms | 🟢 1.0ms | +195.8% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/no-empty-model | 🟢 0.1ms | 🟢 0.3ms | +93.4% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/no-override-props | 🟢 0.1ms | 🟢 0.3ms | +303.9% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/no-resource-delete-operation | 🟢 0.2ms | 🟢 0.5ms | +131.0% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/no-response-body | 🔴 21.5ms | 🔴 31.8ms | +48.2% 🔴 |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/patch-envelope | 🟢 0.2ms | 🟢 0.4ms | +161.6% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/resource-name | 🟢 0.2ms | 🟢 0.4ms | +167.2% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/secret-prop | 🟢 4.0ms | 🟢 5.3ms | +33.0% 🔴 |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/unsupported-type | 🟢 0.4ms | 🟢 0.7ms | +75.6% |
| ↳ linter/@azure-tools/typespec-azure-resource-manager/version-progression | 🟢 0.0ms | 🟢 0.3ms | +560.9% |
| ↳ linter/@azure-tools/typespec-client-generator-core/property-name-conflict | 🟢 1.2ms | 🟢 2.3ms | +100.0% 🔴 |
| ↳ linter/@azure-tools/typespec-client-generator-core/require-client-suffix | 🟢 0.3ms | 🟢 1.7ms | +510.0% 🔴 |
| emit | 🔴 5.59s | 🔴 6.13s | +9.7% 🔴 |
| ↳ emit/@Azure-Tools | 🟢 0.0ms | 🟢 0.0ms | +0.0% |
| ↳ emit/@azure-tools/typespec-autorest | 🟢 84.4ms | 🟢 129.2ms | +53.1% 🔴 |
| ↳ emit/@azure-tools/typespec-python | 🔴 2.15s | 🔴 2.27s | +5.8% 🔴 |
| ↳ emit/@typespec | 🟢 0.0ms | 🟢 0.0ms | +0.0% |
| ↳ emit/@typespec/http-client-js | 🔴 470.0ms | 🔴 586.2ms | +24.7% 🔴 |
| ↳ emit/@typespec/openapi3 | 🟢 76.7ms | 🟢 112.1ms | +46.0% 🔴 |
| ↳ emit/@typespec/openapi3/compute | 🟢 66.9ms | 🟢 97.4ms | +45.5% 🔴 |
| ↳ emit/@typespec/openapi3/write | 🟢 9.6ms | 🟢 14.3ms | +49.5% 🔴 |
Averaged across 3 specs (azure-arm-resource-manager, azure-core-dataplane, azure-full).
Threshold: changes > ±5% are highlighted.
🟢 Fast · 🟡 Moderate (stages >200ms, rules >10ms) · 🔴 Slow (stages >400ms, rules >20ms)
What
Clears the emitter's process-wide singleton state at the end of
$onEmit:ContextManager.clearContexts()— drops the storedEmitContext/Program, TCGCSdkContext, ts-morphProject, binder, etc.resetSdkTypesState()— clears the module-levelemitQueue/flattenPropertyModelMap/pagedModelsKeptPubliccollections.Why
These live at module scope, so after an emit they keep the most recently emitted program graph reachable until the next emit overwrites them. Clearing right after the emit finishes lets that memory be collected sooner when many emits run in one process (test suites, watch mode).
Scope / honesty
This is bounded-to-one-program hygiene — it is not a fix for an unbounded leak. The actual unbounded leak behind #4536 is upstream in the compiler's experimental mutators (
seencache pins every mutated program's type-graph for the process lifetime) and is tracked separately in microsoft/typespec#11120. This PR is just good housekeeping on the typespec-ts side and is independent of that fix.Changeset is marked
internalaccordingly.Related: #4536, microsoft/typespec#11120