Add opt-in assembly trimming for self-contained .NET 8 publishes#1272
Draft
jimmyp wants to merge 2 commits into
Draft
Add opt-in assembly trimming for self-contained .NET 8 publishes#1272jimmyp wants to merge 2 commits into
jimmyp wants to merge 2 commits into
Conversation
Publishing with -p:EnableTrimming=true enables PublishTrimmed in partial mode, which trims only assemblies that declare themselves trim-compatible (the framework). App and NuGet assemblies are kept whole, so reflection-based code (Autofac registrations, Newtonsoft serialization, NLog config, attribute-scanned Halibut services) keeps working. TrimmerRoots.xml preserves System.Lazy`2, which Autofac instantiates via reflection for Lazy<ICommand, CommandMetadata> command registrations and which the trimmer would otherwise strip. Measured on linux-x64 self-contained Release publish: - baseline: 102 MB (265 files) - partial trim: 59 MB (203 files), -42% - full trim: 32 MB, but breaks NLog custom layout renderers at startup and cannot be safely verified against Newtonsoft-based Halibut wire serialization, so it is not the default. win-x64 shows the same ratio (103 MB -> 58 MB). Smoke-tested the partial-trimmed linux-x64 output: version, help, create-instance, new-certificate, show-thumbprint, list-instances, and a 10s agent run with the Halibut listener bound on 10933. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011AL61wGJeScoyKmdhtRUPy
|
|
Full trim mode (-p:EnableTrimming=true -p:TrimMode=full) member-trims app and NuGet assemblies as well as the framework. Root the reflection-driven assemblies (Tentacle projects, Halibut, Newtonsoft.Json, NLog, Autofac, KubernetesClient) so they are kept whole. Measured on linux-x64: 49 MB vs 59 MB for partial mode. With these roots the full-trimmed Tentacle passes command and agent smoke tests (create-instance, new-certificate, agent with Halibut listener) but still hangs the integration test suite, so full mode remains experimental; partial mode is the supported configuration. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011AL61wGJeScoyKmdhtRUPy
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Background
Self-contained Tentacle publishes carry the full .NET runtime (~102 MB on linux-x64). .NET's assembly trimming can remove the unused parts of the runtime at publish time. This PR adds an opt-in trimming mode to measure and validate that saving without changing any default build behaviour.
Trimming is enabled with
-p:EnableTrimming=trueat publish time and usesTrimMode=partial, which only trims assemblies that declare themselves trim-compatible (the framework). App and NuGet assemblies (Autofac, Newtonsoft.Json, NLog, KubernetesClient, the attribute-scanned Halibut services) are kept whole, so their reflection-based behaviour is unaffected.One trimmer root descriptor (
TrimmerRoots.xml) is required: Autofac materialisesLazy<ICommand, CommandMetadata>command registrations by invokingLazyconstructors through reflection, which the trimmer cannot see and would otherwise strip.An experimental full-trim configuration (
-p:TrimMode=full) with root assemblies for the reflection-driven libraries is also included but is NOT the supported path — see Results.Results
Measured on net8.0 Release self-contained publishes (linux-x64):
Assembly.Locationusage (IL3000)win-x64 shows the same ratio for partial trim (103 MB → 58 MB).
Before
dotnet publish -f net8.0 -r linux-x64 -c Release --self-contained→ 102 MBAfter
dotnet publish -f net8.0 -r linux-x64 -c Release --self-contained -p:EnableTrimming=true→ 59 MBTest evidence (partial trim, linux-x64)
Ran
Octopus.Tentacle.Tests.IntegrationclassesCapabilitiesServiceV2Test,ScriptServiceV2IntegrationTest,FileTransferServiceTests,TentacleCommandLineTests,TentacleStartupAndShutdownTests,ScriptServiceTests,WorkspaceCleanerTests,ScriptsAreGivenRequiredEnvironmentVariables,MachineConfigurationHomeDirectoryTestswith the trimmed publish substituted as the Tentacle under test: 105 passed, 12 failed — and an untrimmed control run fails the identical 12 test cases (old 5.0.4/5.0.12 downloaded tentacle binaries and service-manager tests that cannot run in the sandbox container), i.e. no trimming-attributable failures.Also smoke-tested:
version,help,create-instance,new-certificate,show-thumbprint,list-instances --format json, and anagentrun with the Halibut listener bound and NLog file logging working.How to review this PR
This is an experiment to validate trimming viability — an "in principle" review is the goal. Nothing changes for existing builds: trimming only activates when
-p:EnableTrimming=trueis passed at publish time, and only for the net8.0/net8.0-windows targets. The interesting review questions are whether partial-mode trimming is an acceptable risk profile for reflection-heavy code, and what test coverage should gate turning this on in the release pipeline.Quality ✔️
Full
Octopus.Tentacle.Tests.Integrationsuite on CI against a trimmed publish is the remaining gate before wiring this into the release pipeline; the local subset run above (105 tests, failures identical to untrimmed control) is the evidence so far.Pre-requisites
🤖 Generated with Claude Code
https://claude.ai/code/session_011AL61wGJeScoyKmdhtRUPy