enso links into a GraalVM native image. The HTTP/1.1, HTTP/2 and WebSocket
server needs no reflection or resource metadata. HTTP/3 does not go into the
image: it calls the quiche shim through JNI, so leave :http3 off (the
default).
Two working examples: examples/graalvm-clojure
uses the Clojure run-server, examples/graalvm starts
the server from Java. Build and run either:
export GRAALVM_HOME=/path/to/graalvm # or put native-image on PATH
examples/graalvm-clojure/build.sh
examples/graalvm-clojure/target/enso-native
curl http://127.0.0.1:8080/
run-server works unchanged. The entrypoint namespace is AOT-compiled with
:gen-class, which also compiles s-exp.enso.
(ns example.server
(:require [s-exp.enso :as enso])
(:gen-class))
(defn -main [& _]
(enso/run-server (fn [_] {:status 200 :body "hello\n"})
{:port 8080})
@(promise))
Starting the server from Java keeps the image to the server and the handler
you write. The request map is still a Clojure data structure, so clojure.lang
is on the classpath either way.
Config config = new Config.Builder().host("127.0.0.1").port(8080).build();
RingHandler handler = request ->
new Response(200, Map.of("content-type", "text/plain"),
"hello\n".getBytes());
new EnsoServer(handler, config).start();
Clojure's classes initialise at build time through the
graal-build-time feature. The
request map extends clojure.lang.AFn, so the Clojure runtime is part of the
image; the feature initialises it in the right order. Without it the build
fails in clojure.lang.Compiler.
--features=clj_easy.graal_build_time.InitClojureClasses
The Clojure example also initialises its own namespace and enso's Java packages
at build time. s-exp.enso builds a few Java objects as it loads (a rate
limiter, loggers); those objects can only live in the image when their classes
initialise at build time too.
--initialize-at-build-time=example.server,com.s_exp.enso
The classpath passed to native-image must list target/classes by an
absolute path, or be resolved from the repository root. clojure -Spath
prints it relative, so both build.sh scripts run native-image from the
repository root.
The example serves TLS when ENSO_TLS_CERT and ENSO_TLS_KEY point at a PEM
certificate and key. The JVM's SSL engine works in the image with no extra
flags for RSA keys. An EC key also needs SunEC (libsunec, shipped with
GraalVM) reachable at run time.
openssl req -x509 -newkey rsa:2048 -nodes -days 7 \
-keyout key.pem -out cert.pem \
-subj /CN=localhost -addext subjectAltName=DNS:localhost,IP:127.0.0.1
ENSO_TLS_CERT=cert.pem ENSO_TLS_KEY=key.pem examples/graalvm/target/enso-native
curl -k https://127.0.0.1:8443/
Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |