I’ve written a crude module for retrieving files from a remote server using rsync, since I didn’t see any existing tools already. This could be useful anywhere one needs to efficiently move files across filesystem or network boundaries, and could even be used for better control and monitoring of deployments. Does it sound like something I should package into a library?
The inner logic takes advantage of the --info=progress2 reporting mode for rsync, reading status lines to monitor progress:
Thanks. Had a quick look. IMO you should include a complete example with the error messages that your GenServer can also emit (not only the happy path). I’d be interested in just copy-pasting such an entire block of code in a project of mine and then tuning the separate case branches for my goals. Better peace of mind.
I was also curious about error cases, so I added some tests that show reasonable behavior when rsync emits random junk (forward to Logger at :warning level) and when the process crashes (forward error to linked parent). Deleted: random claims that the tests are a full example.
Feel free to share the case statements you add for your own application goals.
I struggle with basic OTP principles. Is the normal way to handle a start_link failure to run it under a Supervisor? Anyone feel like sharing a snippet showing how to run a brittle command like this and catch the error?
In my own app I’m letting Oban handle the retry logic and in tests I’ve trapped the exit but these are side-stepping typical usage I suspect.
Very informative post, Adam. I am using ports to communicate with long-running OS processes and struggle to understand the niceties about how to signal them from the BEAM. I did not know about erl_child_setup but I see that it is used by two other OS process-oriented libraries: alcove and prx.
I’d be curious to hear more about the obstacles that you’ve run into. If you mean “signal” in the generic sense of sending data back and forth, there are certainly some complexities but it should be possible to accomplish whatever you need, just set up a gen_server to write and read to and from the process.
But if you mean “signal” in the POSIX kill sense I think it’s impossible to do with the built-in functions, since the OS PID mapping is strictly internal and can’t be accessed from code. If this is the intention, you could write a wrapper in C or shell, which listens for messages from BEAM and translates those into signals to send to child. But I wait to hear more!
@akash-akya thanks for pointing this out! I updated the linked blog with your correction but unfortunately can’t edit my post above, so the misinformation will linger…
The other shortcoming of the “kill” approach which I should mention here is that it’s hard to include as an automatic clean-up, for example if the controlling BEAM process tree is shut down. That’s what lead me to push the signaling down into erl_child_setup or the analogous C shim program included in the rsync library.