"If Edison had a needle to find in a haystack, he would proceed at once with the diligence of the bee to examine straw after straw until he found the object of his search." - Nikola Tesla
This is the common basis for some of otto.de's microservices. It is written in clojure using the component framework.
tesla-microservice is used for a number of different services now. Still it is a work in progress. See CHANGES.md for instructions on breaking changes.
- Load configuration from filesystem.
- Aggregate a status.
- Execute functions with a scheduler
- Reply to a health check.
- Deliver a json status report.
- Report to graphite using the metrics library.
- Manage handlers using ring.
- Optional auto-hot-reloading of changed source files
- Shutdown gracefully. If necessary delayed, so load-balancers have time to notice.
- A growing set of example applications can be found at tesla-examples.
- David & Germán created an example application based, among other, on tesla-microservice. They wrote a very instructive blog post about it
- Moritz created tesla-pubsub-service. It showcases how to connect components via core.async channels. Also the embedded jetty was replaced by immutant.
The scheduler wraps a thread-pool which can be used for scheduling tasks. It is based on overtones at-at project.
To actually use it you have to pass the :scheduler
as a dependency to the component in which it should be used.
Afterwards you can schedule tasks using the overtone api like this:
(overtone.at-at/every 100 #(println "Hello world") (de.otto.tesla.stateful.scheduler/pool scheduler) :desc "HelloWord Task")
The overtone-pool wrapped by the scheduler can be configured by the config-entry :scheduler
. (See overtone.at-at/mk-pool
)
By default the pool holds no threads.
The app-status indicates the current status of your microservice. To use it you can register a status function to it.
Here is a simple example for a function that checks if an atom is empty or not.
(de.otto.tesla.stateful.app-status/register-status-fun app-status #(status atom))
The app-status
is injected under the keyword :app-status from the base system.
(defn status [atom]
(let [status (if @atom :error :ok)
message (if @atom "Atom is empty" "Atom is not empty")]
(de.otto.status/status-detail :status-id status message)))
For further information and usages take a look at the: status library
As of version 0.1.15
there is no server included any more directly in tesla-microservice.
This gives you the freedom to a) not use any server at all (e.g. for embedded use) b) choose another server e.g. a non-blocking one like httpkit or immutant. The available options are:
- tesla-jetty: The tried and tested embedded jetty.
- tesla-httpkit: The non-blocking httpkit.
Applications build with tesla-microservices
can be configured via
edn
-files, that have to be located in the class path.
For backwards compatibility, it is also possible to load config from properties
-files.
See below for noteworthy differences.
- A file named
default.edn
is loaded as a resource from classpath if present. - A file either named
application.edn
or overridden by the ENV-variable$CONFIG_FILE
is loaded as a resource or, if that is not possible, from the filesystem. - A file name
local.edn
is loaded from classpath if present.
The configuration hash-map in those files is loaded and merged in the specified order. Which mean configurations for the same key is overridden by the latter occurrence.
In contrast to former versions of tesla-microservice
ENV-variables are not
merged into the configuration.
But you can easily specify ENV-variables, that should be accessible in your configuration:
{
:my-app-secret #ts/env [:my-env-dep-app-secret "default"]
}
ENV-variables are read with environ. To see which keyword represents which ENV-var have a look in their docs.
For backwards compatibility, it is also possible to load config from properties
-files.
You'll have to pass {:property-file-preferred true}
as a runtime config to the base-system.
It is not possible to load individual environment variables when using properties config.
Adding :merge-env-to-properties-config true
to the runtime config will add all system properties
and environment variables, overiding any config from files.
Applications utilizing Tesla-Microservice can use iapetos prometheus client for monitoring.
Metrics are send by reporters which can be configured using the :metrics
keyword.
Each configured reporter will start at system startup automatically.
See example configuration below for all supported reporters.
:metrics {:graphite {:host "localhost"
:port "2003"
:prefix "my.prefix"
:interval-in-s 60
:include-hostname :first-part}
:prometheus {:metrics-path "/metrics"}}
Restarting the whole system after a small change can be cumbersome. A tesla-microservice can detect changes to your source files and load them into a running server. Add this to your config, to check for changes on each request to your system:
{:handler {:hot-reload? true}}
Note: This should only be enabled in development mode.
Use your local.edn
to enable this feature safely.
You can add a private.edn
as well for personal configurations. This file should be added to your .gitignore
.
The Tesla-Microservice comes with endpoints that hold information about the internal state of your application. Those endpoints can be the app-status or even metrics (Prometheus, see above). To secure those endpoints you can provide an authentication-middleware to the base-system.
E.g.:
(defn auth-middleware [config handler-fn]
(fn [request] (if (authenticated? config request)
(handler-fn request)
{:status 401 :body "access denied"})))
(defn example-system [runtime-config]
(-> (de.otto.tesla.system/base-system runtime-config auth-middleware)))
The basis included is stripped to the very minimum. Additional functionality is available as addons:
- tesla-zookeeper-observer: Read only access to zookeeper.
- tesla-mongo-connect: Read/write access to mongodb.
- tesla-cachefile: Read and write a cachefile. Locally or in hdfs.
More features will be released at a later time as separate addons.
Q: Is it any good? A: Yes.
Q: Why tesla? A: It's a reference to the ingenious scientist and inventor.
Q: Are there alternatives? A: Yes. You might want to look at modularity.org, system and duct.
Christian Stamm, Felix Bechstein, Ralf Sigmund, Kai Brandes, Florian Weyandt
Released under Apache License 2.0 license.