Fork me on GitHub
#clojure
<
2023-03-18
>
jdkealy02:03:51

This shutDownHook never seems to get called in my app

(.addShutdownHook (Runtime/getRuntime)
                    (Thread.
                     #(dotimes [_ 20]
                        (log "SHUT_DOWN")
                        (mount/stop))))
I'm using Docker/Kubernetes

hiredman02:03:13

Shutdown hooks basically only get called in you call System/exit

hiredman02:03:21

If your process is being killed by some external thing there is no guarantee they will run

jdkealy02:03:31

So kubernetes gives it a kill signal, which seems to last some 30-60 seconds

jdkealy03:03:00

SIGTERM
is signal is given, then there's 30 seconds, and i'm not getting that signal

practicalli-johnny09:03:11

I have this expression in a -main function of a Clojure web service, which was working with docker and Aws

(.addShutdownHook (Runtime/getRuntime) (Thread. ^Runnable #(stop system))))
stop is a function that shuts down the system with a system config passed as an argument That part of the expression could be replaced with a call to mount stop or anything else

jdkealy18:03:14

Right. How do you stop your docker ?

practicalli-johnny18:03:19

locally I mostly use docker compose down as I'm often running more than one service. I dont think I've needed to check what AWS does specifically (I dont have access to any system at the moment). I havent tried a hook shutdown on Kubernettes as of yet

jdkealy19:03:12

So... I tried SSH'ing onto the kubernetes pod and called kill -15 on my process ID ... .i can see the shutdown behaivor actually works as expected

jdkealy19:03:37

PID TTY      STAT   TIME COMMAND
    1 ?        Ss     0:00 sh -c java -Xms1000m -Xmx4900m  -Ddatomic.metricsCallback=lms.db/stats-handler -Ddatomic.memcachedServers=clj-memcached:80 -jar target/lms.jar
    7 ?        Sl     0:31 java -Xms1000m -Xmx4900m -Ddatomic.metricsCallback=lms.db/stats-handler -Ddatomic.memcachedServers=clj-memcached:80 -jar target/lms.jar

jdkealy19:03:53

I have a suspiscioun that kubernetes is calling kill -15 on PID = 1

jdkealy19:03:02

but the shutdown only works on pid = 7

practicalli-johnny20:03:02

Perhaps use a tool like https://github.com/Yelp/dumb-init which ensures signals get to the relevant processes. dumb-init runs on PID 1 and the clojure app is run as a child and should receive the shutdown signal. Install dumb-init and use the dumb-init command as the ENTRYPOINT command and CMD to pass the java command to start the Clojure service as an argument. dumb-init ensures TERM signals are sent to the Java process and all child processes are cleaned up on shutdown.

ENTRYPOINT ["/usr/bin/dumb-init", "--"]
CMD ["java", "-jar", "/service/practicalli-service.jar"]
This is the approach I take for Dockerfile configs for Clojure https://practical.li/blog/posts/build-and-run-clojure-with-multistage-dockerfile/

Bobbi Towers08:03:44

Is there a Clojure book that goes particularly deep in terms of programming language theory?

respatialized12:03:57

To my knowledge nothing goes as deep as Structure and Interpretation of Computer Programs, which many people have adapted to Clojure from Scheme. I enjoyed the perspective in Elements of Clojure but I wouldn't say it goes deep into PL theory

👆 4
2
Ben Lieberman13:03:38

+1 for SICP, it's readily adaptable to Clojure

Clojuri0an08:03:21

any way to download clojure guide as epub? I like to do my reading without xorg or web browser as plain text

p-himik08:03:02

Not really Clojure related. There are extensions for browsers that let you save the current web page as an eBook. Although I don't know how you'd read it without X - epub also has formatting, it's not just text.

jdkealy19:03:53

When I call java -jar path/to/my.jar why does it create two processes ? My kubernetes deployment is getting confused and sending a kill signal to the wrong process. It launches PID=1 and it launches PID=7 I need either to get kubernetes to send the kill signal to PID=7, or i need to make clojure not launch a second process.

jdkealy19:03:06

PID TTY      STAT   TIME COMMAND
    1 ?        Ss     0:00 sh -c java -Xms1000m -Xmx4900m  -Ddatomic.metricsCallback=lms.db/stats-handler -Ddatomic.memcachedServers=clj-memcached:80 -jar target/lms.jar
    7 ?        Sl     0:31 java -Xms1000m -Xmx4900m -Ddatomic.metricsCallback=lms.db/stats-handler -Ddatomic.memcachedServers=clj-memcached:80 -jar target/lms.jar

p-himik19:03:31

What do you mean by "call"? It seems that that PID 1 is actually the parent process of PID 7, so PID 1 is the thing that executes that java command.

p-himik19:03:58

Also, it should've been asked in #off-topic or some other channel - not in #clojure.

lispyclouds19:03:33

the first process is sh and that is forking the java process. maybe you have sh -c 'java -jar ...' as the entrypoint in the image? if so, this is expected.

jdkealy20:03:15

Yes it's the entrypoint of the image

jdkealy20:03:41

only because when i try without sh -c i get this error

Message:      failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "java -Xms1000m -Xmx1000m  -Ddatomic.metricsCallback=lms.db/stats-handler -Ddatomic.memcachedServers=clj- │
│ memcached:80 -jar /usr/src/app/target/lms.jar": stat java -Xms1000m -Xmx1000m  -Ddatomic.metricsCallback=lms.db/stats-handler -Ddatomic.memcachedServers=clj-memcached:80 -jar /usr/src/app/target/lms.jar: no such file or directory: unknown    │

lispyclouds20:03:56

can you show what the entry point is in the dockerfile? this seems to be taking the entire string java -jar ... as the excutable and not java and rest as args

jdkealy20:03:38

command = ["java ${var.settings[terraform.workspace].api.xms} ${var.settings[terraform.workspace].api.xmx}  -Ddatomic.metricsCallback=lms.db/stats-handler -Ddatomic.memcachedServers=clj-memcached:80 -jar /usr/src/app/target/lms.jar"]

jdkealy20:03:45

I'm not using CMD from dockerfile

jdkealy20:03:09

i'm using command in kubernetes / terraform

lispyclouds20:03:26

can you try command = ["java", "...", "..."]

lispyclouds20:03:02

specify each as a list item and not one full string. this is how the standard cmd syntax is

lispyclouds20:03:39

also like its mentioned before, we can handle such question better on #C0PME9N9X for instance 😄

jdkealy20:03:16

Wow that was totally it

lispyclouds20:03:42

id recommend looking into the cmd and entrypoint specs, quite fundamental but confusing too 😅

practicalli-johnny21:03:08

https://github.com/Yelp/dumb-init is also a useful tool for managing service processes running in Docker, an example can be found in https://practical.li/blog/posts/build-and-run-clojure-with-multistage-dockerfile/

jumar05:03:27

This also happens when you have a shell script wrapper for you java command. You can use exec to make java be the pid 1 but bear in mind that pid 1 has responsibilities like reaping zombies. I like to use tini https://github.com/krallin/tini See also my blog post https://curiousprogrammer.net/posts/2022-04-23-java-in-docker-zombies

💡 2