Skip to content
This repository was archived by the owner on Jun 11, 2023. It is now read-only.

Commit 34ce73c

Browse files
author
Oleg Noga
committed
initial
1 parent 36e9547 commit 34ce73c

File tree

5 files changed

+191
-14
lines changed

5 files changed

+191
-14
lines changed

.gitignore

+5-14
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,5 @@
1-
pom.xml
2-
pom.xml.asc
3-
*.jar
4-
*.class
5-
/lib/
6-
/classes/
7-
/target/
8-
/checkouts/
9-
.lein-deps-sum
10-
.lein-repl-history
11-
.lein-plugins/
12-
.lein-failures
13-
.nrepl-port
14-
.cpcache/
1+
/target
2+
/.nrepl-port
3+
/.idea
4+
/*.iml
5+
/*.lein-*

README.adoc

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
= Consul agent client for clojure
2+
3+
Any clojure service can register and send heartbeats to consul agent.
4+
5+
== Start continuous heartbeat
6+
7+
Service will be registered initially.
8+
If consul or third party deregisters service, registration will be renewed"
9+
10+
[source,clojure]
11+
----
12+
(start-heartbeat {:id "my-service" ; service id
13+
:address "127.0.0.1" ; service remote address
14+
:port 8081
15+
:ttl "15s" ; timeout since last heartbeat to set critical state
16+
:deregister-critical-service-after "1m" ; timeout for consul to deregister service in critical state
17+
:interval-ms 7500}) ; heartbeat interval, milliseconds
18+
----
19+
20+
== Stop continuous heartbeat
21+
22+
[source,clojure]
23+
----
24+
(stop-heartbeat "my-service")
25+
----
26+
27+
== Single hearbeat
28+
29+
Service will be registered if not registered yet.
30+
31+
[source,clojure]
32+
----
33+
(heartbeat {:id "my-service"
34+
:address "127.0.0.1"
35+
:port 8081
36+
:ttl "15s"
37+
:deregister-critical-service-after "1m"})
38+
----

project.clj

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
(defproject consul-clj "0.1.0"
2+
:description "Clojure library for registering service with consul agent"
3+
:url "https://github.com/tbt-post/consul-clj"
4+
:license {:name "MIT"}
5+
:dependencies [[http-kit "2.3.0"]
6+
[cheshire "5.10.0"]
7+
[org.clojure/core.async "1.3.610"]
8+
[org.clojure/tools.logging "1.1.0"]]
9+
:profiles {:uberjar {:aot :all}
10+
:dev {:dependencies [[org.clojure/clojure "1.10.1"]]}}
11+
:plugins [[lein-ancient "0.6.15"]])

src/consul/agent.clj

+101
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
(ns consul.agent
2+
(:require [cheshire.core :as json]
3+
[clojure.core.async :refer [go-loop timeout <!]]
4+
[clojure.string :as string]
5+
[clojure.tools.logging :as log]
6+
[org.httpkit.client :as http]))
7+
8+
9+
(def ^:dynamic *consul-url* "http://127.0.0.1:8500/shit")
10+
(def ^:private alive (atom #{}))
11+
12+
13+
(defn- default-callback [{:keys [status] :as response}]
14+
(when (or
15+
(nil? status)
16+
(>= status 400))
17+
(log/warn "Error requesting consul agent: " response)))
18+
19+
20+
(defn- http-get [path]
21+
(log/debug "GET" (str *consul-url* "/v1/agent" path))
22+
(http/request {:url (str *consul-url* "/v1/agent" path)}))
23+
24+
25+
(defn- http-put [path body callback]
26+
(log/debug "PUT" (str *consul-url* "/v1/agent" path) "\n" (json/encode body {:pretty true}))
27+
(http/request {:method :put
28+
:url (str *consul-url* "/v1/agent" path)
29+
:body (if body (json/encode body) "")}
30+
(or callback default-callback)))
31+
32+
33+
(defn service-list []
34+
(http-get "/services"))
35+
36+
37+
(defn service-details [service-id]
38+
(http-get (str "/service/" service-id)))
39+
40+
41+
(defn service-register [request & [callback]]
42+
(http-put "/service/register" request callback))
43+
44+
45+
(defn service-deregister [service-id & [callback]]
46+
(http-put (str "/service/deregister/" service-id) nil callback))
47+
48+
49+
(defn check-update [check-id status & [callback]]
50+
{:pre [(#{:passing :warning :critical} status)]}
51+
(http-put (str "/check/update/" check-id) {:status status} callback))
52+
53+
54+
(defn check-update-with-register
55+
"check update with registration if not registered yet"
56+
[check-id check-status register-request]
57+
(let [consul-url *consul-url*]
58+
(check-update check-id check-status
59+
(fn [{:keys [status body] :as response}]
60+
(log/debug "-->" status body)
61+
(if (and status
62+
(>= status 400)
63+
(string/includes? body (format "\"%s\"" check-id))
64+
(string/includes? body "TTL"))
65+
(binding [*consul-url* consul-url]
66+
(service-register register-request
67+
(fn [{:keys [status] :as response}]
68+
(if (= status 200)
69+
(binding [*consul-url* consul-url]
70+
(check-update check-id check-status))
71+
(default-callback response)))))
72+
(default-callback response))))))
73+
74+
75+
(defn heartbeat
76+
"single heartbeat"
77+
[{:keys [id name address port ttl deregister-critical-service-after]}]
78+
(let [check-id (str id ":ttl-check")]
79+
(check-update-with-register check-id :passing
80+
{:id id
81+
:name (or name id)
82+
:address address
83+
:port port
84+
:check {:CheckId check-id
85+
:TTL ttl
86+
:DeregisterCriticalServiceAfter deregister-critical-service-after}})))
87+
88+
89+
(defn start-heartbeat [{:keys [id interval-ms] :as params}]
90+
(service-deregister id)
91+
(swap! alive #(conj % [*consul-url* id]))
92+
(go-loop []
93+
(when (@alive [*consul-url* id])
94+
(heartbeat params)
95+
(<! (timeout interval-ms))
96+
(recur))))
97+
98+
99+
(defn stop-heartbeat [service-id]
100+
(swap! alive #(disj % [*consul-url* service-id]))
101+
(service-deregister service-id))

test/consul/agent_test.clj

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
(ns consul.agent-test
2+
(:require [clojure.test :refer :all]
3+
[consul.agent :as agent]
4+
[clojure.core.async :refer [timeout <!!]]))
5+
6+
7+
(deftest test-1-start-stop-heartbeat
8+
(testing "start-stop-heartbeat"
9+
(binding [agent/*consul-url* "http://127.0.0.1:8500"]
10+
11+
(agent/start-heartbeat {:id "my-service"
12+
:address "127.0.0.1"
13+
:port 8080
14+
:ttl "4s"
15+
:deregister-critical-service-after "1m"
16+
:interval-ms 2000})
17+
18+
(<!! (timeout 500))
19+
20+
(let [{:keys [status body]} @(agent/service-details "my-service")]
21+
(println body)
22+
(is (= status 200)))
23+
24+
(<!! (timeout 8500))
25+
26+
(let [{:keys [status body]} @(agent/service-details "my-service")]
27+
(println body)
28+
(is (= status 200)))
29+
30+
(agent/stop-heartbeat "my-service")
31+
32+
(<!! (timeout 500))
33+
34+
(let [{:keys [status body]} @(agent/service-details "my-service")]
35+
(println body)
36+
(is (= status 404))))))

0 commit comments

Comments
 (0)