Swift-service-lifecycle question

While doing some deep dive research and optimizations for some of my server projects using swift-service-lifecycle (not swift-nio), it is consistently bloating the binaries with swift-async-algorithms stuff while also having the second largest symbol (and more, lesser symbols; even in release mode).

None of my projects use swift-async-algorithms directly but do use swift-service-lifecycle minimally. Is there any way to use swift-service-lifecycle without AsyncAlgorithms, or is there any alternative, without having to create my own solution? Wouldn't a small actor + system-dependent signal handling suffice for something like this?

You can just handle the signals manually: MultiArchSwiftDockerfileExample/Sources/ExampleApp/main.swift at master · Cyberbeni/MultiArchSwiftDockerfileExample · GitHub

(If you only want FoundationEssentials and not the whole Foundation then you can also use dispatchMain() instead of RunLoop. Some Foundation stuff depends on using RunLoop, IIRC Timer is one of those)

1 Like

This works, is beautiful and is exactly what I'm looking for. Thank you! :heart:

Do you mind opening an issue in the service-lifecycle-repo about this? Maybe we can slim down the required code that we need from async algos or we could use another approach. Right now the only reason ServiceLifecycle is using AsyncAlgorithms is for merge which we might be able to replace.

Sure thing: swift-async-algorithms dependency bloat (binary size optimization) · Issue #210 · swift-server/swift-service-lifecycle · GitHub

Do you also do stripping when measuring binary size? MultiArchSwiftDockerfileExample/Package.swift at 481f3e5a72e508419bcf7c22aea01e07301e7f96 · Cyberbeni/MultiArchSwiftDockerfileExample · GitHub

There have been some discussions in some server side repos that package traits could be used in the future to control transitively importing frameworks (mainly the full Foundation because that also pulls in FoundationICU which contains around 30-40MBs of data): swift-evolution/proposals/0450-swiftpm-package-traits.md at main · swiftlang/swift-evolution · GitHub

Yes, I usually only do stripping when pushing to production or specialized debugging. I got a small http server using my networking library down to 12.1 MiB as a stripped executable, and most of that is from swift-syntax I suspect. The swift-syntax prebuilts don't work for me at the moment so I guess that's the best I can do for now.

Hmm, if you are linking swift-syntax into your production binary, the pre-builts won't reduce the footprint for your production code. It will still be linked in.

I understand. What I was thinking there was to dynamically link swift-syntax, but that is a whole different hurdle in Swift and doing that is not a high priority for me right now.

I am now thinking more about reducing swift-syntax's overall footprint by looking for ways to improve its binary sizes (like codegen for ChildNameForKeyPath.swift, SwiftParser and the Rewriter & Visitor).