Saturday, November 10, 2018

Unix Signals with Clojure (1.10-beta5), JDK11, and Kubernetes (1.12)

Kubernetes has a beta feature where you can share the process namespaces for a pod, allowing you to send, say, SIGHUP to another container in the pod, assuming you set the relevant permissions in the pod manifest.

Clojure and JDK11 allow you to catch signals, through sun.misc.Signal, (despite years of threatening to take it away).

So you can catch SIGHUP with the following:

(defn set-signal-handler!
  "Catch HUP, INT, or USR1, etc. and run a one argument handler that
  accepts a sun.misc.Signal"
  [sig f]
  (sun.misc.Signal/handle
   (sun.misc.Signal. sig)
   (proxy [sun.misc.SignalHandler] []
     (handle [received-signal]
       (f received-signal)))))

Just for reference, you can get your pid via

 (.pid (java.lang.ProcessHandle/current))

If you need to send a signal from Clojure, I'd suggest shelling out, as to the best of my knowledge, the JVM only lets you send SIGTERM and SIGKILL:

(clojure.java.shell/sh "/bin/kill" "-s" "SIGINT" "<some-pid>")

or

(clojure.java.shell/sh "/usr/bin/pkill" "-HUP" "some-process-name")

Here is the relevant Kubernetes information with the pod configuration, which basically amounts to setting shareProcessNamespace: true at the top of the pod spec, and adding the following to the container that will be sending the signal:

securityContext:
      capabilities:
        add:
        - SYS_PTRACE

Also, if you've come this far, you should take a look at https://github.com/pyr/signal

Note that java has a flag that seems to be related.  I found it after I wrote the original post.

-XX:+AllowUserSignalHandlers
Enables installation of signal handlers by the application. By default, this option is disabled and the application isn’t allowed to install signal handlers.

Referenced Javadocs:
java.lang.ProcessHandle