boot-clj / boot

Build tooling for Clojure.
https://boot-clj.github.io/
Eclipse Public License 1.0
1.75k stars 180 forks source link

New task: socket-server #549

Closed pesterhazy closed 7 years ago

pesterhazy commented 7 years ago

Exposes the Socket Server functionality available in Clojure 1.8 or above as a new task. By default, the handler function is clojure.core.server/repl, but a different handler can be specified.

This is useful because Clojure's standard way of enabling the socket server, by setting a system property, doesn't work well with boot (https://github.com/boot-clj/boot/issues/453).

Wheres boot repl --server, provides nREPL functionality used in CIDER, boot socket-server can be used e.g. with Emacs's inf-clojure mode. It starts up much faster than boot repl --server (12s vs 80s), and is more easily accessible using nc or telnet. But compared to REPLy it is pretty bare-bones and doesn't provide advanced features like auto-completion or beautiful stack traces.

This commit adds a new task rather than extending repl. The reason is that Socket Servers provides not just REPL but server functionality in general, and that repl semantics are already confusing because of how --server and --client flags work.

Like repl, socket-server defaults to picking a port at random and stores it in a file, .socket-port, in the current directory.

Fixes #453

pesterhazy commented 7 years ago

Looking into this again, I thought about your suggestion, @martinklepsch. boot.pod or boot.util don't seem appropriate places to put this code as they contain fns to do with pods or utilities.

I don't fully understand why code in a pod would want to run launch-socket-server as opposed to just calling clojure.core.server/start-server. In my view launch-socket-server is just the implementation of the deftask.

I chose core.clj so the fn sits next to launch-nrepl. Is part of the concern that we shouldn't clutter core.clj? In that case maybe boot.task.built-in would be better?

martinklepsch commented 7 years ago

launch-nrepl runs an nrepl server in a pod via boot.repl/launch-nrepl 🙂

The concern is not cluttering core but instead making it available as a general utility (which includes usage from within pods) which is not possible when it's put into core.

Seeing that there is boot.repl maybe it should just go there?

Edit: if you look closely at boot.core/launch-nrepl you see it's mostly a shim around boot.repl/launch-nrepl that handles some defaults around pods and allows passing the name of a pod where the nrepl server should be launched.

pesterhazy commented 7 years ago

Would this mean that the code needs to be run in a pod, like the nrepl server?

martinklepsch commented 7 years ago

@pesterhazy no, you can still run it in your regular REPL just like that or wherever you want of course (theoretically everything is in a pod but that's more of a detail and probably not what you're concerned about).

pesterhazy commented 7 years ago

I've updated the PR as per the comments above

martinklepsch commented 7 years ago

I think this is good to merge but maybe someone else can take a look too? @Deraen @alandipert?

alandipert commented 7 years ago

Just took a look. Awesome, thanks!

Looking at this I thought it might be cool if launch-socket-server took an optional pod name argument. Then we'd have a way to get simultaneous pod REPLs. If it took the argument, the pod name should perhaps influence the name of .socket-port, or maybe not create such a file at all.

danielsz commented 7 years ago

Great work, folks. Thank you!

pesterhazy commented 7 years ago

@alandipert, thanks for merging!

Could you outline a scenario where opening a socket server into a pod would be useful?

martinklepsch commented 7 years ago

@pesterhazy I think what @alandipert is thinking of are situations where you want to "look into a pod" but don't have a reference to the pod object and instead only have the name.

I have never needed to look into a pod like that myself though.

alandipert commented 7 years ago

@pesterhazy getting a REPL in a pod with the repl task's -P option is useful for developing Boot, and for developing and debugging tasks that use pods.

Using repl -P to get a REPL inside a pod is especially useful when tasks don't make their pods public. It's a way to run code in them anyway :sunglasses: