Server Tuning

Contents

  1. Application Middleware
  2. Immutant Configuration
  3. Context paths

While Luminus aims to provide reasonable defaults, you will likely want to tune your server configuration to fit the needs of your specific application.

Application Middleware

Luminus includes a number of useful wrappers in its default middleware stack. These include ring-defaults, session middleware, ring-middleware-format, and ring-webjars.

While such middleware is useful in most situations, it will also incur a performance cost. In cases where you wish to optimize for performance, only wrap the routes with the necessary middleware. For example, if a route doesn't serve static resources, then you would not need to wrap it with the webjars middleware.

Immutant Configuration

Luminus used to be using Immutant as the default server, but now it defaults to ring-undertow. The following information is still applicable to using +immutant.

The Immutant server provides a number of options that are unique to it.

Immutant allows setting the number of worker and IO threads using the :worker-threads and the :io-threads keys respectively. For example, we could update the default configuration as follows:

(mount/defstate http-server
  :start
  (http/start
    (-> env
        (assoc
          :handler handler/app
          :worker-threads 200
          :io-threads (* 2 (.availableProcessors (Runtime/getRuntime))))
        (update :port #(or (-> env :options :port) %))))
  :stop
  (http/stop http-server))

Note that the env is used to supply the base configuration, meaning that any initialization parameters can also be supplied using the environment variables at runtime.

Another feature provided by Immutant is the ability to chain multiple independent handlers together. Luminus provides the wrap-handler helper function for this purpose:

(mount/defstate http-server
                :start
                (->
                   (http/start
                     (-> env
                        (assoc :handler handler/app)
                        (update :port #(or (-> env :options :port) %))))
                   (http/wrap-handler io-routes {:path "/io" :dispatch? false}))
                :stop
                (http/stop http-server))

The additional handler uses a :path prefix as a context. All the routes served by this handler will be prefixed with the supplied path. Each handler can have its own middleware stack that's independent of other handlers in the application.

Immutant uses separate thread pools for managing the IO and the worker threads. The :dispatch? flag is used to decide whether the request should be dispatched by the IO thread to a separate worker thread. Since dispatching the request to a worker carries overhead, it may be more performant to handle some requests, such as hardcoded text responses, directly in the IO thread.

Context paths

Set the value of :handler-path key to customize the global path for the application (default is /). In the example below the value is gotten from a custom environment variable :my-path.

(mount/defstate http-server
    :start
    (http/start
      (-> env
        (assoc :handler (handler/app))
        (update :port #(or (-> env :options :port) %))
        (update :handler-path #(or (-> env :my-path) %))))
    :stop
    (http/stop http-server))

You can also supply the :app-context key in the environment that's used by the wrap-context wrapper in the middleware namespace. It will populate the *app-context* variable in the layout namespace. That can be used to populate the context on the page for the client to use.