• Stars
    star
    356
  • Rank 119,446 (Top 3 %)
  • Language
    Clojure
  • License
    Eclipse Public Li...
  • Created almost 13 years ago
  • Updated over 2 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Transparent, non-incursive RPC by clojure and for clojure

slacker

slacker

slacker is a simple RPC framework designed for Clojure and created by Clojure.

Build Status Clojars License Donate

Features

  • Fast network layer, fully asynchronous and multiplexed
  • Plugable serialization backend, EDN, JSON and Nippy are built-in.
  • Transparent and non-incursive API. Calling remote is just like local invocation.
  • Extensible server and client with interceptor framework.
  • Flexible cluster with Zookeeper (moved to slacker-cluster)

Slacker family

  • slacker-cluster Slacker cluster, service discovery with Zookeeper, and custom grouping call.
  • slacker-metrics Codahale's metrics collector as a slacker interceptor. It measures QPS and latency for every function exposed.
  • slacker-htrace Distributed tracing for slacker.
  • slacker-rust An experimental slacker RPC implementation in Rust.
  • slacker-python A limited python library for calling slacker functions.

Examples

A pair of example server/client can be found under "examples", you can run the examples by lein run-example-server and lein run-example-client. The example client will print out various outputs from the server as well as a RuntimeException: "Expected exception." This exception is part of the example - not a genuine error in the slacker source code.

Usage

Leiningen

latest version on clojars

Basic Usage

Slacker will expose all your public functions under a given namespace.

(ns slapi)
(defn timestamp
  "return server time in milliseconds"
  []
  (System/currentTimeMillis))

;; ...more functions

To expose slapi from port 2104, use:

