initial import
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
This commit is contained in:
parent
cbe64b813f
commit
74f42ab78d
46
go.mod
Normal file
46
go.mod
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
module go.unistack.org/micro-register-redis/v3
|
||||||
|
|
||||||
|
go 1.23.4
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/alicebob/miniredis/v2 v2.34.0
|
||||||
|
github.com/docker/docker v27.4.1+incompatible
|
||||||
|
github.com/redis/go-redis/extra/rediscmd/v9 v9.7.0
|
||||||
|
github.com/redis/go-redis/v9 v9.7.0
|
||||||
|
go.unistack.org/micro/v3 v3.11.35
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302 // indirect
|
||||||
|
github.com/ash3in/uuidv8 v1.2.0 // indirect
|
||||||
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
|
github.com/containerd/log v0.1.0 // indirect
|
||||||
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||||
|
github.com/distribution/reference v0.6.0 // indirect
|
||||||
|
github.com/docker/distribution v2.8.3+incompatible // indirect
|
||||||
|
github.com/docker/go-connections v0.5.0 // indirect
|
||||||
|
github.com/docker/go-metrics v0.0.1 // indirect
|
||||||
|
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 // indirect
|
||||||
|
github.com/golang/protobuf v1.5.4 // indirect
|
||||||
|
github.com/google/go-cmp v0.6.0 // indirect
|
||||||
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
|
github.com/gorilla/mux v1.8.1 // indirect
|
||||||
|
github.com/kr/pretty v0.3.1 // indirect
|
||||||
|
github.com/matoous/go-nanoid v1.5.1 // indirect
|
||||||
|
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
||||||
|
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||||
|
github.com/opencontainers/image-spec v1.1.0 // indirect
|
||||||
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
|
github.com/prometheus/client_golang v1.1.0 // indirect
|
||||||
|
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 // indirect
|
||||||
|
github.com/prometheus/common v0.6.0 // indirect
|
||||||
|
github.com/prometheus/procfs v0.0.3 // indirect
|
||||||
|
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||||
|
github.com/yuin/gopher-lua v1.1.1 // indirect
|
||||||
|
go.unistack.org/micro-proto/v3 v3.4.1 // indirect
|
||||||
|
golang.org/x/sys v0.28.0 // indirect
|
||||||
|
google.golang.org/protobuf v1.36.1 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
gotest.tools/v3 v3.5.1 // indirect
|
||||||
|
)
|
151
go.sum
Normal file
151
go.sum
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU=
|
||||||
|
github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU=
|
||||||
|
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
|
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
|
github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302 h1:uvdUDbHQHO85qeSydJtItA4T55Pw6BtAejd0APRJOCE=
|
||||||
|
github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
|
||||||
|
github.com/alicebob/miniredis/v2 v2.34.0 h1:mBFWMaJSNL9RwdGRyEDoAAv8OQc5UlEhLDQggTglU/0=
|
||||||
|
github.com/alicebob/miniredis/v2 v2.34.0/go.mod h1:kWShP4b58T1CW0Y5dViCd5ztzrDqRWqM3nksiyXk5s8=
|
||||||
|
github.com/ash3in/uuidv8 v1.2.0 h1:2oogGdtCPwaVtyvPPGin4TfZLtOGE5F+W++E880G6SI=
|
||||||
|
github.com/ash3in/uuidv8 v1.2.0/go.mod h1:BnU0wJBxnzdEKmVg4xckBkD+VZuecTFTUP3M0dWgyY4=
|
||||||
|
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||||
|
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||||
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
|
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
|
||||||
|
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
|
||||||
|
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
|
||||||
|
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
||||||
|
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
||||||
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||||
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||||
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||||
|
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
|
||||||
|
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||||
|
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
|
||||||
|
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||||
|
github.com/docker/docker v27.4.1+incompatible h1:ZJvcY7gfwHn1JF48PfbyXg7Jyt9ZCWDW+GGXOIxEwp4=
|
||||||
|
github.com/docker/docker v27.4.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||||
|
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
|
||||||
|
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
|
||||||
|
github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8=
|
||||||
|
github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw=
|
||||||
|
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 h1:UhxFibDNY/bfvqU5CAUmr9zpesgbU6SWc8/B4mflAE4=
|
||||||
|
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
|
||||||
|
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
|
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||||
|
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||||
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
|
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||||
|
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||||
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
||||||
|
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
||||||
|
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||||
|
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
|
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||||
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
|
github.com/matoous/go-nanoid v1.5.1 h1:aCjdvTyO9LLnTIi0fgdXhOPPvOHjpXN6Ik9DaNjIct4=
|
||||||
|
github.com/matoous/go-nanoid v1.5.1/go.mod h1:zyD2a71IubI24efhpvkJz+ZwfwagzgSO6UNiFsZKN7U=
|
||||||
|
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||||
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
|
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
|
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||||
|
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||||
|
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||||
|
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
|
||||||
|
github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
|
||||||
|
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||||
|
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||||
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||||
|
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||||
|
github.com/prometheus/client_golang v1.1.0 h1:BQ53HtBmfOitExawJ6LokA4x8ov/z0SYYb0+HxJfRI8=
|
||||||
|
github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
|
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||||
|
github.com/prometheus/common v0.6.0 h1:kRhiuYSXR3+uv2IbVbZhUxK5zVD/2pp3Gd2PpvPkpEo=
|
||||||
|
github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
|
||||||
|
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
|
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||||
|
github.com/prometheus/procfs v0.0.3 h1:CTwfnzjQ+8dS6MhHHu4YswVAD99sL2wjPqP+VkURmKE=
|
||||||
|
github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
|
||||||
|
github.com/redis/go-redis/extra/rediscmd/v9 v9.7.0 h1:BIx9TNZH/Jsr4l1i7VVxnV0JPiwYj8qyrHyuL0fGZrk=
|
||||||
|
github.com/redis/go-redis/extra/rediscmd/v9 v9.7.0/go.mod h1:eTg/YQtGYAZD5r3DlGlJptJ45AHA+/G+2NPn30PKzik=
|
||||||
|
github.com/redis/go-redis/v9 v9.7.0 h1:HhLSs+B6O021gwzl+locl0zEDnyNkxMtf/Z3NNBMa9E=
|
||||||
|
github.com/redis/go-redis/v9 v9.7.0/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw=
|
||||||
|
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||||
|
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||||
|
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||||
|
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||||
|
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||||
|
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||||
|
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
|
github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M=
|
||||||
|
github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw=
|
||||||
|
go.unistack.org/micro-proto/v3 v3.4.1 h1:UTjLSRz2YZuaHk9iSlVqqsA50JQNAEK2ZFboGqtEa9Q=
|
||||||
|
go.unistack.org/micro-proto/v3 v3.4.1/go.mod h1:okx/cnOhzuCX0ggl/vToatbCupi0O44diiiLLsZ93Zo=
|
||||||
|
go.unistack.org/micro/v3 v3.11.34 h1:kwAo09FLcWrAwDSWSnyegQGTJT5oz4cpb/LN7uw5imQ=
|
||||||
|
go.unistack.org/micro/v3 v3.11.34/go.mod h1:POGU5hstnAT9LH70m8FalyQSNi2GfIew71K75JenIZk=
|
||||||
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
|
||||||
|
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk=
|
||||||
|
google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||||
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
|
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
|
||||||
|
gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
|
30
options.go
Normal file
30
options.go
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package redis
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
goredis "github.com/redis/go-redis/v9"
|
||||||
|
"go.unistack.org/micro/v3/register"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
DefaultSeparator = "/"
|
||||||
|
DefaultOptions = &goredis.UniversalOptions{
|
||||||
|
Username: "",
|
||||||
|
Password: "", // no password set
|
||||||
|
DB: 0, // use default DB
|
||||||
|
MaxRetries: 2,
|
||||||
|
MaxRetryBackoff: 256 * time.Millisecond,
|
||||||
|
DialTimeout: 1 * time.Second,
|
||||||
|
ReadTimeout: 1 * time.Second,
|
||||||
|
WriteTimeout: 1 * time.Second,
|
||||||
|
PoolTimeout: 1 * time.Second,
|
||||||
|
MinIdleConns: 10,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
type configKey struct{}
|
||||||
|
|
||||||
|
func Config(c *goredis.UniversalOptions) register.Option {
|
||||||
|
return register.SetOption(configKey{}, c)
|
||||||
|
}
|
393
redis.go
Normal file
393
redis.go
Normal file
@ -0,0 +1,393 @@
|
|||||||
|
package redis
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/docker/docker/registry"
|
||||||
|
goredis "github.com/redis/go-redis/v9"
|
||||||
|
"go.unistack.org/micro/v3/codec"
|
||||||
|
"go.unistack.org/micro/v3/register"
|
||||||
|
"go.unistack.org/micro/v3/util/id"
|
||||||
|
pool "go.unistack.org/micro/v3/util/xpool"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
separator = "/"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
_ register.Register = (*Redis)(nil)
|
||||||
|
_ register.Watcher = (*Watcher)(nil)
|
||||||
|
)
|
||||||
|
|
||||||
|
type Redis struct {
|
||||||
|
cli goredis.UniversalClient
|
||||||
|
opts register.Options
|
||||||
|
watchers map[string]*Watcher
|
||||||
|
services map[string][]*registry.Service
|
||||||
|
db int
|
||||||
|
pool *pool.StringsPool
|
||||||
|
sync.RWMutex
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRegister returns an initialized in-memory register
|
||||||
|
func NewRegister(opts ...register.Option) *Redis {
|
||||||
|
r := &Redis{
|
||||||
|
opts: register.NewOptions(opts...),
|
||||||
|
watchers: make(map[string]*Watcher),
|
||||||
|
services: make(map[string][]*registry.Service),
|
||||||
|
}
|
||||||
|
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Redis) Connect(ctx context.Context) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Redis) Disconnect(ctx context.Context) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Redis) Init(opts ...register.Option) error {
|
||||||
|
for _, o := range opts {
|
||||||
|
o(&r.opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
redisOptions := DefaultOptions
|
||||||
|
|
||||||
|
if r.opts.Context != nil {
|
||||||
|
if c, ok := r.opts.Context.Value(configKey{}).(*goredis.UniversalOptions); ok && c != nil {
|
||||||
|
redisOptions = c
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(r.opts.Addrs) > 0 {
|
||||||
|
redisOptions.Addrs = r.opts.Addrs
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.opts.TLSConfig != nil {
|
||||||
|
redisOptions.TLSConfig = r.opts.TLSConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
c := goredis.NewUniversalClient(redisOptions)
|
||||||
|
setTracing(c, r.opts.Tracer)
|
||||||
|
r.pool = pool.NewStringsPool(50)
|
||||||
|
r.db = redisOptions.DB
|
||||||
|
r.cli = c
|
||||||
|
r.statsMeter()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Redis) Options() register.Options {
|
||||||
|
return r.opts
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Redis) Register(ctx context.Context, s *register.Service, opts ...register.RegisterOption) error {
|
||||||
|
options := register.NewRegisterOptions(opts...)
|
||||||
|
b := r.pool.Get()
|
||||||
|
defer func() {
|
||||||
|
b.Reset()
|
||||||
|
r.pool.Put(b)
|
||||||
|
}()
|
||||||
|
|
||||||
|
for _, n := range s.Nodes {
|
||||||
|
buf, err := r.opts.Codec.Marshal(n)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = r.cli.Set(ctx, r.getKey(b, options.Namespace, s.Name, s.Version, n.ID), buf, options.TTL).Err(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
evt := ®ister.Event{
|
||||||
|
Timestamp: time.Now(),
|
||||||
|
Type: register.EventCreate,
|
||||||
|
Service: s,
|
||||||
|
ID: id.MustNew(),
|
||||||
|
}
|
||||||
|
|
||||||
|
buf, err := r.opts.Codec.Marshal(evt)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = r.cli.Publish(ctx, options.Namespace+separator+"events", buf).Err(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Redis) Deregister(ctx context.Context, s *register.Service, opts ...register.DeregisterOption) error {
|
||||||
|
options := register.NewDeregisterOptions(opts...)
|
||||||
|
b := r.pool.Get()
|
||||||
|
defer func() {
|
||||||
|
b.Reset()
|
||||||
|
r.pool.Put(b)
|
||||||
|
}()
|
||||||
|
var err error
|
||||||
|
for _, n := range s.Nodes {
|
||||||
|
if err = r.cli.Del(ctx, r.getKey(b, options.Namespace, s.Name, s.Version, n.ID)).Err(); err != nil && err != goredis.Nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
evt := ®ister.Event{
|
||||||
|
Timestamp: time.Now(),
|
||||||
|
Type: register.EventDelete,
|
||||||
|
Service: s,
|
||||||
|
ID: id.MustNew(),
|
||||||
|
}
|
||||||
|
|
||||||
|
buf, err := r.opts.Codec.Marshal(evt)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = r.cli.Publish(ctx, options.Namespace+separator+"events", buf).Err(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Redis) LookupService(ctx context.Context, name string, opts ...register.LookupOption) ([]*register.Service, error) {
|
||||||
|
options := register.NewLookupOptions(opts...)
|
||||||
|
b := r.pool.Get()
|
||||||
|
defer func() {
|
||||||
|
b.Reset()
|
||||||
|
r.pool.Put(b)
|
||||||
|
}()
|
||||||
|
|
||||||
|
keys, err := r.cli.Keys(ctx, r.getKey(b, options.Namespace, name, "*", "")).Result()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(keys) == 0 {
|
||||||
|
return nil, register.ErrNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
vals, err := r.cli.MGet(ctx, keys...).Result()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(vals) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
servicesMap := make(map[string]*register.Service)
|
||||||
|
for idx := range keys {
|
||||||
|
eidx := strings.LastIndex(keys[idx], separator)
|
||||||
|
sidx := strings.LastIndex(keys[idx][:eidx], separator)
|
||||||
|
if string(keys[idx][sidx]) == separator {
|
||||||
|
sidx++
|
||||||
|
}
|
||||||
|
name := keys[idx][sidx:eidx]
|
||||||
|
svc, ok := servicesMap[name]
|
||||||
|
if !ok {
|
||||||
|
p := strings.Split(name, "-")
|
||||||
|
svc = ®ister.Service{Name: p[0], Version: p[1]}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch v := vals[idx].(type) {
|
||||||
|
case string:
|
||||||
|
node := ®ister.Node{}
|
||||||
|
if err = r.opts.Codec.Unmarshal([]byte(v), node); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
svc.Nodes = append(svc.Nodes, node)
|
||||||
|
case []byte:
|
||||||
|
node := ®ister.Node{}
|
||||||
|
if err = r.opts.Codec.Unmarshal(v, node); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
svc.Nodes = append(svc.Nodes, node)
|
||||||
|
}
|
||||||
|
|
||||||
|
servicesMap[name] = svc
|
||||||
|
}
|
||||||
|
|
||||||
|
svcs := make([]*register.Service, 0, len(servicesMap))
|
||||||
|
for _, svc := range servicesMap {
|
||||||
|
svcs = append(svcs, svc)
|
||||||
|
}
|
||||||
|
|
||||||
|
return svcs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Redis) ListServices(ctx context.Context, opts ...register.ListOption) ([]*register.Service, error) {
|
||||||
|
options := register.NewListOptions(opts...)
|
||||||
|
b := r.pool.Get()
|
||||||
|
defer func() {
|
||||||
|
b.Reset()
|
||||||
|
r.pool.Put(b)
|
||||||
|
}()
|
||||||
|
|
||||||
|
// TODO: replace Keys with Scan
|
||||||
|
keys, err := r.cli.Keys(ctx, r.getKey(b, options.Namespace, "*", "", "")).Result()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(keys) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
vals, err := r.cli.MGet(ctx, keys...).Result()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(vals) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
servicesMap := make(map[string]*register.Service)
|
||||||
|
for idx := range keys {
|
||||||
|
eidx := strings.LastIndex(keys[idx], separator)
|
||||||
|
sidx := strings.LastIndex(keys[idx][:eidx], separator)
|
||||||
|
if string(keys[idx][sidx]) == separator {
|
||||||
|
sidx++
|
||||||
|
}
|
||||||
|
name := keys[idx][sidx:eidx]
|
||||||
|
svc, ok := servicesMap[name]
|
||||||
|
if !ok {
|
||||||
|
p := strings.Split(name, "-")
|
||||||
|
svc = ®ister.Service{Name: p[0], Version: p[1]}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch v := vals[idx].(type) {
|
||||||
|
case string:
|
||||||
|
node := ®ister.Node{}
|
||||||
|
if err = r.opts.Codec.Unmarshal([]byte(v), node); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
svc.Nodes = append(svc.Nodes, node)
|
||||||
|
case []byte:
|
||||||
|
node := ®ister.Node{}
|
||||||
|
if err = r.opts.Codec.Unmarshal(v, node); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
svc.Nodes = append(svc.Nodes, node)
|
||||||
|
}
|
||||||
|
|
||||||
|
servicesMap[name] = svc
|
||||||
|
}
|
||||||
|
|
||||||
|
svcs := make([]*register.Service, 0, len(servicesMap))
|
||||||
|
for _, svc := range servicesMap {
|
||||||
|
svcs = append(svcs, svc)
|
||||||
|
}
|
||||||
|
|
||||||
|
return svcs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Redis) Watch(ctx context.Context, opts ...register.WatchOption) (register.Watcher, error) {
|
||||||
|
id, err := id.New()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
wo := register.NewWatchOptions(opts...)
|
||||||
|
|
||||||
|
w := &Watcher{
|
||||||
|
exit: make(chan bool),
|
||||||
|
res: make(chan *register.Result),
|
||||||
|
id: id,
|
||||||
|
wo: wo,
|
||||||
|
sub: r.cli.Subscribe(ctx, wo.Namespace+separator+"events"),
|
||||||
|
codec: r.opts.Codec,
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Lock()
|
||||||
|
r.watchers[w.id] = w
|
||||||
|
r.Unlock()
|
||||||
|
|
||||||
|
return w, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Redis) Name() string {
|
||||||
|
return r.opts.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Redis) String() string {
|
||||||
|
return "redis"
|
||||||
|
}
|
||||||
|
|
||||||
|
type Watcher struct {
|
||||||
|
res chan *register.Result
|
||||||
|
exit chan bool
|
||||||
|
wo register.WatchOptions
|
||||||
|
id string
|
||||||
|
codec codec.Codec
|
||||||
|
sub *goredis.PubSub
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Watcher) Next() (*register.Result, error) {
|
||||||
|
var err error
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case msg := <-w.sub.Channel():
|
||||||
|
evt := ®ister.Event{}
|
||||||
|
if err = w.codec.Unmarshal([]byte(msg.Payload), evt); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if evt.Service == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(w.wo.Service) > 0 && w.wo.Service != evt.Service.Name {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace := register.DefaultNamespace
|
||||||
|
if evt.Service.Namespace != "" {
|
||||||
|
namespace = evt.Service.Namespace
|
||||||
|
}
|
||||||
|
|
||||||
|
// only send the event if watching the wildcard or this specific domain
|
||||||
|
if w.wo.Namespace == register.WildcardNamespace || w.wo.Namespace == namespace {
|
||||||
|
return ®ister.Result{Service: evt.Service, Action: evt.Type}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
case <-w.exit:
|
||||||
|
return nil, register.ErrWatcherStopped
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Watcher) Stop() {
|
||||||
|
select {
|
||||||
|
case <-w.exit:
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
w.sub.Close()
|
||||||
|
close(w.exit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Redis) getKey(b *strings.Builder, opNamespace string, name string, version string, nid string) string {
|
||||||
|
if opNamespace != "" {
|
||||||
|
b.WriteString(opNamespace)
|
||||||
|
b.WriteString(separator)
|
||||||
|
}
|
||||||
|
|
||||||
|
if name != "" {
|
||||||
|
b.WriteString(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if version != "" {
|
||||||
|
b.WriteString("-")
|
||||||
|
b.WriteString(version)
|
||||||
|
}
|
||||||
|
|
||||||
|
if nid != "" {
|
||||||
|
b.WriteString(separator)
|
||||||
|
b.WriteString(nid)
|
||||||
|
}
|
||||||
|
return b.String()
|
||||||
|
}
|
188
redis_test.go
Normal file
188
redis_test.go
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
package redis
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/alicebob/miniredis/v2"
|
||||||
|
"go.unistack.org/micro/v3/register"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRegister(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
s := miniredis.RunT(t)
|
||||||
|
|
||||||
|
r := NewRegister(register.Addrs(s.Addr()))
|
||||||
|
if err := r.Init(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := r.Connect(ctx); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if err := r.Disconnect(ctx); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
nodes := []*register.Node{
|
||||||
|
{ID: "1", Address: "11.22.33.44"},
|
||||||
|
}
|
||||||
|
svc := ®ister.Service{Name: "test", Version: "1.2.0", Nodes: nodes}
|
||||||
|
if err := r.Register(ctx, svc, register.RegisterTTL(100*time.Millisecond)); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
svcs, err := r.ListServices(ctx)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if len(svcs) == 0 {
|
||||||
|
t.Fatalf("no services registered")
|
||||||
|
}
|
||||||
|
if svcs[0].Name != "test" || svcs[0].Version != "1.2.0" {
|
||||||
|
t.Fatalf("invalid service %#+v", svcs[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
svcs, err = r.LookupService(ctx, "test")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if len(svcs) == 0 {
|
||||||
|
t.Fatalf("no services registered")
|
||||||
|
}
|
||||||
|
if svcs[0].Name != "test" || svcs[0].Version != "1.2.0" {
|
||||||
|
t.Fatalf("invalid service %d %#+v", len(svcs), svcs[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
s.FastForward(200 * time.Millisecond)
|
||||||
|
|
||||||
|
svcs, err = r.ListServices(ctx)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if len(svcs) != 0 {
|
||||||
|
t.Fatalf("have registered services")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeregister(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
s := miniredis.RunT(t)
|
||||||
|
|
||||||
|
r := NewRegister(register.Addrs(s.Addr()))
|
||||||
|
if err := r.Init(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := r.Connect(ctx); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if err := r.Disconnect(ctx); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
nodes := []*register.Node{
|
||||||
|
{ID: "1", Address: "11.22.33.44"},
|
||||||
|
}
|
||||||
|
svc := ®ister.Service{Name: "test", Version: "1.2.0", Nodes: nodes}
|
||||||
|
if err := r.Register(ctx, svc, register.RegisterTTL(500*time.Millisecond)); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
svcs, err := r.LookupService(ctx, "test")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if len(svcs) == 0 {
|
||||||
|
t.Fatalf("no services registered")
|
||||||
|
}
|
||||||
|
if svcs[0].Name != "test" || svcs[0].Version != "1.2.0" {
|
||||||
|
t.Fatalf("invalid service %#+v", svcs[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := r.Deregister(ctx, svc); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
svcs, err = r.LookupService(ctx, "test")
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("service not deregistered")
|
||||||
|
} else if len(svcs) != 0 {
|
||||||
|
t.Fatalf("service not deregistered")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWatch(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
s := miniredis.RunT(t)
|
||||||
|
|
||||||
|
r := NewRegister(register.Addrs(s.Addr()))
|
||||||
|
if err := r.Init(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := r.Connect(ctx); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if err := r.Disconnect(ctx); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
w, err := r.Watch(ctx)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer w.Stop()
|
||||||
|
|
||||||
|
cherr := make(chan error)
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
res, err := w.Next()
|
||||||
|
if err != nil {
|
||||||
|
cherr <- err
|
||||||
|
}
|
||||||
|
if res.Action != register.EventCreate {
|
||||||
|
cherr <- fmt.Errorf("invalid event %#+v", res)
|
||||||
|
}
|
||||||
|
if res.Service.Name != "test" {
|
||||||
|
cherr <- fmt.Errorf("invalid event %#+v", res)
|
||||||
|
}
|
||||||
|
if res.Service.Version != "1.2.0" {
|
||||||
|
cherr <- fmt.Errorf("invalid event %#+v", res)
|
||||||
|
}
|
||||||
|
if len(res.Service.Nodes) != 1 {
|
||||||
|
cherr <- fmt.Errorf("invalid event %#+v", res)
|
||||||
|
}
|
||||||
|
if res.Service.Nodes[0].ID != "1" {
|
||||||
|
cherr <- fmt.Errorf("invalid event %#+v", res)
|
||||||
|
}
|
||||||
|
if res.Service.Nodes[0].Address != "11.22.33.44" {
|
||||||
|
cherr <- fmt.Errorf("invalid event %#+v", res)
|
||||||
|
}
|
||||||
|
cherr <- nil
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
nodes := []*register.Node{
|
||||||
|
{ID: "1", Address: "11.22.33.44"},
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
svc := ®ister.Service{Name: "test", Version: "1.2.0", Nodes: nodes}
|
||||||
|
if err := r.Register(ctx, svc, register.RegisterTTL(500*time.Millisecond)); err != nil {
|
||||||
|
cherr <- err
|
||||||
|
}
|
||||||
|
time.Sleep(300 * time.Millisecond)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
if err = <-cherr; err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
49
stats.go
Normal file
49
stats.go
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
package redis
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
goredis "github.com/redis/go-redis/v9"
|
||||||
|
"go.unistack.org/micro/v3/meter"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
PoolHitsTotal = "pool_hits_total"
|
||||||
|
PoolMissesTotal = "pool_misses_total"
|
||||||
|
PoolTimeoutTotal = "pool_timeout_total"
|
||||||
|
PoolConnTotalCurrent = "pool_conn_total_current"
|
||||||
|
PoolConnIdleCurrent = "pool_conn_idle_current"
|
||||||
|
PoolConnStaleTotal = "pool_conn_stale_total"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Statser interface {
|
||||||
|
PoolStats() *goredis.PoolStats
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Redis) statsMeter() {
|
||||||
|
var st Statser
|
||||||
|
|
||||||
|
if r.cli != nil {
|
||||||
|
st = r.cli
|
||||||
|
} else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
ticker := time.NewTicker(meter.DefaultMeterStatsInterval)
|
||||||
|
defer ticker.Stop()
|
||||||
|
|
||||||
|
for range ticker.C {
|
||||||
|
if st == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
stats := st.PoolStats()
|
||||||
|
r.opts.Meter.Counter(PoolHitsTotal).Set(uint64(stats.Hits))
|
||||||
|
r.opts.Meter.Counter(PoolMissesTotal).Set(uint64(stats.Misses))
|
||||||
|
r.opts.Meter.Counter(PoolTimeoutTotal).Set(uint64(stats.Timeouts))
|
||||||
|
r.opts.Meter.Counter(PoolConnTotalCurrent).Set(uint64(stats.TotalConns))
|
||||||
|
r.opts.Meter.Counter(PoolConnIdleCurrent).Set(uint64(stats.IdleConns))
|
||||||
|
r.opts.Meter.Counter(PoolConnStaleTotal).Set(uint64(stats.StaleConns))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
128
tracer.go
Normal file
128
tracer.go
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
package redis
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
rediscmd "github.com/redis/go-redis/extra/rediscmd/v9"
|
||||||
|
goredis "github.com/redis/go-redis/v9"
|
||||||
|
"go.unistack.org/micro/v3/tracer"
|
||||||
|
)
|
||||||
|
|
||||||
|
func setTracing(rdb goredis.UniversalClient, tr tracer.Tracer, opts ...tracer.SpanOption) {
|
||||||
|
switch rdb := rdb.(type) {
|
||||||
|
case *goredis.Client:
|
||||||
|
opt := rdb.Options()
|
||||||
|
connString := formatDBConnString(opt.Network, opt.Addr)
|
||||||
|
rdb.AddHook(newTracingHook(connString, tr))
|
||||||
|
case *goredis.ClusterClient:
|
||||||
|
rdb.OnNewNode(func(rdb *goredis.Client) {
|
||||||
|
opt := rdb.Options()
|
||||||
|
connString := formatDBConnString(opt.Network, opt.Addr)
|
||||||
|
rdb.AddHook(newTracingHook(connString, tr))
|
||||||
|
})
|
||||||
|
case *goredis.Ring:
|
||||||
|
rdb.OnNewNode(func(rdb *goredis.Client) {
|
||||||
|
opt := rdb.Options()
|
||||||
|
connString := formatDBConnString(opt.Network, opt.Addr)
|
||||||
|
rdb.AddHook(newTracingHook(connString, tr))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type tracingHook struct {
|
||||||
|
tr tracer.Tracer
|
||||||
|
opts []tracer.SpanOption
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ goredis.Hook = (*tracingHook)(nil)
|
||||||
|
|
||||||
|
func newTracingHook(connString string, tr tracer.Tracer, opts ...tracer.SpanOption) *tracingHook {
|
||||||
|
opts = append(opts, tracer.WithSpanKind(tracer.SpanKindClient))
|
||||||
|
if connString != "" {
|
||||||
|
opts = append(opts, tracer.WithSpanLabels("db.connection_string", connString))
|
||||||
|
}
|
||||||
|
|
||||||
|
return &tracingHook{
|
||||||
|
tr: tr,
|
||||||
|
opts: opts,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *tracingHook) DialHook(hook goredis.DialHook) goredis.DialHook {
|
||||||
|
return func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||||
|
/*
|
||||||
|
_, span := h.tr.Start(ctx, "goredis.dial", h.opts...)
|
||||||
|
defer span.Finish()
|
||||||
|
*/
|
||||||
|
conn, err := hook(ctx, network, addr)
|
||||||
|
// recordError(span, err)
|
||||||
|
|
||||||
|
return conn, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *tracingHook) ProcessHook(hook goredis.ProcessHook) goredis.ProcessHook {
|
||||||
|
return func(ctx context.Context, cmd goredis.Cmder) error {
|
||||||
|
cmdString := rediscmd.CmdString(cmd)
|
||||||
|
var err error
|
||||||
|
|
||||||
|
switch cmdString {
|
||||||
|
case "cluster slots":
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
_, span := h.tr.Start(ctx, "sdk.database", append(h.opts, tracer.WithSpanLabels("db.statement", cmdString))...)
|
||||||
|
defer func() {
|
||||||
|
recordError(span, err)
|
||||||
|
span.Finish()
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
err = hook(ctx, cmd)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *tracingHook) ProcessPipelineHook(hook goredis.ProcessPipelineHook) goredis.ProcessPipelineHook {
|
||||||
|
return func(ctx context.Context, cmds []goredis.Cmder) error {
|
||||||
|
_, cmdsString := rediscmd.CmdsString(cmds)
|
||||||
|
|
||||||
|
opts := append(h.opts, tracer.WithSpanLabels(
|
||||||
|
"db.database.num_cmd", strconv.Itoa(len(cmds)),
|
||||||
|
"db.statement", cmdsString,
|
||||||
|
))
|
||||||
|
|
||||||
|
_, span := h.tr.Start(ctx, "sdk.database", opts...)
|
||||||
|
defer span.Finish()
|
||||||
|
|
||||||
|
err := hook(ctx, cmds)
|
||||||
|
recordError(span, err)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setSpanError(ctx context.Context, err error) {
|
||||||
|
if err == nil || err == goredis.Nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if sp, ok := tracer.SpanFromContext(ctx); !ok && sp != nil {
|
||||||
|
sp.SetStatus(tracer.SpanStatusError, err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func recordError(span tracer.Span, err error) {
|
||||||
|
if err != nil && err != goredis.Nil {
|
||||||
|
span.SetStatus(tracer.SpanStatusError, err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func formatDBConnString(network, addr string) string {
|
||||||
|
if network == "tcp" {
|
||||||
|
network = "redis"
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s://%s", network, addr)
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user