i have a tool written in Swift that occasionally traps on precondition failure. changing the tool so that it never traps is not realistic, and is also not desirable. therefore, i would like to run the tool as a child process to allow for cleanup and recovery if the tool crashes.
the tool has a complex interface, so i do not want to write a command line argument parser for it. is there a simpler way to run a Swift function in a child process?
This is probably not a good answer, but it would be fun to make a distributed actor provider that did that. The reason my mind went there is because all the structure is there to handle the argument/result serialization and asynchrony.
My experimental implementation just uses Process, so that's probably not what I'd call "lightweight." But I am eager to explore how distributed actors could be used instead for the same purpose.
@ktoso knows far more about what's possible with them than I do.
I'd love to try that. A first naive question - does it work on iOS? IIRC before we were limited to one process per app (excluding extensions for things like QuickLook previewing, audio units, sharing, etc).
If the subtask doesn't need to also run as native code, and can run within the limits of the platform, another thing to try might be to build it as wasm and run it in a wasm host. wasm might be an interesting way of building the "in process distributed actor host" concept Jordan alluded to.
My first thought was: thatâs just a fork. A quick search on âfork without execâ shows that you have to be very careful with it though, but perhaps itâs usable in your situation.
Any chance that implementation can become its own library? I really need something like that for a project I'm currently working on. Right now I'm using Process which accepts data as a blob of serialised stuff. This is much less ergonomic than using something like your implementation and obviously more bug prone
Any chance that implementation can become its own library?
Why, yes!
The Foundation folks are in the process (hey hey) of creating a replacement for Process. See [Pitch] Swift Subprocess. I donât think thereâs any ETA for that yet, but itâs definitely on the cards.
In the meantime, there are a number of alternative Process wrappers from other third-party developers. I donât keep track of them â due to the nature of my work, Iâm not able to use third-party libraries â so I canât give you a specific recommendation. Perhaps someone else will chime inâŚ
Subprocess still can't run a swift function inside it though. I'm working on a project where it would be highly beneficial to do just that. For now, I'm using a multicall binary and a bincode-encoded blob of data to pass it all the needed information. This works fine, but feels pretty junky. So an ability to run a function in a subprocess would be incredibly nice to have. See: procspawn â Rust data encoding library // Lib.rs as an example
We'd have a binary that we launch and enter the "child process mode" and communicate with it. You could have a distributed actor encapsulate your (distributed) function and this way invoke it in the child process. It doesn't have to be the same binary, but we could think of such way -- I had old old old prototypes with just that in the distributed actors library from way before we even had actors in the language, for inspiration. We could do this much nicer today with (distributed) actors being part of the language though
The implementation in swift-testing's proof-of-concept exit tests feature is probably not possible to factor into a library as-is. It depends on some pretty deep/arcane knowledge of the Swift runtime's emitted metadata. @ktoso's distributed actors work is probably closer to a general-purpose solution.