(use 'slacker.server)
(start-slacker-server [(the-ns 'slapi)] 2104)

Multiple namespaces can be exposed by appending them to the vector

You can also add option :threads 50 to configure the size of server thread pool.

On the client side, You can use defn-remote to create facade one by one. Remember to add remote namespace here as facade name, slapi/timestamp, eg. Otherwise, the name of current namespace will be treated as remote namespace.

(use 'slacker.client)
(def sc (slackerc "localhost:2104"))
(defn-remote sc slapi/timestamp)
(timestamp)

Also the use-remote function is convenience for importing all functions under a remote namespace. (Note that use-remote uses inspection calls to fetch remote functions, so network is required.)

(use-remote 'sc 'slapi)
(timestamp)

By checking the metadata of timestamp, you can get some useful information:

(slacker-meta timestamp)
=> {:slacker-remote-name "timestamp", :slacker-remote-fn true,
:slacker-client #<SlackerClient
slacker.client.common.SlackerClient@575752>, :slacker-remote-ns
"slapi" :arglists ([]), :name timestamp
:doc "return server time in milliseconds"}

Advanced Usage

Options in defn-remote

You can specify the remote function name when there are conflicts in current namespace.

(defn-remote sc remote-time
  :remote-ns "slapi"
  :remote-name "timestamp")

If you add an :async? flag to defn-remote, then the facade will be asynchronous which returns a promise when you call it. You should deref it by yourself to get the return value.

(defn-remote sc slapi/timestamp :async? true)
@(timestamp)

You can also assign a callback (fn [error result]) for an asynchronous facade.

(defn-remote sc slapi/timestamp :callback #(println %2))
(timestamp)

The callback accepts two arguments

  • error
  • result

You need to check (nil? error) because reading the result. Also note that doing blocking tasks in callback function could ruin system performance.

Serialiation

Slacker provides plugable serialization support. From 0.13, Slacker uses Clojure EDN as default serializer, because it doesn't introduce in additional dependencies. Also Slacker provides built-in support for cheshire (json) and nippy. Personally I recommend you to use :nippy in real applications because it's fast and compact.

JSON Serialization

JSON is a text based format which is more friendly to human beings. It may be useful for debugging, or communicating with external applications. In order to use JSON, be sure to include any version of cheshire in your classpath, because Slacker doesn't depend on it at compile time.

Configure slacker client to use JSON:

(def sc (slackerc "localhost:2104" :content-type :json))

One thing you should note is the representation of keyword in JSON. Keywords and strings are both encoded as JSON string in transport. But while decoding, all map keys will be decoded to keyword, and all other strings will be decoded to clojure string.

EDN Serialization

From slacker 0.4, clojure pr/read is supported. And then in 0.13, EDN becomes default serialization. You can just set content-type as :clj. clojure pr/read has full support on clojure data structures and also easy for debugging. However, it's much slower and verbose than binary format, so you'd better not use it if you have critical performance requirements.

Nippy Serialization

Slacker 0.13 and above has full support for nippy serialization. Remember to add nippy into your classpath and set the content-type as :nippy to use it. Nippy has excellent support for custom types, you can find detailed information on its page.

Interceptor

To add custom functions on server and client, you can define custom interceptors before or after function called.

(definterceptor logging-interceptor
   :before (fn [req] (println (str "calling: " (:fname req))) req))

(start-slacker-server (the-ns 'slapi) 2104
                      :interceptors (interceptors logging-interceptor))

For more information about using interceptors and creating your own interceptors, query the wiki page.

Here we have two typical demo middlewares:

Slacker on HTTP

From 0.4, slacker can be configured to run on HTTP protocol. To enable HTTP transport, just add a :http option to your slacker server:

(start-slacker-server ...
                      :http 4104)

The HTTP url pattern is http://localhost:4104/*namespace*/*function-name*.*format*. Arguments are encoded in format, and posted to server via HTTP body. If you have multiple arguments, you should put them into a clojure vector (for clj format) or javascript array (for json format).

See a curl example:

$ curl -d "[5]" http://localhost:4104/slapi/rand-ints.clj
(38945142 1413770549 1361247669 1899499977 1281637740)

Note that you can only use json or clj as format.

Slacker as a Ring App

You can also use slacker as a ring app with slacker.server/slacker-ring-app. The ring app is fully compatible with ring spec. So it could be deployed on any ring adapter.

(use 'slacker.server)
(use 'ring.adapter.jetty)

(run-jetty (slacker-ring-app (the-ns 'slapi))  {:port 8080})

The url pattern of this ring app is same as slacker's built-in http module.

Custom client on function call

One issue with previous version of slacker is you have to define a remote function with a slacker client, then call this function with that client always. This is inflexible.

From 0.10.3, we added a macro with-slackerc to isolate local function facade and a specific client. You can call the function with any slacker client.

;; conn0 and conn1 are two slacker clients

(defn-remote conn0 timestamp)

;; call the function with conn0
(timestamp)

;; call the function with conn1
(with-slackerc conn1
  (timestamp))

Note that you have ensure that the function you call is also available to the client. Otherwise, there will be a not-found exception raised.

API Documentation

API docs

Performance

To test performance, just start an example server with lein run -m slacker.example.server.

Then run the performance test script: lein exec -p scripts/performance-test.clj 200000 40. This will run 200,000 calls with 40 threads.

Tested on my laptop(i7-5600U), 200,000 calls with 40 threads is completed in 12677.487741 msecs, which means slacker could handle more than 15700 calls per second on this machine.

License

Copyright (C) 2011-2019 Sun Ning

Distributed under the Eclipse Public License, the same as Clojure.

Donation

I'm now accepting donation on liberapay, if you find my work helpful and want to keep it going.

More Repositories

1

handlebars-rust

Rust templating with Handlebars
Rust
1,089
star
2

node-geohash

geohash library for nodejs
JavaScript
565
star
3

heatcanvas

Pixel based heatmap with html5 canvas.
JavaScript
401
star
4

diehard

Clojure resilience library for flexible retry, circuit breaker and rate limiter
Clojure
309
star
5

ring-jetty9-adapter

An enhanced version of jetty adapter for ring, with additional features like websockets, http/2 and http/3
Clojure
228
star
6

pgwire

PostgreSQL wire protocol implemented as a rust library.
Rust
163
star
7

shake

clojure library that shakes your shell
Java
122
star
8

handlebars-iron

Handlebars middleware for Iron web framework
Rust
118
star
9

slacker-cluster

Clojure Micro-Service framework based on Slacker RPC
Clojure
77
star
10

pyclj

talking clojure with python - an edn implementation for python
Python
63
star
11

lein-jlink

A lein plugin creates and manages custom java environment
Clojure
59
star
12

hbs

clojure templating by handlebars.java
Clojure
48
star
13

papaline

Clojure concurrent pipleline on core.async
Clojure
47
star
14

rigui

Hierarchical Timing Wheels for Clojure and ClojureScript
Clojure
45
star
15

urdict

command line urban dictionary
Rust
42
star
16

stavka

Stavka manages configuration from various sources, for your Clojure application.
Clojure
41
star
17

exaile-doubanfm-plugin

An alternative choice to enjoy personalized music from douban.fm
Python
40
star
18

openbirdingmap

eBird location and observation data rendered on OpenStreetMap
Clojure
35
star
19

metriki

Rust metrics ported from dropwizard metrics
Rust
27
star
20

reddit.clj

A clojure wrapper for Reddit API
Clojure
25
star
21

rustmann

A riemann client on tokio, async/await
Rust
20
star
22

clojalk

A beanstalkd (distributed task queue) clone in clojure
Clojure
20
star
23

Exaile-Soundmenu-Indicator

integrate exaile with sound menu indicator
Python
19
star
24

cljts

A clojure wrapper of JTS, implements Simple Feature Specification of OGC
Clojure
17
star
25

clojuredocs-android

An Android app for ClojureDocs
JavaScript
14
star
26

lein-control

A lein plugin for clojure control
Clojure
12
star
27

tojson_macros

Simple rust syntax extension generates default ToJson implementation
Rust
11
star
28

timing

clojure syntax sugars for perf4j
Clojure
11
star
29

iron-json-response

Json response middleware for iron
Rust
10
star
30

stages

SEDA framework
Java
7
star
31

exaile-doubanfm-gnome-shell-extension

Exaile DoubanFM Control on GNOME-shell
JavaScript
7
star
32

bason

annotaion driven bson mapping tookit
Java
6
star
33

rageviewer

A rage comic viewer in clojure
Clojure
6
star
34

slacker-rust

Slacker RPC implemented by Rust and for Rust
Rust
4
star
35

greptimedb-bin.aur

AUR repository for GreptimeDB
Shell
4
star
36

lein-bootclasspath-deps

A Leiningen plugin to manage your bootclasspath.
Clojure
4
star
37

slacker-python

python client for slacker
Python
3
star
38

lazypress

Simplified online writing and publishing
JavaScript
3
star
39

sway-im.aur

Sway with input method popup support, packaged as AUR
Shell
2
star
40

mapzei

A maps extension for Ruman Nurik's live wallpaper app Muzei.
Java
2
star
41

karmalet

working in progress
Clojure
2
star
42

debug

Clojure port of nodejs debug
Clojure
2
star
43

link-socketio

Socketio server with link API
Clojure
2
star
44

slacker-htrace

Distributed tracing support for Slacker RPC using Apache HTrace
Clojure
2
star
45

nordenize

A project aimed to transform any webpage into nord color theme.
TypeScript
2
star
46

Artificial301

a simple firefox plugin and google appengine help you to get real link behind feedburner/feedproxy.google.com and url shorten services
JavaScript
2
star
47

alpine-jlink-base

Minimal base image for custom JRE created from jlink
1
star
48

handlebars-gotham

Handlebars templating middleware for Gotham
Rust
1
star
49

slacker-metrics

The metrics middleware for slacker RPC
Clojure
1
star
50

athtool

Command line TOTP generator
Rust
1
star
51

radar

redis proxy [WIP]
Clojure
1
star
52

metaq

A set of metaq API in favour of clojure
Clojure
1
star
53

leancloud-rtm-blacklist

LeanCloud ćźžæ—¶é€šäżĄèŠć€©ćź€é»‘ćć•èŒƒäŸ‹
JavaScript
1
star
54

datafusion-postgres

Rust
1
star
55

greptimedb-metabase-driver

A metabase driver plugin for GreptimeDB
Clojure
1
star