Thank you for telling me how "it works".
You are welcome!
FWIW, I'm all ears and am following every incoming GH issue being reported on SwiftPM. The community needs to be successful and hopefully I can help with that.
SwiftPM should get the love it deserves, so thank you for your efforts.
i think server encompasses a huge range of very different types of applications, so when i hear āthis is how it worksā i try to read an implicit within the problem domain that i spend most of my time working on.
Yeah, would be nice to have a way to execute some things in isolated memory space.
agreed. I did not take it any other way ; )
Also, I am not even disagreeing with @Helge_Hess1. Many times things will be just fine if you somehow manage to wind down a bit more elegantly rather than crash on the spot.
But, to me, it is a bit like saying "accessing this shared state is fine, I have the threading under control", and then you end up having the weirdest, most difficult to find issues with data races.
Unless there are some compile-time and/or runtime guarantees that things are not messed up beyond repair after an undefined op, crashing is a fine solution in my book.
Any other pain points for Swift Server applications that aren't related to crash isolation?
I was addressing one specific technological aspect. He suggested that a failing transaction would just be ignored, because YOLO. This is incorrect, state of the art (for like 20+ years) is that a process that failed somewhere is wound down cleanly w/o killing other transactions unnecessarily. We have very good infra available that does such things.
There are good reasons for this generally, but Swift is an outlier here with its crash first mentality that doesn't fit that well on servers. We can argue how relevant that is in what deployment circumstances, but I think there is no need to argue that it is actually a relevant issue.
The other thing that comes to my mind is memory management. In a Swift program you are bound to hit retain cycle issues eventually. You can design to work against that, but the language allows for it and it will hit you at one point.
Again, that is a know problem we have general infrastructure (e.g. Apache) for to deal with it gracefully, but not something that is usually deployed in the SwiftNIO space.
Say more, is the issue in your view that Swift uses ARC on the server, or that ARC is fine, but the tools to help debug retain cycles should be easier to use for server deployments? Or something else?
fatalError is a hard trip on the whole process, it can't be isolated. That's essentially the issue being discussed.
I think ARC is fine (just like SwiftNIO is fine), but it is a tradeoff. You accept cycles in return for determinism and speed. That will definitely be worth it if you are serving billions of users, but that gain is often irrelevant at smaller scales (even in most apps).
What I'm saying that it is likely that you'll have retain cycles eventually (yes, those are "just" bugs, but ones that don't happen w/ a GC), and that the regular Swift server side deployment setup today doesn't deal gracefully with it.
E.g. in Apache you can tell it that once a processing child exceeds a certain memory limit, it will be shutdown cleanly and a fresh one will serve the next requests. That doesn't mean that the bug is fixed, but that the environment is resilient against such bugs.
It goes along the other things, Swift is fast and performant, but not very resilient. Pick your poison ;-)
to compare notes, hereās what i am currently doing
i currently do not use swiftly, i just use Docker for my development environment.
i currently use SwiftPM, as there is no real alternative to it. i believe there is broad consensus on what the missing pieces in SwiftPM are but for note-keeping iāll list them below:
- no support for shallow git clone
- cannot build app in debug mode but dependencies in release mode
- cannot use pre-built dependencies
- does not check for explicit target dependency by default, still requires a long-winded command line flag that i can never remember the spelling of
- cache invalidation for local package dependencies doesnāt seem to work very reliably at the moment
i currently avoid both, but largely because they increase binary size by a lot, which also increases baseline memory consumption by the same amount.
the platform portability aspect is less important to me, mostly because a lot of this code is server-specific and therefore Linux-only.
the swift-async-algorithms package has a similar issue, which i currently solve by just copying and pasting the source code of the AsyncChannel
implementation into my projects.
i currently use ArraySlice<UInt8>
everywhere. it really works!
i use Docker to deploy, which took me a long time to figure out but itās pretty nice once youāve got it set up. sadly, this stuff is sparsely documented, especially the cross-compilation aspect, and i only figured it out because many kind folks on these Forums spent time helping me.
i believe we as a project need to consider documentation as a blocking requirement for evolution proposals, as we have gotten into the habit of shipping a lot of complex features while treating the educational aspect as an afterthought.
i use VSCode
i write and maintain a lot of my own libraries, and open-source many of them. but obviously thatās not a scalable practice. we need to see more (financial!) investment from Apple in the library ecosystem.
I think proper Xcode support for server side Swift would help the effort a lot. This includes things like "Previews for Endpoints".
That you have to rebuild every time is another achilles heel of it.
I host multiple Swift servers in production on a locally hosted Arch Linux machine, and develop using VSCode & SwiftPM on an Arch Linux machine.
I used to main macOS with Xcode for the development of my servers and open-source projects, but there were way too many variables to consider for cross deployment (personally I've had problems with variations of: clang, gcc, Swift, llvm, different installed compilers, different tooling) that resulted in the servers crashing daily, but not once on macOS, while deploying the same code! Swift has gotten better on Linux, and in general, in this regard the past 2 years.
Like others have pointed out, server resilience is the main pain point of Swift on Server. Using safer techniques when parsing/sanitizing input data eliminated all my crashes, but I had to manually create those solutions.
With Swift 6 it is a lot easier to fix problems relating to memory access (at least in my experience). Perhaps more compilation errors/warnings should be added to detect possible crashes relating to integer overflows and manipulating decoded data. Third-party libraries can do this, albeit in a very limited capacity, utilizing Swift Macros and diagnostic messages.
In summary, my pain points for deploying Swift on Server are:
- different code behavior on macOS than Linux (especially when working with unsafe pointers; irrelevant if developing & deploying on Linux)
- crashes relating to integer overflow or input decoding require manual solution to avoid crashing
- bloated dependencies (not really a problem, but adds unnecessary compilation time; SwiftPM will be getting better at this in the future; my precious uptime...)
- great libraries and Swift/Apple features not being cross-platform (data compression, localization)
- great libraries in other languages needing a Swift compatibility layer, if they don't already have one
- lack of standalone libraries (or any library) for creating websites, managing databases, server networking, data compression, localization, and region subdivisions
There are way more points that make Swift excellent for applications, even for servers. The only real competitor in this space that I see is Rust, but Swift is way easier to use and understand syntactically.
I'm actively developing open-source standalone libraries for my pain points
- Websites: Swift HTMLKit
- Databases: Swift Database
- Server Networking: Destiny
- Data Compression: Swift Compression
- Localization: Swift String Catalogs
- Region Subdivisions: Swift Sovereign States
are there compression algorithms you would like to use in Swift, but donāt have library support?
Well, all of the best/well known ones out there. Itās not really the lack of library support, but more of doing it well. Like there is always a tradeoff, whether it be implementation, lacking customization or not being standalone. I'd much rather have a single library that does them all, or a few libraries focused on a single compression area (one for SSL, one for images & video, one for text and similar data, etc).
This gripe is mainly based on the Compression
framework not being available on Linux and some good libraries not being standalone (pulls in a large dependency that I won't use).
Just to name a few: huffman coding, brotli, deflate, jpeg, h.264 & h.265, gzip, zstd, lz + variants, 7Z, RAR, DNAC-SBE, json compression, bzip2, botan, boringssl, openssl, s2n-tls.
have you looked at swift-png yet? it implements the LZ77 algorithm and the Gzip format, which is just a wrapper around an LZ77 algorithm. LZ77 and DEFLATE are also the same thing.
i have also written the swift-jpeg library for the JPEG format
I am trying something like this there, maybe others might join the efforts (or write something better). (UPDATE: I started a separate topic on this.) But this has overhead.
Well, I think it is also about selling your application (in cases where it is not you who is actually running it). The customer might want to run only one instance (maybe as a first deployment), and telling the customer that a failure in a single request might crash the whole application is not a good selling point.
Sorry for quoting myself, but maybe one of the compiler people could comment this, would be interesting to know. Thanks.
Yes, the discussion about this point got big here, could better be a topic on its own. But it seems to be a major pain point for some people (including me).
UPDATE: I started a separate topic on this.