{"id":13846464,"url":"https://github.com/sunng87/slacker","last_synced_at":"2025-04-12T15:33:40.496Z","repository":{"id":1907426,"uuid":"2834632","full_name":"sunng87/slacker","owner":"sunng87","description":"Transparent, non-incursive RPC by clojure and for clojure","archived":false,"fork":false,"pushed_at":"2022-04-29T08:04:34.000Z","size":804,"stargazers_count":356,"open_issues_count":4,"forks_count":28,"subscribers_count":12,"default_branch":"master","last_synced_at":"2025-04-03T15:08:56.529Z","etag":null,"topics":["clojure","remote","rpc","rpc-framework","slacker"],"latest_commit_sha":null,"homepage":"","language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"epl-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sunng87.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2011-11-23T09:33:23.000Z","updated_at":"2025-03-18T14:33:41.000Z","dependencies_parsed_at":"2022-09-08T11:12:36.893Z","dependency_job_id":null,"html_url":"https://github.com/sunng87/slacker","commit_stats":null,"previous_names":[],"tags_count":42,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sunng87%2Fslacker","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sunng87%2Fslacker/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sunng87%2Fslacker/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sunng87%2Fslacker/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sunng87","download_url":"https://codeload.github.com/sunng87/slacker/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248589886,"owners_count":21129698,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["clojure","remote","rpc","rpc-framework","slacker"],"created_at":"2024-08-04T18:00:34.691Z","updated_at":"2025-04-12T15:33:40.464Z","avatar_url":"https://github.com/sunng87.png","language":"Clojure","funding_links":["https://liberapay.com/Sunng/donate"],"categories":["Clojure","\u003ca name=\"Clojure\"\u003e\u003c/a\u003eClojure","开发框架"],"sub_categories":["RPC框架"],"readme":"# slacker\n\n![slacker](http://i.imgur.com/Jd02f.png)\n\nslacker is a simple RPC framework designed for Clojure and created by\nClojure.\n\n[![Build Status](https://travis-ci.org/sunng87/slacker.png?branch=master)](https://travis-ci.org/sunng87/slacker)\n[![Clojars](https://img.shields.io/clojars/v/slacker/slacker.svg)](https://clojars.org/slacker)\n[![License](https://img.shields.io/badge/license-eclipse-blue.svg)](https://github.com/sunng87/slacker/blob/master/LICENSE)\n[![Donate](https://img.shields.io/badge/donate-liberapay-yellow.svg)](https://liberapay.com/Sunng/donate)\n\n## Features\n\n* Fast network layer, fully asynchronous and multiplexed\n* Plugable serialization backend, EDN, JSON and Nippy are built-in.\n* Transparent and non-incursive API. Calling remote is just like local invocation.\n* Extensible server and client with interceptor framework.\n* Flexible cluster with Zookeeper (moved to\n  [slacker-cluster](https://github.com/sunng87/slacker-cluster))\n\n## Slacker family\n\n* [slacker-cluster](https://github.com/sunng87/slacker-cluster)\n  Slacker cluster, service discovery with Zookeeper, and custom\n  grouping call.\n* [slacker-metrics](https://github.com/sunng87/slacker-metrics)\n  Codahale's metrics collector as a slacker interceptor. It measures\n  QPS and latency for every function exposed.\n* [slacker-htrace](https://github.com/sunng87/slacker-htrace)\n  Distributed tracing for slacker.\n* [slacker-rust](https://github.com/sunng87/slacker-rust)\n  An experimental slacker RPC implementation in Rust.\n* [slacker-python](https://github.com/sunng87/slacker-python)\n  A limited python library for calling slacker functions.\n\n## Examples\n\nA pair of example server/client can be found under \"examples\", you\ncan run the examples by `lein run-example-server` and\n`lein run-example-client`. The example client will print out various\noutputs from the server as well as a RuntimeException: \"Expected exception.\"\nThis exception is part of the example - not a genuine error in the slacker\nsource code.\n\n## Usage\n\n### Leiningen\n\n\n[![latest version on clojars](https://clojars.org/slacker/slacker/latest-version.svg)](https://clojars.org/slacker/slacker)\n\n### Basic Usage\n\nSlacker will expose all your public functions under a given namespace.\n\n``` clojure\n(ns slapi)\n(defn timestamp\n  \"return server time in milliseconds\"\n  []\n  (System/currentTimeMillis))\n\n;; ...more functions\n```\n\nTo expose `slapi` from port 2104, use:\n\n``` clojure\n(use 'slacker.server)\n(start-slacker-server [(the-ns 'slapi)] 2104)\n```\n\nMultiple namespaces can be exposed by appending them to the vector\n\nYou can also add option `:threads 50` to configure the size of server\nthread pool.\n\nOn the client side, You can use `defn-remote` to create facade one by\none. Remember to add remote namespace here as facade name,\n`slapi/timestamp`, eg. Otherwise, the name of current namespace will\nbe treated as remote namespace.\n\n``` clojure\n(use 'slacker.client)\n(def sc (slackerc \"localhost:2104\"))\n(defn-remote sc slapi/timestamp)\n(timestamp)\n```\n\nAlso the `use-remote` function is convenience for importing all functions\nunder a remote namespace. (Note that `use-remote` uses inspection\ncalls to fetch remote functions, so network is required.)\n\n``` clojure\n(use-remote 'sc 'slapi)\n(timestamp)\n```\n\nBy checking the metadata of `timestamp`, you can get some useful\ninformation:\n\n``` clojure\n(slacker-meta timestamp)\n=\u003e {:slacker-remote-name \"timestamp\", :slacker-remote-fn true,\n:slacker-client #\u003cSlackerClient\nslacker.client.common.SlackerClient@575752\u003e, :slacker-remote-ns\n\"slapi\" :arglists ([]), :name timestamp\n:doc \"return server time in milliseconds\"}\n```\n\n### Advanced Usage\n\n#### Options in defn-remote\n\nYou can specify the remote function name when there are conflicts in\ncurrent namespace.\n\n``` clojure\n(defn-remote sc remote-time\n  :remote-ns \"slapi\"\n  :remote-name \"timestamp\")\n```\n\nIf you add an `:async?` flag to `defn-remote`, then the facade will be\nasynchronous which returns a *promise* when you call it. You should\nderef it by yourself to get the return value.\n\n``` clojure\n(defn-remote sc slapi/timestamp :async? true)\n@(timestamp)\n```\n\nYou can also assign a callback `(fn [error result])` for an\nasynchronous facade.\n\n``` clojure\n(defn-remote sc slapi/timestamp :callback #(println %2))\n(timestamp)\n```\n\nThe callback accepts two arguments\n\n* error\n* result\n\nYou need to check (nil? error) because reading the result. Also note\nthat doing blocking tasks in callback function could ruin system\nperformance.\n\n#### Serialiation\n\nSlacker provides plugable serialization support. From 0.13, Slacker\nuses Clojure EDN as default serializer, because it doesn't introduce\nin additional dependencies. Also Slacker provides built-in support for\n[cheshire (json)](https://github.com/dakrone/cheshire) and\n[nippy](https://github.com/ptaoussanis/nippy). Personally I\nrecommend you to use `:nippy` in real applications because it's\nfast and compact.\n\n##### JSON Serialization\n\nJSON is a text based format which is more friendly to\nhuman beings. It may be useful for debugging, or communicating with\nexternal applications. In order to use JSON, be sure to include any\nversion of cheshire in your classpath, because Slacker doesn't depend\non it at compile time.\n\nConfigure slacker client to use JSON:\n\n``` clojure\n(def sc (slackerc \"localhost:2104\" :content-type :json))\n```\n\nOne thing you should note is the representation of keyword in\nJSON. Keywords and strings are both encoded as JSON string in\ntransport. But while decoding, all map keys will be decoded to\nkeyword, and all other strings will be decoded to clojure string.\n\n##### EDN Serialization\n\nFrom slacker 0.4, clojure pr/read is supported. And then in 0.13, EDN\nbecomes default serialization. You can just set content-type as\n`:clj`. clojure pr/read has full support on clojure data structures\nand also easy for debugging. However, it's much slower and verbose\nthan binary format, so you'd better not use it if you have critical\nperformance requirements.\n\n##### Nippy Serialization\n\nSlacker 0.13 and above has full support for\n[nippy](https://github.com/ptaoussanis/nippy) serialization. Remember\nto add nippy into your classpath and set the content-type as `:nippy`\nto use it. Nippy has excellent support for custom types, you can find\ndetailed information on its page.\n\n#### Interceptor\n\nTo add custom functions on server and client, you can define custom\ninterceptors before or after function called.\n\n``` clojure\n(definterceptor logging-interceptor\n   :before (fn [req] (println (str \"calling: \" (:fname req))) req))\n\n(start-slacker-server (the-ns 'slapi) 2104\n                      :interceptors (interceptors logging-interceptor))\n```\n\nFor more information about using interceptors and creating your own\ninterceptors, query the [wiki\npage](https://github.com/sunng87/slacker/wiki/Interceptors).\n\nHere we have two typical demo middlewares:\n\n* The [metrics middleware](https://github.com/sunng87/slacker-metrics)\nintegrates [metrics-clojure](https://github.com/sjl/metrics-clojure)\ninto slacker server.\n* The [htrace middleware](https://github.com/sunng87/slacker-htrace)\nenables htrace distributed tracing on both server and client side.\n\n#### Slacker on HTTP\n\nFrom 0.4, slacker can be configured to run on HTTP protocol. To\nenable HTTP transport, just add a `:http` option to your slacker\nserver:\n\n``` clojure\n(start-slacker-server ...\n                      :http 4104)\n```\n\nThe HTTP url pattern is\nhttp://localhost:4104/*namespace*/*function-name*.*format*.  Arguments\nare encoded in *format*, and posted to server via HTTP body. If you\nhave multiple arguments, you should put them into a clojure vector\n(for clj format) or javascript array (for json format).\n\nSee a curl example:\n\n``` bash\n$ curl -d \"[5]\" http://localhost:4104/slapi/rand-ints.clj\n(38945142 1413770549 1361247669 1899499977 1281637740)\n```\n\nNote that you can only use `json` or `clj` as format.\n\n#### Slacker as a Ring App\n\nYou can also use slacker as a ring app with\n`slacker.server/slacker-ring-app`. The ring app is fully compatible\nwith ring spec. So it could be deployed on any ring adapter.\n\n``` clojure\n(use 'slacker.server)\n(use 'ring.adapter.jetty)\n\n(run-jetty (slacker-ring-app (the-ns 'slapi))  {:port 8080})\n```\n\nThe url pattern of this ring app is same as slacker's built-in http\nmodule.\n\n#### Custom client on function call\n\nOne issue with previous version of slacker is you have to define a\nremote function with a slacker client, then call this function with\nthat client always. This is inflexible.\n\nFrom 0.10.3, we added a macro `with-slackerc` to isolate local\nfunction facade and a specific client. You can call the function with\nany slacker client.\n\n```clojure\n;; conn0 and conn1 are two slacker clients\n\n(defn-remote conn0 timestamp)\n\n;; call the function with conn0\n(timestamp)\n\n;; call the function with conn1\n(with-slackerc conn1\n  (timestamp))\n```\n\nNote that you have ensure that the function you call is also available\nto the client. Otherwise, there will be a `not-found` exception\nraised.\n\n## API Documentation\n\n[API docs](https://cljdoc.org/s/slacker/slacker/)\n\n## Performance\n\nTo test performance, just start an example server with `lein run -m\nslacker.example.server`.\n\nThen run the performance test script:\n`lein exec -p scripts/performance-test.clj 200000 40`. This will run\n200,000 calls with 40 threads.\n\nTested on my laptop(i7-5600U), **200,000** calls with **40** threads\nis completed in **12677.487741 msecs**, which means slacker could\nhandle more than **15700** calls per second on this machine.\n\n## License\n\nCopyright (C) 2011-2019 Sun Ning\n\nDistributed under the Eclipse Public License, the same as Clojure.\n\n## Donation\n\nI'm now accepting donation on [liberapay](https://liberapay.com/Sunng/donate),\nif you find my work helpful and want to keep it going.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsunng87%2Fslacker","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsunng87%2Fslacker","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsunng87%2Fslacker/lists"}