├── doc ├── intro.md ├── js │ └── page_effects.js ├── index.html ├── css │ └── default.css └── carmine-sentinel.core.html ├── .gitignore ├── project.clj ├── CHANGELOG.md ├── Makefile ├── test └── carmine_sentinel │ └── core_test.clj ├── README.md ├── raw-sentinel.conf ├── LICENSE ├── src └── carmine_sentinel │ └── core.clj └── raw-redis.conf /doc/intro.md: -------------------------------------------------------------------------------- 1 | # Introduction to carmine-sentinel 2 | 3 | TODO: write [great documentation](http://jacobian.org/writing/what-to-write/) 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /classes 3 | /checkouts 4 | pom.xml 5 | pom.xml.asc 6 | *.jar 7 | *.class 8 | /.lein-* 9 | /.nrepl-port 10 | .hgignore 11 | .hg/ 12 | -------------------------------------------------------------------------------- /project.clj: -------------------------------------------------------------------------------- 1 | (defproject net.fnil/carmine-sentinel "1.0.0" 2 | :description "A Clojure library designed to connect redis by sentinel, make carmine to support sentinel." 3 | :url "https://github.com/killme2008/carmine-sentinel" 4 | :license {:name "Eclipse Public License" 5 | :url "http://www.eclipse.org/legal/epl-v10.html"} 6 | :dependencies [[org.clojure/clojure "1.10.0"] 7 | [com.taoensso/carmine "2.19.1"]] 8 | :plugins [[codox "0.6.8"]] 9 | :warn-on-reflection true) 10 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | ## [0.3.0] - 2019-02-27 4 | ### Compatibility Breaking Change 5 | - Change defined sentinel commands format to be compatible with `carmine` version post `2.14`: will only work for `2.15`+ ! 6 | 7 | ### Fixed 8 | - carmine server connection settings are no longer lost: password connection works! 9 | 10 | ### Changed 11 | - Expanded hard to read use of macros 12 | - Change variable names from acronyms to full words from acronyms 13 | - `try-resolve-master-spec` now accepts `server-conn` argument 14 | - `get-sentinel-redis-spec` now checks arguments using `:pre` not `if ... throw` 15 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | THIS_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) 2 | 3 | sentinel.conf: 4 | cp raw-sentinel.conf $@ 5 | echo 'requirepass "foobar"' >> $@ 6 | echo 'daemonize yes' >> $@ 7 | 8 | sentinel.%.conf: sentinel.conf 9 | cp sentinel.conf sentinel.$*.conf 10 | echo pidfile $(THIS_DIR)/sentinel.$*.pid >> $@ 11 | 12 | sentinel.%: sentinel.%.conf 13 | redis-sentinel sentinel.$*.conf --port 500$* & 14 | 15 | sentinels: sentinel.conf 16 | $(MAKE) sentinel.0 17 | $(MAKE) sentinel.1 18 | $(MAKE) sentinel.2 19 | 20 | redis.conf: 21 | cp raw-redis.conf $@ 22 | echo 'requirepass "foobar"' >> $@ 23 | echo 'daemonize yes' >> $@ 24 | echo pidfile $(THIS_DIR)/redis.pid >> $@ 25 | 26 | redis: redis.conf 27 | redis-server redis.conf & 28 | 29 | test_setup: sentinels redis 30 | 31 | test: test_setup 32 | lein test 33 | $(MAKE) stop 34 | $(MAKE) clean 35 | 36 | clean: 37 | rm sentinel*.conf redis*.conf 38 | 39 | stop: 40 | kill `cat sentinel.*.pid` 41 | kill `cat redis.pid` 42 | 43 | .PRECIOUS: sentinel.%.conf redis.conf 44 | 45 | .PHONY: clean stop test 46 | -------------------------------------------------------------------------------- /doc/js/page_effects.js: -------------------------------------------------------------------------------- 1 | function visibleInParent(element) { 2 | var position = $(element).position().top 3 | return position > -50 && position < ($(element).offsetParent().height() - 50) 4 | } 5 | 6 | function hasFragment(link, fragment) { 7 | return $(link).attr("href").indexOf("#" + fragment) != -1 8 | } 9 | 10 | function findLinkByFragment(elements, fragment) { 11 | return $(elements).filter(function(i, e) { return hasFragment(e, fragment)}).first() 12 | } 13 | 14 | function setCurrentVarLink() { 15 | $('#vars li').removeClass('current') 16 | $('.public'). 17 | filter(function(index) { return visibleInParent(this) }). 18 | each(function(index, element) { 19 | findLinkByFragment("#vars a", element.id). 20 | parent(). 21 | addClass('current') 22 | }) 23 | } 24 | 25 | var hasStorage = (function() { try { return localStorage.getItem } catch(e) {} }()) 26 | 27 | function scrollPositionId(element) { 28 | var directory = window.location.href.replace(/[^\/]+\.html$/, '') 29 | return 'scroll::' + $(element).attr('id') + '::' + directory 30 | } 31 | 32 | function storeScrollPosition(element) { 33 | if (!hasStorage) return; 34 | localStorage.setItem(scrollPositionId(element) + "::x", $(element).scrollLeft()) 35 | localStorage.setItem(scrollPositionId(element) + "::y", $(element).scrollTop()) 36 | } 37 | 38 | function recallScrollPosition(element) { 39 | if (!hasStorage) return; 40 | $(element).scrollLeft(localStorage.getItem(scrollPositionId(element) + "::x")) 41 | $(element).scrollTop(localStorage.getItem(scrollPositionId(element) + "::y")) 42 | } 43 | 44 | function persistScrollPosition(element) { 45 | recallScrollPosition(element) 46 | $(element).scroll(function() { storeScrollPosition(element) }) 47 | } 48 | 49 | function sidebarContentWidth(element) { 50 | var widths = $(element).find('span').map(function() { return $(this).width() }) 51 | return Math.max.apply(Math, widths) 52 | } 53 | 54 | function resizeNamespaces() { 55 | var width = sidebarContentWidth('#namespaces') + 40 56 | $('#namespaces').css('width', width) 57 | $('#vars, .namespace-index').css('left', width + 1) 58 | $('.namespace-docs').css('left', $('#vars').width() + width + 2) 59 | } 60 | 61 | $(window).ready(resizeNamespaces) 62 | $(window).ready(setCurrentVarLink) 63 | $(window).ready(function() { persistScrollPosition('#namespaces')}) 64 | $(window).ready(function() { 65 | $('#content').scroll(setCurrentVarLink) 66 | $(window).resize(setCurrentVarLink) 67 | }) 68 | -------------------------------------------------------------------------------- /doc/index.html: -------------------------------------------------------------------------------- 1 | 2 |
(add-sentinel-groups! conf)Add sentinel groups,it will be merged into current conf:
3 | {:group-name {:specs [{ :host host
4 | :port port
5 | :password password
6 | :timeout-ms timeout-ms },
7 | ...other sentinel instances...]
8 | :pool {<opts>}}}
9 | The conf is a map of sentinel group to connection spec.(get-sentinel-redis-spec sg master-name {:keys [prefer-slave? slaves-balancer], :or {prefer-slave? false, slaves-balancer first}, :as opts})Get redis spec by sentinel-group and master name. 10 | If it is not resolved, it will query from sentinel and 11 | cache the result in memory. 12 | Recommend to call this function at your app startup to reduce 13 | resolving cost.
(notify-event-listeners event)(register-listener! listener)Register listener for switching master.
14 | The listener will be called with an event:
15 | {:event "+switch-master"
16 | :old {:host old-master-ip
17 | :port old-master-port
18 | :new {:host new-master-ip
19 | :port new-master-port}}}
20 | (remove-last-resolved-spec! sg master-name)Remove last resolved master spec by sentinel group and master name. 21 |
(remove-sentinel-group! group-name)Remove a sentinel group configuration by name. 22 |
(sentinel-get-master-addr-by-name name)SENTINEL get-master-addr-by-name name 23 | 24 | get master address by master name.. 25 | 26 | Available since: . 27 | 28 | Time complexity: O(1)
(sentinel-sentinels name)SENTINEL sentinels name 29 | 30 | get sentinel instances by mater name.. 31 | 32 | Available since: . 33 | 34 | Time complexity: O(1)
(sentinel-slaves name)SENTINEL slaves name 35 | 36 | get slaves address by master name.. 37 | 38 | Available since: . 39 | 40 | Time complexity: O(1)
(set-sentinel-groups! conf)Configure sentinel groups, it will replace current conf:
41 | {:group-name {:specs [{ :host host
42 | :port port
43 | :password password
44 | :timeout-ms timeout-ms },
45 | ...other sentinel instances...]
46 | :pool {<opts>}}}
47 | The conf is a map of sentinel group to connection spec.(sync-on sg mn & body)(unregister-listener! listener)Remove the listener for switching master. 48 |
(update-conn-spec conn)Cast a carmine-sentinel conn to carmine raw conn spec. 49 | It will resolve master from sentinel first time,then cache the result in 50 | memory for reusing.
(wcar conn :as-pipeline & body)(wcar conn & body)It's the same as taoensso.carmine/wcar, but supports 51 | :master-name "mymaster" 52 | :sentinel-group :default 53 | in conn for redis sentinel cluster. 54 |