Skip to content

manage mutagen daemon lifecycle for coder-desktop-macos #381

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
spikecurtis opened this issue Feb 18, 2025 · 2 comments · Fixed by coder/coder-desktop-macos#98
Closed

manage mutagen daemon lifecycle for coder-desktop-macos #381

spikecurtis opened this issue Feb 18, 2025 · 2 comments · Fixed by coder/coder-desktop-macos#98
Assignees

Comments

@spikecurtis
Copy link

Daemon Lifecycle

  • We’ll embed the daemon in Coder Desktop as described in the [mutagen docs.](https://mutagen.io/documentation/introduction/daemon/)
    • We’ll use a data directory under the main Coder Desktop data directory to ensure our instance of mutagen doesn’t interfere with other instances on the system (i.e. directly installed by the end user).
  • We’ll use Mutagen’s existing autostart capability if possible, and avoid implementing our own autostart.
    • Technical risk: Support is listed as experimental. If we find problems we should be prepared to roll our own lifecycle management.
    • call mutagen daemon register when first file sync is created
    • call mutagen daemon unregister when last file sync is deleted, or file sync disabled entirely.
@ethanndickson
Copy link
Member

ethanndickson commented Mar 5, 2025

We’ll use Mutagen’s existing autostart capability if possible, and avoid implementing our own autostart.

Without forking, we won't be able to use mutagen daemon register in conjunction with MUTAGEN_DATA_DIRECTORY as mutagen reads the environment on start-up, and doesn't persist the configured directory.

To test this, I ran MUTAGEN_DATA_DIRECTORY=($pwd) mutagen daemon register, and made sure ~/.mutagen did not exist. Initially, the pwd was used as the data directory, but on restart ~/.mutagen had been created and was used instead. The mutagen source code backs this up.

The Mac app already has support for launching on login - on app launch we could just spawn the mutagen daemon as a background process using mutagen daemon run (as opposed to start) and manage it ourselves.

@spikecurtis
Copy link
Author

Agreed, let's use mutagen daemon run and manage ourselves.

ethanndickson added a commit to coder/coder-desktop-macos that referenced this issue Mar 12, 2025
Closes coder/internal#381.

- Moves the VPN-specific app files into a `VPN` folder.
- Adds an empty `Resources` folder whose contents are copied into the bundle at build time.
- Adds a `MutagenDaemon` abstraction for managing the mutagen daemon lifecycle, this class:
  -  Starts the mutagen daemon using `mutagen daemon run`, with a `MUTAGEN_DATA_DIRECTORY` in `Application Support/Coder Desktop/Mutagen`, to avoid collisions with a system mutagen using `~/.mutagen`.
  -  Maintains a `gRPC` connection to the daemon socket.
  -  Stops the mutagen daemon over `gRPC`
  -  Relays stdout & stderr from the daemon, and watches if the process exits unexpectedly.
  -  Handles replacing an orphaned `mutagen daemon run` process if one exists.

This PR does not embed the mutagen binaries within the bundle, it just handles the case where they're present.


## Why is the file sync code in VPNLib?

When I had the FileSync code (namely protobuf definitions) in either:
- The app target
- A new `FSLib` framework target

Either the network extension crashed (in the first case) or the app crashed (in the second case) on launch.
The crash was super obtuse:
```
Library not loaded: @rpath/SwiftProtobuf.framework/Versions/A/SwiftProtobuf
```
especially considering `SwiftProtobuf` doesn't have a stable ABI and shouldn't be compiled as a framework.

At least one other person has ran into this issue when importing `SwiftProtobuf` multiple times:
apple/swift-protobuf#1506 (comment)

Curiously, this also wasn't happening on local development builds (building and running via the XCode GUI), only when exporting via our build script.

### Solution

We're just going to overload `VPNLib` as the source of all our SwiftProtobuf & GRPC code. Since it's pretty big, and we don't want to embed it twice, we'll embed it once within the System Extension, and then have the app look for it in that bundle, see `LD_RUNPATH_SEARCH_PATHS`. It's not exactly ideal, but I don't think it's worth going to war with XCode over.


#### TODO
- [x] Replace the `Process` with https://github.com/jamf/Subprocess
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants