From aba00a3cfd1e3ec2e259d4d4dd0dd758248fe489 Mon Sep 17 00:00:00 2001 From: Joram Wilander Date: Thu, 4 Mar 2021 11:16:08 -0500 Subject: [PATCH] Update split SDK to 6.0.2 to fix sync bug (#17060) * Update split SDK to 6.0.2 to fix sync bug * Vendor and tidy --- go.mod | 5 +- go.sum | 33 +- .../go-client/v6/splitio/client/client.go | 10 +- .../go-client/v6/splitio/client/factory.go | 50 +-- .../v6/splitio/client/factory_tracker.go | 2 +- .../v6/splitio/client/input_validator.go | 6 +- .../go-client/v6/splitio/client/manager.go | 6 +- .../go-client/v6/splitio/conf/sdkconf.go | 8 +- .../splitio/go-client/v6/splitio/conf/util.go | 2 +- .../go-client/v6/splitio/engine/engine.go | 2 +- .../v6/splitio/engine/evaluator/evaluator.go | 8 +- .../v6/splitio/engine/grammar/condition.go | 6 +- .../engine/grammar/matchers/allofset.go | 2 +- .../engine/grammar/matchers/anyofset.go | 2 +- .../engine/grammar/matchers/equaltoset.go | 2 +- .../engine/grammar/matchers/insegment.go | 2 +- .../engine/grammar/matchers/matchers.go | 6 +- .../engine/grammar/matchers/partofset.go | 2 +- .../engine/grammar/matchers/whitelist.go | 2 +- .../v6/splitio/engine/grammar/split.go | 6 +- .../impressions_listener_wrapper.go | 2 +- .../splitio/go-client/v6/splitio/version.go | 2 +- .../splitio/go-split-commons/v2/push/dtos.go | 47 --- .../go-split-commons/v2/push/eventhandler.go | 89 ---- .../go-split-commons/v2/push/interface.go | 10 - .../go-split-commons/v2/push/keeper.go | 98 ----- .../go-split-commons/v2/push/parser.go | 64 --- .../go-split-commons/v2/push/processor.go | 112 ----- .../go-split-commons/v2/push/pushmanager.go | 370 ---------------- .../go-split-commons/v2/push/segment.go | 76 ---- .../splitio/go-split-commons/v2/push/split.go | 77 ---- .../v2/service/api/sse/client.go | 127 ------ .../v2/synchronizer/interface.go | 12 - .../v2/synchronizer/manager.go | 184 -------- .../synchronizer/worker/segment/interface.go | 8 - .../v2/synchronizer/worker/split/interface.go | 6 - .../go-split-commons/{v2 => v3}/LICENSE | 0 .../go-split-commons/{v2 => v3}/conf/conf.go | 0 .../{v2 => v3}/conf/defaults.go | 0 .../go-split-commons/{v2 => v3}/dtos/event.go | 0 .../go-split-commons/{v2 => v3}/dtos/http.go | 0 .../{v2 => v3}/dtos/impression.go | 0 .../{v2 => v3}/dtos/metadata.go | 0 .../{v2 => v3}/dtos/metrics.go | 0 .../{v2 => v3}/dtos/notification.go | 2 + .../{v2 => v3}/dtos/segment.go | 0 .../go-split-commons/{v2 => v3}/dtos/split.go | 0 .../go-split-commons/{v2 => v3}/dtos/token.go | 0 .../{v2 => v3}/provisional/impcounter.go | 2 +- .../{v2 => v3}/provisional/imphasher.go | 4 +- .../{v2 => v3}/provisional/impmanager.go | 6 +- .../{v2 => v3}/provisional/impobserver.go | 4 +- .../go-split-commons/v3/push/borrowed.go | 13 + .../go-split-commons/v3/push/constants.go | 14 + .../go-split-commons/v3/push/manager.go | 237 +++++++++++ .../go-split-commons/v3/push/parser.go | 399 ++++++++++++++++++ .../go-split-commons/v3/push/processor.go | 107 +++++ .../go-split-commons/v3/push/segment.go | 82 ++++ .../splitio/go-split-commons/v3/push/split.go | 80 ++++ .../go-split-commons/v3/push/statustracker.go | 158 +++++++ .../{v2 => v3}/service/api/auth.go | 8 +- .../{v2 => v3}/service/api/client.go | 32 +- .../{v2 => v3}/service/api/http_fetchers.go | 23 +- .../{v2 => v3}/service/api/http_recorders.go | 6 +- .../v3/service/api/sse/client.go | 123 ++++++ .../{v2 => v3}/service/interfaces.go | 6 +- .../{v2 => v3}/service/local/splitFetcher.go | 9 +- .../{v2 => v3}/service/split.go | 8 +- .../{v2 => v3}/storage/interfaces.go | 4 +- .../{v2 => v3}/storage/metricWrapper.go | 2 +- .../{v2 => v3}/storage/mocks/event.go | 2 +- .../{v2 => v3}/storage/mocks/impression.go | 2 +- .../{v2 => v3}/storage/mocks/metric.go | 2 +- .../{v2 => v3}/storage/mocks/segment.go | 2 +- .../{v2 => v3}/storage/mocks/split.go | 4 +- .../{v2 => v3}/storage/mutexmap/metrics.go | 2 +- .../{v2 => v3}/storage/mutexmap/segments.go | 2 +- .../{v2 => v3}/storage/mutexmap/splits.go | 4 +- .../storage/mutexqueue/constants.go | 0 .../{v2 => v3}/storage/mutexqueue/events.go | 4 +- .../storage/mutexqueue/impressions.go | 4 +- .../{v2 => v3}/storage/redis/constants.go | 0 .../{v2 => v3}/storage/redis/events.go | 8 +- .../{v2 => v3}/storage/redis/impressions.go | 6 +- .../{v2 => v3}/storage/redis/metrics.go | 6 +- .../{v2 => v3}/storage/redis/miscstorage.go | 4 +- .../{v2 => v3}/storage/redis/redis.go | 8 +- .../{v2 => v3}/storage/redis/segments.go | 6 +- .../{v2 => v3}/storage/redis/splits.go | 8 +- .../v3/synchronizer/interface.go | 13 + .../{v2 => v3}/synchronizer/local.go | 30 +- .../v3/synchronizer/manager.go | 207 +++++++++ .../{v2 => v3}/synchronizer/synchronizer.go | 59 ++- .../synchronizer/worker/event/interface.go | 0 .../synchronizer/worker/event/single.go | 13 +- .../worker/impression/interface.go | 0 .../synchronizer/worker/impression/single.go | 15 +- .../worker/impressionscount/interface.go | 0 .../worker/impressionscount/single.go | 8 +- .../synchronizer/worker/metric/interface.go | 0 .../synchronizer/worker/metric/single.go | 6 +- .../synchronizer/worker/segment/interface.go | 9 + .../synchronizer/worker/segment/segment.go | 41 +- .../v3/synchronizer/worker/split/interface.go | 7 + .../synchronizer/worker/split/split.go | 64 ++- .../{v2 => v3}/tasks/eventsync.go | 8 +- .../{v2 => v3}/tasks/impressionscountsync.go | 6 +- .../{v2 => v3}/tasks/impressionsync.go | 8 +- .../{v2 => v3}/tasks/interface.go | 10 +- .../{v2 => v3}/tasks/metricsync.go | 6 +- .../{v2 => v3}/tasks/segmentsync.go | 14 +- .../{v2 => v3}/tasks/splitsync.go | 11 +- .../{v2 => v3}/tasks/worker.go | 0 .../{v2 => v3}/util/metrics.go | 0 .../go-split-commons/{v2 => v3}/util/mode.go | 2 +- .../go-split-commons/{v2 => v3}/util/time.go | 0 .../splitio/go-toolkit/v3/sse/sse.go | 216 ---------- .../splitio/go-toolkit/{v3 => v4}/LICENSE | 0 .../{v3 => v4}/asynctask/asynctasks.go | 119 ++---- .../splitio/go-toolkit/v4/backoff/backoff.go | 35 ++ .../go-toolkit/{v3 => v4}/common/interface.go | 0 .../go-toolkit/{v3 => v4}/common/iterutil.go | 0 .../go-toolkit/{v3 => v4}/common/refutil.go | 0 .../go-toolkit/{v3 => v4}/common/sliceutil.go | 0 .../go-toolkit/{v3 => v4}/common/strutil.go | 0 .../go-toolkit/{v3 => v4}/common/timeutil.go | 0 .../datastructures/set/functions.go | 0 .../datastructures/set/implementations.go | 0 .../{v3 => v4}/datastructures/set/set.go | 0 .../{v3 => v4}/injection/container.go | 0 .../{v3 => v4}/logging/functions.go | 0 .../{v3 => v4}/logging/interface.go | 0 .../go-toolkit/{v3 => v4}/logging/levels.go | 0 .../go-toolkit/{v3 => v4}/logging/logging.go | 0 .../go-toolkit/{v3 => v4}/logging/rotate.go | 0 .../go-toolkit/{v3 => v4}/nethelpers/ip.go | 0 .../provisional/hashing/murmur128.go | 0 .../provisional/int64cache/cache.go | 0 .../go-toolkit/{v3 => v4}/queuecache/cache.go | 0 .../{v3 => v4}/redis/helpers/helpers.go | 2 +- .../{v3 => v4}/redis/prefixedclient.go | 0 .../go-toolkit/{v3 => v4}/redis/types.go | 0 .../go-toolkit/{v3 => v4}/redis/wrapper.go | 0 .../splitio/go-toolkit/v4/sse/errors.go | 31 ++ .../splitio/go-toolkit/v4/sse/event.go | 120 ++++++ .../splitio/go-toolkit/v4/sse/sse.go | 174 ++++++++ .../v4/struct/traits/lifecycle/lifecycle.go | 108 +++++ .../splitio/go-toolkit/v4/sync/atomicbool.go | 41 ++ .../{v3 => v4}/workerpool/workerpool.go | 149 ++++--- vendor/modules.txt | 79 ++-- 150 files changed, 2500 insertions(+), 1960 deletions(-) delete mode 100644 vendor/github.com/splitio/go-split-commons/v2/push/dtos.go delete mode 100644 vendor/github.com/splitio/go-split-commons/v2/push/eventhandler.go delete mode 100644 vendor/github.com/splitio/go-split-commons/v2/push/interface.go delete mode 100644 vendor/github.com/splitio/go-split-commons/v2/push/keeper.go delete mode 100644 vendor/github.com/splitio/go-split-commons/v2/push/parser.go delete mode 100644 vendor/github.com/splitio/go-split-commons/v2/push/processor.go delete mode 100644 vendor/github.com/splitio/go-split-commons/v2/push/pushmanager.go delete mode 100644 vendor/github.com/splitio/go-split-commons/v2/push/segment.go delete mode 100644 vendor/github.com/splitio/go-split-commons/v2/push/split.go delete mode 100644 vendor/github.com/splitio/go-split-commons/v2/service/api/sse/client.go delete mode 100644 vendor/github.com/splitio/go-split-commons/v2/synchronizer/interface.go delete mode 100644 vendor/github.com/splitio/go-split-commons/v2/synchronizer/manager.go delete mode 100644 vendor/github.com/splitio/go-split-commons/v2/synchronizer/worker/segment/interface.go delete mode 100644 vendor/github.com/splitio/go-split-commons/v2/synchronizer/worker/split/interface.go rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/LICENSE (100%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/conf/conf.go (100%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/conf/defaults.go (100%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/dtos/event.go (100%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/dtos/http.go (100%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/dtos/impression.go (100%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/dtos/metadata.go (100%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/dtos/metrics.go (100%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/dtos/notification.go (99%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/dtos/segment.go (100%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/dtos/split.go (100%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/dtos/token.go (100%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/provisional/impcounter.go (96%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/provisional/imphasher.go (90%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/provisional/impmanager.go (94%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/provisional/impobserver.go (94%) create mode 100644 vendor/github.com/splitio/go-split-commons/v3/push/borrowed.go create mode 100644 vendor/github.com/splitio/go-split-commons/v3/push/constants.go create mode 100644 vendor/github.com/splitio/go-split-commons/v3/push/manager.go create mode 100644 vendor/github.com/splitio/go-split-commons/v3/push/parser.go create mode 100644 vendor/github.com/splitio/go-split-commons/v3/push/processor.go create mode 100644 vendor/github.com/splitio/go-split-commons/v3/push/segment.go create mode 100644 vendor/github.com/splitio/go-split-commons/v3/push/split.go create mode 100644 vendor/github.com/splitio/go-split-commons/v3/push/statustracker.go rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/service/api/auth.go (78%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/service/api/client.go (85%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/service/api/http_fetchers.go (76%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/service/api/http_recorders.go (97%) create mode 100644 vendor/github.com/splitio/go-split-commons/v3/service/api/sse/client.go rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/service/interfaces.go (83%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/service/local/splitFetcher.go (95%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/service/split.go (83%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/storage/interfaces.go (97%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/storage/metricWrapper.go (98%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/storage/mocks/event.go (95%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/storage/mocks/impression.go (95%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/storage/mocks/metric.go (97%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/storage/mocks/segment.go (96%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/storage/mocks/split.go (95%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/storage/mutexmap/metrics.go (98%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/storage/mutexmap/segments.go (97%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/storage/mutexmap/splits.go (98%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/storage/mutexqueue/constants.go (100%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/storage/mutexqueue/events.go (97%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/storage/mutexqueue/impressions.go (96%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/storage/redis/constants.go (100%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/storage/redis/events.go (96%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/storage/redis/impressions.go (97%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/storage/redis/metrics.go (98%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/storage/redis/miscstorage.go (94%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/storage/redis/redis.go (91%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/storage/redis/segments.go (95%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/storage/redis/splits.go (97%) create mode 100644 vendor/github.com/splitio/go-split-commons/v3/synchronizer/interface.go rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/synchronizer/local.go (68%) create mode 100644 vendor/github.com/splitio/go-split-commons/v3/synchronizer/manager.go rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/synchronizer/synchronizer.go (67%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/synchronizer/worker/event/interface.go (100%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/synchronizer/worker/event/single.go (86%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/synchronizer/worker/impression/interface.go (100%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/synchronizer/worker/impression/single.go (90%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/synchronizer/worker/impressionscount/interface.go (100%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/synchronizer/worker/impressionscount/single.go (88%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/synchronizer/worker/metric/interface.go (100%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/synchronizer/worker/metric/single.go (91%) create mode 100644 vendor/github.com/splitio/go-split-commons/v3/synchronizer/worker/segment/interface.go rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/synchronizer/worker/segment/segment.go (77%) create mode 100644 vendor/github.com/splitio/go-split-commons/v3/synchronizer/worker/split/interface.go rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/synchronizer/worker/split/split.go (52%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/tasks/eventsync.go (86%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/tasks/impressionscountsync.go (79%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/tasks/impressionsync.go (87%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/tasks/interface.go (85%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/tasks/metricsync.go (75%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/tasks/segmentsync.go (84%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/tasks/splitsync.go (58%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/tasks/worker.go (100%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/util/metrics.go (100%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/util/mode.go (93%) rename vendor/github.com/splitio/go-split-commons/{v2 => v3}/util/time.go (100%) delete mode 100644 vendor/github.com/splitio/go-toolkit/v3/sse/sse.go rename vendor/github.com/splitio/go-toolkit/{v3 => v4}/LICENSE (100%) rename vendor/github.com/splitio/go-toolkit/{v3 => v4}/asynctask/asynctasks.go (55%) create mode 100644 vendor/github.com/splitio/go-toolkit/v4/backoff/backoff.go rename vendor/github.com/splitio/go-toolkit/{v3 => v4}/common/interface.go (100%) rename vendor/github.com/splitio/go-toolkit/{v3 => v4}/common/iterutil.go (100%) rename vendor/github.com/splitio/go-toolkit/{v3 => v4}/common/refutil.go (100%) rename vendor/github.com/splitio/go-toolkit/{v3 => v4}/common/sliceutil.go (100%) rename vendor/github.com/splitio/go-toolkit/{v3 => v4}/common/strutil.go (100%) rename vendor/github.com/splitio/go-toolkit/{v3 => v4}/common/timeutil.go (100%) rename vendor/github.com/splitio/go-toolkit/{v3 => v4}/datastructures/set/functions.go (100%) rename vendor/github.com/splitio/go-toolkit/{v3 => v4}/datastructures/set/implementations.go (100%) rename vendor/github.com/splitio/go-toolkit/{v3 => v4}/datastructures/set/set.go (100%) rename vendor/github.com/splitio/go-toolkit/{v3 => v4}/injection/container.go (100%) rename vendor/github.com/splitio/go-toolkit/{v3 => v4}/logging/functions.go (100%) rename vendor/github.com/splitio/go-toolkit/{v3 => v4}/logging/interface.go (100%) rename vendor/github.com/splitio/go-toolkit/{v3 => v4}/logging/levels.go (100%) rename vendor/github.com/splitio/go-toolkit/{v3 => v4}/logging/logging.go (100%) rename vendor/github.com/splitio/go-toolkit/{v3 => v4}/logging/rotate.go (100%) rename vendor/github.com/splitio/go-toolkit/{v3 => v4}/nethelpers/ip.go (100%) rename vendor/github.com/splitio/go-toolkit/{v3 => v4}/provisional/hashing/murmur128.go (100%) rename vendor/github.com/splitio/go-toolkit/{v3 => v4}/provisional/int64cache/cache.go (100%) rename vendor/github.com/splitio/go-toolkit/{v3 => v4}/queuecache/cache.go (100%) rename vendor/github.com/splitio/go-toolkit/{v3 => v4}/redis/helpers/helpers.go (89%) rename vendor/github.com/splitio/go-toolkit/{v3 => v4}/redis/prefixedclient.go (100%) rename vendor/github.com/splitio/go-toolkit/{v3 => v4}/redis/types.go (100%) rename vendor/github.com/splitio/go-toolkit/{v3 => v4}/redis/wrapper.go (100%) create mode 100644 vendor/github.com/splitio/go-toolkit/v4/sse/errors.go create mode 100644 vendor/github.com/splitio/go-toolkit/v4/sse/event.go create mode 100644 vendor/github.com/splitio/go-toolkit/v4/sse/sse.go create mode 100644 vendor/github.com/splitio/go-toolkit/v4/struct/traits/lifecycle/lifecycle.go create mode 100644 vendor/github.com/splitio/go-toolkit/v4/sync/atomicbool.go rename vendor/github.com/splitio/go-toolkit/{v3 => v4}/workerpool/workerpool.go (52%) diff --git a/go.mod b/go.mod index 9530e9a323..7251c84d3e 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,6 @@ require ( github.com/aws/aws-sdk-go v1.36.29 github.com/blang/semver v3.5.1+incompatible github.com/blevesearch/bleve v1.0.14 - github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect github.com/cespare/xxhash/v2 v2.1.1 github.com/corpix/uarand v0.1.1 // indirect github.com/dgrijalva/jwt-go v3.2.0+incompatible @@ -32,12 +31,10 @@ require ( github.com/getsentry/sentry-go v0.9.0 github.com/glycerine/go-unsnap-stream v0.0.0-20190901134440-81cf024a9e0a // indirect github.com/go-asn1-ber/asn1-ber v1.5.3 // indirect - github.com/go-bindata/go-bindata v3.1.2+incompatible // indirect github.com/go-redis/redis/v8 v8.4.9 // indirect github.com/go-resty/resty/v2 v2.4.0 // indirect github.com/go-sql-driver/mysql v1.5.0 github.com/gobwas/ws v1.1.0-rc.2 - github.com/golang-migrate/migrate v3.5.4+incompatible // indirect github.com/golang-migrate/migrate/v4 v4.14.1 github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 github.com/golang/snappy v0.0.2 // indirect @@ -108,7 +105,7 @@ require ( github.com/sirupsen/logrus v1.7.0 github.com/smartystreets/assertions v1.0.0 // indirect github.com/spf13/cobra v1.1.1 - github.com/splitio/go-client/v6 v6.0.1 + github.com/splitio/go-client/v6 v6.0.2 github.com/stretchr/objx v0.3.0 // indirect github.com/stretchr/testify v1.7.0 github.com/throttled/throttled v2.2.5+incompatible diff --git a/go.sum b/go.sum index c1d64b3518..0040d12119 100644 --- a/go.sum +++ b/go.sum @@ -48,6 +48,7 @@ git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGy git.apache.org/thrift.git v0.12.0/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/Azure/azure-sdk-for-go v26.5.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/Azure/go-autorest v11.5.2+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= @@ -71,6 +72,7 @@ github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0 github.com/Masterminds/squirrel v1.5.0 h1:JukIZisrUXadA9pl3rMkjhiamxiB0cXiu+HGp/Y8cY8= github.com/Masterminds/squirrel v1.5.0/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10= github.com/Masterminds/vcs v1.13.0/go.mod h1:N09YCmOQr6RLxC6UNHzuVwAdodYbbnycGHSmwVJjcKA= +github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5 h1:ygIc8M6trr62pF5DucadTWGdEB4mEyvzi0e2nbcmcyA= github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/PaulARoy/azurestoragecache v0.0.0-20170906084534-3c249a3ba788/go.mod h1:lY1dZd8HBzJ10eqKERHn3CU59tfhzcAVb2c0ZhIWSOk= @@ -205,6 +207,7 @@ github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE github.com/codegangsta/cli v1.20.0/go.mod h1:/qJNoX69yVSKu5o4jLyXAENLRyk1uhi7zkbQ3slBdOA= github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= github.com/containerd/containerd v1.4.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.4.1 h1:pASeJT3R3YyVn+94qEPk0SnU1OQ20Jd/T+SPKy9xehY= github.com/containerd/containerd v1.4.1/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= @@ -249,15 +252,20 @@ github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUn 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/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/dhui/dktest v0.3.3 h1:DBuH/9GFaWbDRa42qsut/hbQu+srAQ0rPWnUoiGX7CA= github.com/dhui/dktest v0.3.3/go.mod h1:EML9sP4sqJELHn4jV7B0TY8oF6077nk83/tz7M56jcQ= github.com/die-net/lrucache v0.0.0-20181227122439-19a39ef22a11/go.mod h1:ew0MSjCVDdtGMjF3kzLK9hwdgF5mOE8SbYVF3Rc7mkU= github.com/disintegration/imaging v1.6.0/go.mod h1:xuIt+sRxDFrHS0drzXUlCJthkJ8k7lkkUojDSR247MQ= github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c= github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4= github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= +github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v17.12.0-ce-rc1.0.20200618181300-9dc6525e6118+incompatible h1:iWPIG7pWIsCwT6ZtHnTUpoVMnete7O/pzd9HFE3+tn8= github.com/docker/docker v17.12.0-ce-rc1.0.20200618181300-9dc6525e6118+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dsnet/compress v0.0.1 h1:PlZu0n3Tuv04TzpfPbrnI0HW/YwodEXDS+oPKahKF0Q= github.com/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5JflhBbQEHo= @@ -323,9 +331,6 @@ github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1T github.com/go-asn1-ber/asn1-ber v1.3.2-0.20191121212151-29be175fc3a3/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-asn1-ber/asn1-ber v1.5.3 h1:u7utq56RUFiynqUzgVMFDymapcOtQ/MZkh3H4QYkxag= github.com/go-asn1-ber/asn1-ber v1.5.3/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= -github.com/go-bindata/go-bindata v1.0.0 h1:DZ34txDXWn1DyWa+vQf7V9ANc2ILTtrEjtlsdJRF26M= -github.com/go-bindata/go-bindata v3.1.2+incompatible h1:5vjJMVhowQdPzjE1LdxyFF7YFTXg5IgGVW4gBr5IbvE= -github.com/go-bindata/go-bindata v3.1.2+incompatible/go.mod h1:xK8Dsgwmeed+BBsSy2XTopBn/8uK2HWuGSnA11C3Joo= github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= @@ -370,10 +375,8 @@ github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFG github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= -github.com/golang-migrate/migrate v1.3.2 h1:QAlFV1QF9zdkzy/jujlBVkVu+L/+k18cg8tuY1/4JDY= -github.com/golang-migrate/migrate v3.5.4+incompatible h1:R7OzwvCJTCgwapPCiX6DyBiu2czIUMDCB118gFTKTUA= -github.com/golang-migrate/migrate v3.5.4+incompatible/go.mod h1:IsVUlFN5puWOmXrqjgGUfIRIbU7mr8oNBE2tyERd9Wk= github.com/golang-migrate/migrate/v4 v4.14.1 h1:qmRd/rNGjM1r3Ve5gHd5ZplytrD02UcItYNxJ3iUHHE= github.com/golang-migrate/migrate/v4 v4.14.1/go.mod h1:l7Ks0Au6fYHuUIxUhQ0rcVX1uLlJg54C/VvW7tvxSz0= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= @@ -766,6 +769,7 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg= @@ -827,7 +831,9 @@ github.com/onsi/gomega v1.10.4/go.mod h1:g/HbgYopi++010VEqkFgJHKC09uJiW9UkXvMUuK github.com/oov/psd v0.0.0-20201203182240-dad9002861d9 h1:a6xAIHhp7La7zsMnX7RLRokELz540I7oJV56TR50TYg= github.com/oov/psd v0.0.0-20201203182240-dad9002861d9/go.mod h1:GHI1bnmAcbp96z6LNfBJvtrjxhaXGkbsk967utPlvL8= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= +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.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= @@ -1025,12 +1031,12 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= -github.com/splitio/go-client/v6 v6.0.1 h1:w8lOuyIw4S2DQQjAIPBKzF+eDngzkQIY8hWcbkWjcxc= -github.com/splitio/go-client/v6 v6.0.1/go.mod h1:WHjkBtEEJFHOpgqnHSb/X+e4CgzTi1gPNkg+c7w1Izg= -github.com/splitio/go-split-commons/v2 v2.0.1 h1:fpmdHKgWdcL6ON7hpSUUKTh4Nsv7Kl/9BBE1ZPcmdsw= -github.com/splitio/go-split-commons/v2 v2.0.1/go.mod h1:YsmZa0AE9DCTosPXekKBxYHzNXJHpZwID9FSfo5Tnis= -github.com/splitio/go-toolkit/v3 v3.0.1 h1:/H2wytH9r4GT4FpVmMWe7wUX99Y67b15fSbfIT1lIt8= -github.com/splitio/go-toolkit/v3 v3.0.1/go.mod h1:HGgawLnM2RlM84zVRbATpPMjF7H6u9CUYG6RlpwOlOk= +github.com/splitio/go-client/v6 v6.0.2 h1:nlEeXaI6bI7c74gkX8kohwqjrkCoTUzMY4QFPsAXKMU= +github.com/splitio/go-client/v6 v6.0.2/go.mod h1:JbxrPJiIJHdPi5alQx5bszNzNrdJR+er1ktd9RzGtgk= +github.com/splitio/go-split-commons/v3 v3.0.0 h1:TtBvkI6mbTJLPO2YIcIXKzbeHHndml44zhi+guWiY/I= +github.com/splitio/go-split-commons/v3 v3.0.0/go.mod h1:6YEmYZnfrqV1Fp0vo4JL26zhzsDPD7p/OwFWy1LW2n4= +github.com/splitio/go-toolkit/v4 v4.0.0 h1:L8yEQ9TxzG0zC1xR3zA+KI4IqCwBV0GiIGsBFRtWXJY= +github.com/splitio/go-toolkit/v4 v4.0.0/go.mod h1:EdIHN0yzB1GTXDYQc0KdKvnjkO/jfUM2YqHVYfhD3Wo= github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf h1:pvbZ0lM0XWPBqUKqFU8cmavspvIl9nulOYwdy6IFRRo= github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf/go.mod h1:RJID2RhlZKId02nZ62WenDCkgHFerpIOmW0iT7GKmXM= github.com/steveyen/gtreap v0.1.0 h1:CjhzTa274PyJLJuMZwIzCO1PfC00oRa8d1Kc78bFXJM= @@ -1395,6 +1401,7 @@ golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e h1:EHBhcS0mlXEAVwNyO2dLfjToGsyY4j24pTs2ScHnX7s= golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1623,6 +1630,7 @@ gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -1634,6 +1642,7 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3 h1:sXmLre5bzIR6ypkjXCDI3jHPssRhc8KD/Ome589sc3U= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4 h1:UoveltGrhghAA7ePc+e+QYDHXrBps2PqFZiHkGR/xK8= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= modernc.org/b v1.0.0/go.mod h1:uZWcZfRj1BpYzfN9JTerzlNUnnPsV9O2ZA8JsRcubNg= modernc.org/db v1.0.0/go.mod h1:kYD/cO29L/29RM0hXYl4i3+Q5VojL31kTUVpVJDw0s8= diff --git a/vendor/github.com/splitio/go-client/v6/splitio/client/client.go b/vendor/github.com/splitio/go-client/v6/splitio/client/client.go index 40a7a94f7a..77444d71e0 100644 --- a/vendor/github.com/splitio/go-client/v6/splitio/client/client.go +++ b/vendor/github.com/splitio/go-client/v6/splitio/client/client.go @@ -9,11 +9,11 @@ import ( "github.com/splitio/go-client/v6/splitio/engine/evaluator" "github.com/splitio/go-client/v6/splitio/engine/evaluator/impressionlabels" impressionlistener "github.com/splitio/go-client/v6/splitio/impressionListener" - "github.com/splitio/go-split-commons/v2/dtos" - "github.com/splitio/go-split-commons/v2/provisional" - "github.com/splitio/go-split-commons/v2/storage" - "github.com/splitio/go-split-commons/v2/util" - "github.com/splitio/go-toolkit/v3/logging" + "github.com/splitio/go-split-commons/v3/dtos" + "github.com/splitio/go-split-commons/v3/provisional" + "github.com/splitio/go-split-commons/v3/storage" + "github.com/splitio/go-split-commons/v3/util" + "github.com/splitio/go-toolkit/v4/logging" ) // SplitClient is the entry-point of the split SDK. diff --git a/vendor/github.com/splitio/go-client/v6/splitio/client/factory.go b/vendor/github.com/splitio/go-client/v6/splitio/client/factory.go index e983fe099d..443269e960 100644 --- a/vendor/github.com/splitio/go-client/v6/splitio/client/factory.go +++ b/vendor/github.com/splitio/go-client/v6/splitio/client/factory.go @@ -15,24 +15,24 @@ import ( "github.com/splitio/go-client/v6/splitio/engine" "github.com/splitio/go-client/v6/splitio/engine/evaluator" impressionlistener "github.com/splitio/go-client/v6/splitio/impressionListener" - config "github.com/splitio/go-split-commons/v2/conf" - "github.com/splitio/go-split-commons/v2/dtos" - "github.com/splitio/go-split-commons/v2/provisional" - "github.com/splitio/go-split-commons/v2/service" - "github.com/splitio/go-split-commons/v2/service/local" - "github.com/splitio/go-split-commons/v2/storage" - "github.com/splitio/go-split-commons/v2/storage/mutexmap" - "github.com/splitio/go-split-commons/v2/storage/mutexqueue" - "github.com/splitio/go-split-commons/v2/storage/redis" - "github.com/splitio/go-split-commons/v2/synchronizer" - "github.com/splitio/go-split-commons/v2/synchronizer/worker/event" - "github.com/splitio/go-split-commons/v2/synchronizer/worker/impression" - "github.com/splitio/go-split-commons/v2/synchronizer/worker/impressionscount" - "github.com/splitio/go-split-commons/v2/synchronizer/worker/metric" - "github.com/splitio/go-split-commons/v2/synchronizer/worker/segment" - "github.com/splitio/go-split-commons/v2/synchronizer/worker/split" - "github.com/splitio/go-split-commons/v2/tasks" - "github.com/splitio/go-toolkit/v3/logging" + config "github.com/splitio/go-split-commons/v3/conf" + "github.com/splitio/go-split-commons/v3/dtos" + "github.com/splitio/go-split-commons/v3/provisional" + "github.com/splitio/go-split-commons/v3/service" + "github.com/splitio/go-split-commons/v3/service/local" + "github.com/splitio/go-split-commons/v3/storage" + "github.com/splitio/go-split-commons/v3/storage/mutexmap" + "github.com/splitio/go-split-commons/v3/storage/mutexqueue" + "github.com/splitio/go-split-commons/v3/storage/redis" + "github.com/splitio/go-split-commons/v3/synchronizer" + "github.com/splitio/go-split-commons/v3/synchronizer/worker/event" + "github.com/splitio/go-split-commons/v3/synchronizer/worker/impression" + "github.com/splitio/go-split-commons/v3/synchronizer/worker/impressionscount" + "github.com/splitio/go-split-commons/v3/synchronizer/worker/metric" + "github.com/splitio/go-split-commons/v3/synchronizer/worker/segment" + "github.com/splitio/go-split-commons/v3/synchronizer/worker/split" + "github.com/splitio/go-split-commons/v3/tasks" + "github.com/splitio/go-toolkit/v4/logging" ) const ( @@ -63,7 +63,7 @@ type SplitFactory struct { cfg *conf.SplitSdkConfig impressionListener *impressionlistener.WrapperImpressionListener logger logging.LoggerInterface - syncManager *synchronizer.Manager + syncManager synchronizer.Manager impressionManager provisional.ImpressionManager } @@ -372,17 +372,11 @@ func setupLocalhostFactory( splitPeriod := cfg.TaskPeriods.SplitSync readyChannel := make(chan int, 1) + splitAPI := &service.SplitAPI{SplitFetcher: local.NewFileSplitFetcher(cfg.SplitFile, logger)} syncManager, err := synchronizer.NewSynchronizerManager( - synchronizer.NewLocal( - splitPeriod, - &service.SplitAPI{ - SplitFetcher: local.NewFileSplitFetcher(cfg.SplitFile, logger), - }, - splitStorage, - logger, - ), + synchronizer.NewLocal(splitPeriod, splitAPI, splitStorage, logger), logger, - config.AdvancedConfig{}, + config.AdvancedConfig{StreamingEnabled: false}, nil, splitStorage, readyChannel, diff --git a/vendor/github.com/splitio/go-client/v6/splitio/client/factory_tracker.go b/vendor/github.com/splitio/go-client/v6/splitio/client/factory_tracker.go index be98821c03..8d4d85c6d9 100644 --- a/vendor/github.com/splitio/go-client/v6/splitio/client/factory_tracker.go +++ b/vendor/github.com/splitio/go-client/v6/splitio/client/factory_tracker.go @@ -5,7 +5,7 @@ import ( "sync" "github.com/splitio/go-client/v6/splitio/conf" - "github.com/splitio/go-toolkit/v3/logging" + "github.com/splitio/go-toolkit/v4/logging" ) // factoryInstances factory tracker instantiations diff --git a/vendor/github.com/splitio/go-client/v6/splitio/client/input_validator.go b/vendor/github.com/splitio/go-client/v6/splitio/client/input_validator.go index b6e0a1e925..d742ae4ea1 100644 --- a/vendor/github.com/splitio/go-client/v6/splitio/client/input_validator.go +++ b/vendor/github.com/splitio/go-client/v6/splitio/client/input_validator.go @@ -9,9 +9,9 @@ import ( "strings" "github.com/splitio/go-client/v6/splitio/engine/evaluator/impressionlabels" - "github.com/splitio/go-split-commons/v2/storage" - "github.com/splitio/go-toolkit/v3/datastructures/set" - "github.com/splitio/go-toolkit/v3/logging" + "github.com/splitio/go-split-commons/v3/storage" + "github.com/splitio/go-toolkit/v4/datastructures/set" + "github.com/splitio/go-toolkit/v4/logging" ) // InputValidation struct is responsible for cheking any input of treatment and diff --git a/vendor/github.com/splitio/go-client/v6/splitio/client/manager.go b/vendor/github.com/splitio/go-client/v6/splitio/client/manager.go index 13e00c3d08..0703674ba4 100644 --- a/vendor/github.com/splitio/go-client/v6/splitio/client/manager.go +++ b/vendor/github.com/splitio/go-client/v6/splitio/client/manager.go @@ -3,9 +3,9 @@ package client import ( "fmt" - "github.com/splitio/go-split-commons/v2/dtos" - "github.com/splitio/go-split-commons/v2/storage" - "github.com/splitio/go-toolkit/v3/logging" + "github.com/splitio/go-split-commons/v3/dtos" + "github.com/splitio/go-split-commons/v3/storage" + "github.com/splitio/go-toolkit/v4/logging" ) // SplitManager provides information of the currently stored splits diff --git a/vendor/github.com/splitio/go-client/v6/splitio/conf/sdkconf.go b/vendor/github.com/splitio/go-client/v6/splitio/conf/sdkconf.go index 3ff10346bf..0ab9848431 100644 --- a/vendor/github.com/splitio/go-client/v6/splitio/conf/sdkconf.go +++ b/vendor/github.com/splitio/go-client/v6/splitio/conf/sdkconf.go @@ -10,10 +10,10 @@ import ( "strings" impressionlistener "github.com/splitio/go-client/v6/splitio/impressionListener" - "github.com/splitio/go-split-commons/v2/conf" - "github.com/splitio/go-toolkit/v3/datastructures/set" - "github.com/splitio/go-toolkit/v3/logging" - "github.com/splitio/go-toolkit/v3/nethelpers" + "github.com/splitio/go-split-commons/v3/conf" + "github.com/splitio/go-toolkit/v4/datastructures/set" + "github.com/splitio/go-toolkit/v4/logging" + "github.com/splitio/go-toolkit/v4/nethelpers" ) const ( diff --git a/vendor/github.com/splitio/go-client/v6/splitio/conf/util.go b/vendor/github.com/splitio/go-client/v6/splitio/conf/util.go index 44f0fd35e1..c4d2eb80d8 100644 --- a/vendor/github.com/splitio/go-client/v6/splitio/conf/util.go +++ b/vendor/github.com/splitio/go-client/v6/splitio/conf/util.go @@ -3,7 +3,7 @@ package conf import ( "strings" - "github.com/splitio/go-split-commons/v2/conf" + "github.com/splitio/go-split-commons/v3/conf" ) // NormalizeSDKConf compares against SDK Config to set defaults diff --git a/vendor/github.com/splitio/go-client/v6/splitio/engine/engine.go b/vendor/github.com/splitio/go-client/v6/splitio/engine/engine.go index 162f367211..1f6abd26f2 100644 --- a/vendor/github.com/splitio/go-client/v6/splitio/engine/engine.go +++ b/vendor/github.com/splitio/go-client/v6/splitio/engine/engine.go @@ -7,7 +7,7 @@ import ( "github.com/splitio/go-client/v6/splitio/engine/evaluator/impressionlabels" "github.com/splitio/go-client/v6/splitio/engine/grammar" "github.com/splitio/go-client/v6/splitio/engine/hash" - "github.com/splitio/go-toolkit/v3/logging" + "github.com/splitio/go-toolkit/v4/logging" ) // Engine struct is responsible for cheking if any of the conditions of the split matches, diff --git a/vendor/github.com/splitio/go-client/v6/splitio/engine/evaluator/evaluator.go b/vendor/github.com/splitio/go-client/v6/splitio/engine/evaluator/evaluator.go index c4d4e249a6..443156c55c 100644 --- a/vendor/github.com/splitio/go-client/v6/splitio/engine/evaluator/evaluator.go +++ b/vendor/github.com/splitio/go-client/v6/splitio/engine/evaluator/evaluator.go @@ -7,11 +7,11 @@ import ( "github.com/splitio/go-client/v6/splitio/engine" "github.com/splitio/go-client/v6/splitio/engine/evaluator/impressionlabels" "github.com/splitio/go-client/v6/splitio/engine/grammar" - "github.com/splitio/go-split-commons/v2/dtos" - "github.com/splitio/go-split-commons/v2/storage" + "github.com/splitio/go-split-commons/v3/dtos" + "github.com/splitio/go-split-commons/v3/storage" - "github.com/splitio/go-toolkit/v3/injection" - "github.com/splitio/go-toolkit/v3/logging" + "github.com/splitio/go-toolkit/v4/injection" + "github.com/splitio/go-toolkit/v4/logging" ) const ( diff --git a/vendor/github.com/splitio/go-client/v6/splitio/engine/grammar/condition.go b/vendor/github.com/splitio/go-client/v6/splitio/engine/grammar/condition.go index 9565b8cbbf..f6ef646e0f 100644 --- a/vendor/github.com/splitio/go-client/v6/splitio/engine/grammar/condition.go +++ b/vendor/github.com/splitio/go-client/v6/splitio/engine/grammar/condition.go @@ -2,9 +2,9 @@ package grammar import ( "github.com/splitio/go-client/v6/splitio/engine/grammar/matchers" - "github.com/splitio/go-split-commons/v2/dtos" - "github.com/splitio/go-toolkit/v3/injection" - "github.com/splitio/go-toolkit/v3/logging" + "github.com/splitio/go-split-commons/v3/dtos" + "github.com/splitio/go-toolkit/v4/injection" + "github.com/splitio/go-toolkit/v4/logging" ) // Condition struct with added logic that wraps around a DTO diff --git a/vendor/github.com/splitio/go-client/v6/splitio/engine/grammar/matchers/allofset.go b/vendor/github.com/splitio/go-client/v6/splitio/engine/grammar/matchers/allofset.go index 098fb3b100..f144bd9ee1 100644 --- a/vendor/github.com/splitio/go-client/v6/splitio/engine/grammar/matchers/allofset.go +++ b/vendor/github.com/splitio/go-client/v6/splitio/engine/grammar/matchers/allofset.go @@ -2,7 +2,7 @@ package matchers import ( "fmt" - "github.com/splitio/go-toolkit/v3/datastructures/set" + "github.com/splitio/go-toolkit/v4/datastructures/set" "reflect" ) diff --git a/vendor/github.com/splitio/go-client/v6/splitio/engine/grammar/matchers/anyofset.go b/vendor/github.com/splitio/go-client/v6/splitio/engine/grammar/matchers/anyofset.go index 1fdd31819a..c903d2f68b 100644 --- a/vendor/github.com/splitio/go-client/v6/splitio/engine/grammar/matchers/anyofset.go +++ b/vendor/github.com/splitio/go-client/v6/splitio/engine/grammar/matchers/anyofset.go @@ -1,7 +1,7 @@ package matchers import ( - "github.com/splitio/go-toolkit/v3/datastructures/set" + "github.com/splitio/go-toolkit/v4/datastructures/set" ) // ContainsAnyOfSetMatcher matches if the set supplied to the getTreatment is a superset of the one in the split diff --git a/vendor/github.com/splitio/go-client/v6/splitio/engine/grammar/matchers/equaltoset.go b/vendor/github.com/splitio/go-client/v6/splitio/engine/grammar/matchers/equaltoset.go index 4ee7779652..2b463b4457 100644 --- a/vendor/github.com/splitio/go-client/v6/splitio/engine/grammar/matchers/equaltoset.go +++ b/vendor/github.com/splitio/go-client/v6/splitio/engine/grammar/matchers/equaltoset.go @@ -1,7 +1,7 @@ package matchers import ( - "github.com/splitio/go-toolkit/v3/datastructures/set" + "github.com/splitio/go-toolkit/v4/datastructures/set" ) // EqualToSetMatcher matches if the set supplied to the getTreatment is equal to the one in the split diff --git a/vendor/github.com/splitio/go-client/v6/splitio/engine/grammar/matchers/insegment.go b/vendor/github.com/splitio/go-client/v6/splitio/engine/grammar/matchers/insegment.go index 53b6f27741..c527d24879 100644 --- a/vendor/github.com/splitio/go-client/v6/splitio/engine/grammar/matchers/insegment.go +++ b/vendor/github.com/splitio/go-client/v6/splitio/engine/grammar/matchers/insegment.go @@ -3,7 +3,7 @@ package matchers import ( "fmt" - "github.com/splitio/go-split-commons/v2/storage" + "github.com/splitio/go-split-commons/v3/storage" ) // InSegmentMatcher matches if the key passed is in the segment which the matcher was constructed with diff --git a/vendor/github.com/splitio/go-client/v6/splitio/engine/grammar/matchers/matchers.go b/vendor/github.com/splitio/go-client/v6/splitio/engine/grammar/matchers/matchers.go index 2a71ec85eb..2ffe0544bb 100644 --- a/vendor/github.com/splitio/go-client/v6/splitio/engine/grammar/matchers/matchers.go +++ b/vendor/github.com/splitio/go-client/v6/splitio/engine/grammar/matchers/matchers.go @@ -4,9 +4,9 @@ import ( "errors" "fmt" - "github.com/splitio/go-split-commons/v2/dtos" - "github.com/splitio/go-toolkit/v3/injection" - "github.com/splitio/go-toolkit/v3/logging" + "github.com/splitio/go-split-commons/v3/dtos" + "github.com/splitio/go-toolkit/v4/injection" + "github.com/splitio/go-toolkit/v4/logging" ) const ( diff --git a/vendor/github.com/splitio/go-client/v6/splitio/engine/grammar/matchers/partofset.go b/vendor/github.com/splitio/go-client/v6/splitio/engine/grammar/matchers/partofset.go index d9e6907528..6678a85436 100644 --- a/vendor/github.com/splitio/go-client/v6/splitio/engine/grammar/matchers/partofset.go +++ b/vendor/github.com/splitio/go-client/v6/splitio/engine/grammar/matchers/partofset.go @@ -1,7 +1,7 @@ package matchers import ( - "github.com/splitio/go-toolkit/v3/datastructures/set" + "github.com/splitio/go-toolkit/v4/datastructures/set" ) // PartOfSetMatcher matches if the set supplied to the getTreatment is a subset of the one in the split diff --git a/vendor/github.com/splitio/go-client/v6/splitio/engine/grammar/matchers/whitelist.go b/vendor/github.com/splitio/go-client/v6/splitio/engine/grammar/matchers/whitelist.go index c232ed5db5..7bc88a200c 100644 --- a/vendor/github.com/splitio/go-client/v6/splitio/engine/grammar/matchers/whitelist.go +++ b/vendor/github.com/splitio/go-client/v6/splitio/engine/grammar/matchers/whitelist.go @@ -1,7 +1,7 @@ package matchers import ( - "github.com/splitio/go-toolkit/v3/datastructures/set" + "github.com/splitio/go-toolkit/v4/datastructures/set" ) // WhitelistMatcher matches if the key received is present in the matcher's whitelist diff --git a/vendor/github.com/splitio/go-client/v6/splitio/engine/grammar/split.go b/vendor/github.com/splitio/go-client/v6/splitio/engine/grammar/split.go index 143aeb1a1e..44f2fe53f0 100644 --- a/vendor/github.com/splitio/go-client/v6/splitio/engine/grammar/split.go +++ b/vendor/github.com/splitio/go-client/v6/splitio/engine/grammar/split.go @@ -1,9 +1,9 @@ package grammar import ( - "github.com/splitio/go-split-commons/v2/dtos" - "github.com/splitio/go-toolkit/v3/injection" - "github.com/splitio/go-toolkit/v3/logging" + "github.com/splitio/go-split-commons/v3/dtos" + "github.com/splitio/go-toolkit/v4/injection" + "github.com/splitio/go-toolkit/v4/logging" ) // Split struct with added logic that wraps around a DTO diff --git a/vendor/github.com/splitio/go-client/v6/splitio/impressionListener/impressions_listener_wrapper.go b/vendor/github.com/splitio/go-client/v6/splitio/impressionListener/impressions_listener_wrapper.go index 523096d042..a3c7c7a0f2 100644 --- a/vendor/github.com/splitio/go-client/v6/splitio/impressionListener/impressions_listener_wrapper.go +++ b/vendor/github.com/splitio/go-client/v6/splitio/impressionListener/impressions_listener_wrapper.go @@ -1,7 +1,7 @@ package impressionlistener import ( - "github.com/splitio/go-split-commons/v2/dtos" + "github.com/splitio/go-split-commons/v3/dtos" ) // ILObject struct to map entire data for listener diff --git a/vendor/github.com/splitio/go-client/v6/splitio/version.go b/vendor/github.com/splitio/go-client/v6/splitio/version.go index 8fc89e39bd..e483a2ee29 100644 --- a/vendor/github.com/splitio/go-client/v6/splitio/version.go +++ b/vendor/github.com/splitio/go-client/v6/splitio/version.go @@ -1,4 +1,4 @@ package splitio // Version contains a string with the split sdk version -const Version = "6.0.1" +const Version = "6.0.2" diff --git a/vendor/github.com/splitio/go-split-commons/v2/push/dtos.go b/vendor/github.com/splitio/go-split-commons/v2/push/dtos.go deleted file mode 100644 index 4e8e7bebd0..0000000000 --- a/vendor/github.com/splitio/go-split-commons/v2/push/dtos.go +++ /dev/null @@ -1,47 +0,0 @@ -package push - -import ( - "fmt" - "github.com/splitio/go-toolkit/v3/common" -) - -// IncomingEvent struct to process every kind of notification that comes from streaming -type IncomingEvent struct { - id *string - timestamp *int64 - encoding *string - data *string - name *string - clientID *string - event string - channel *string - message *string - code *int - statusCode *int - href *string -} - -func (i *IncomingEvent) String() string { - return fmt.Sprintf(`Incoming event [id="%s", ts=%d, enc="%s", data="%s", name="%s", client="%s", `+ - `event="%s", channel="%s", code=%d, status=%d]`, - common.StringFromRef(i.id), - common.Int64FromRef(i.timestamp), - common.StringFromRef(i.encoding), - common.StringFromRef(i.data), - common.StringFromRef(i.name), - common.StringFromRef(i.clientID), - i.event, - common.StringFromRef(i.channel), - common.IntFromRef(i.code), - common.IntFromRef(i.statusCode)) -} - -// Metrics dto -type Metrics struct { - Publishers int `json:"publishers"` -} - -// Occupancy dto -type Occupancy struct { - Data Metrics `json:"metrics"` -} diff --git a/vendor/github.com/splitio/go-split-commons/v2/push/eventhandler.go b/vendor/github.com/splitio/go-split-commons/v2/push/eventhandler.go deleted file mode 100644 index f36cbd4461..0000000000 --- a/vendor/github.com/splitio/go-split-commons/v2/push/eventhandler.go +++ /dev/null @@ -1,89 +0,0 @@ -package push - -import ( - "encoding/json" - "fmt" - - "github.com/splitio/go-split-commons/v2/dtos" - "github.com/splitio/go-toolkit/v3/logging" -) - -// EventHandler struct -type EventHandler struct { - keeper *Keeper - parser *NotificationParser - processor *Processor - logger logging.LoggerInterface -} - -// NewEventHandler builds new EventHandler -func NewEventHandler(keeper *Keeper, parser *NotificationParser, processor *Processor, logger logging.LoggerInterface) *EventHandler { - return &EventHandler{ - keeper: keeper, - parser: parser, - processor: processor, - logger: logger, - } -} - -func (e *EventHandler) wrapOccupancy(incomingEvent IncomingEvent) *Occupancy { - if incomingEvent.data == nil { - return nil - } - - var occupancy *Occupancy - err := json.Unmarshal([]byte(*incomingEvent.data), &occupancy) - if err != nil { - return nil - } - - return occupancy -} - -func (e *EventHandler) wrapUpdateEvent(incomingEvent IncomingEvent) *dtos.IncomingNotification { - if incomingEvent.data == nil { - return nil - } - var incomingNotification *dtos.IncomingNotification - err := json.Unmarshal([]byte(*incomingEvent.data), &incomingNotification) - if err != nil { - e.logger.Error("cannot parse data as IncomingNotification type") - return nil - } - incomingNotification.Channel = *incomingEvent.channel - return incomingNotification -} - -// HandleIncomingMessage handles incoming message from streaming -func (e *EventHandler) HandleIncomingMessage(event map[string]interface{}) { - incomingEvent := e.parser.Parse(event) - switch incomingEvent.event { - case update: - e.logger.Debug("Update event received") - incomingNotification := e.wrapUpdateEvent(incomingEvent) - if incomingNotification == nil { - e.logger.Debug("Skipping incoming notification...") - return - } - e.logger.Debug("Incoming Notification:", incomingNotification) - err := e.processor.Process(*incomingNotification) - if err != nil { - e.logger.Debug("Could not process notification", err.Error()) - return - } - case occupancy: - e.logger.Debug("Presence event received") - occupancy := e.wrapOccupancy(incomingEvent) - if occupancy == nil || incomingEvent.channel == nil { - e.logger.Debug("Skipping occupancy...") - return - } - e.keeper.UpdateManagers(*incomingEvent.channel, occupancy.Data.Publishers) - return - case errorType: // TODO: Update this when logic is fully defined - e.logger.Error(fmt.Sprintf("Error received: %+v", incomingEvent)) - default: - e.logger.Debug(fmt.Sprintf("Unexpected incomingEvent: %+v", incomingEvent)) - e.logger.Error("Unexpected type of event received") - } -} diff --git a/vendor/github.com/splitio/go-split-commons/v2/push/interface.go b/vendor/github.com/splitio/go-split-commons/v2/push/interface.go deleted file mode 100644 index f6e4c6177d..0000000000 --- a/vendor/github.com/splitio/go-split-commons/v2/push/interface.go +++ /dev/null @@ -1,10 +0,0 @@ -package push - -// Manager interface for Push Manager -type Manager interface { - Start() - Stop() - StartWorkers() - StopWorkers() - IsRunning() bool -} diff --git a/vendor/github.com/splitio/go-split-commons/v2/push/keeper.go b/vendor/github.com/splitio/go-split-commons/v2/push/keeper.go deleted file mode 100644 index fa6e2ec8fd..0000000000 --- a/vendor/github.com/splitio/go-split-commons/v2/push/keeper.go +++ /dev/null @@ -1,98 +0,0 @@ -package push - -import ( - "strings" - "sync" -) - -const ( - // PublisherNotPresent there are no publishers sending data - PublisherNotPresent = iota - // PublisherAvailable there are publishers running - PublisherAvailable -) - -const ( - prefix = "[?occupancy=metrics.publishers]" -) - -// last struct for storing the last notification -type last struct { - manager string - timestamp int64 - mutex *sync.RWMutex -} - -// Keeper struct -type Keeper struct { - managers map[string]int - activeRegion string - last last - publishers chan<- int - mutex *sync.RWMutex -} - -// NewKeeper creates new keeper -func NewKeeper(publishers chan int) *Keeper { - last := last{ - mutex: &sync.RWMutex{}, - } - return &Keeper{ - managers: make(map[string]int), - activeRegion: "us-east-1", - mutex: &sync.RWMutex{}, - publishers: publishers, - last: last, - } -} - -func (k *Keeper) cleanManagerPrefix(manager string) string { - return strings.Replace(manager, prefix, "", -1) -} - -// Publishers returns the quantity of publishers for a particular manager -func (k *Keeper) Publishers(manager string) *int { - k.mutex.RLock() - defer k.mutex.RUnlock() - publisher, ok := k.managers[manager] - if ok { - return &publisher - } - return nil -} - -// UpdateManagers updates current manager count -func (k *Keeper) UpdateManagers(manager string, publishers int) { - parsedManager := k.cleanManagerPrefix(manager) - k.mutex.Lock() - defer k.mutex.Unlock() - k.managers[parsedManager] = publishers - - isAvailable := false - for _, publishers := range k.managers { - if publishers > 0 { - isAvailable = true - break - } - } - if !isAvailable { - k.publishers <- PublisherNotPresent - return - } - k.publishers <- PublisherAvailable -} - -// LastNotification return the latest notification saved -func (k *Keeper) LastNotification() (string, int64) { - k.last.mutex.RLock() - defer k.last.mutex.RUnlock() - return k.last.manager, k.last.timestamp -} - -// UpdateLastNotification updates last message received -func (k *Keeper) UpdateLastNotification(manager string, timestamp int64) { - k.last.mutex.Lock() - defer k.last.mutex.Unlock() - k.last.manager = k.cleanManagerPrefix(manager) - k.last.timestamp = timestamp -} diff --git a/vendor/github.com/splitio/go-split-commons/v2/push/parser.go b/vendor/github.com/splitio/go-split-commons/v2/push/parser.go deleted file mode 100644 index 2f2b6c57b5..0000000000 --- a/vendor/github.com/splitio/go-split-commons/v2/push/parser.go +++ /dev/null @@ -1,64 +0,0 @@ -package push - -import ( - "github.com/splitio/go-toolkit/v3/common" - "github.com/splitio/go-toolkit/v3/logging" -) - -const ( - update = "update" - errorType = "error" - occupancy = "[meta]occupancy" -) - -// NotificationParser struct -type NotificationParser struct { - logger logging.LoggerInterface -} - -// NewNotificationParser creates notifcation parser -func NewNotificationParser(logger logging.LoggerInterface) *NotificationParser { - return &NotificationParser{ - logger: logger, - } -} - -// Parse parses incoming event from streaming -func (n *NotificationParser) Parse(event map[string]interface{}) IncomingEvent { - incomingEvent := IncomingEvent{ - id: common.AsStringOrNil(event["id"]), - encoding: common.AsStringOrNil(event["encoding"]), - data: common.AsStringOrNil(event["data"]), - name: common.AsStringOrNil(event["name"]), - clientID: common.AsStringOrNil(event["clientId"]), - channel: common.AsStringOrNil(event["channel"]), - message: common.AsStringOrNil(event["message"]), - href: common.AsStringOrNil(event["href"]), - } - - timestamp := common.AsFloat64OrNil(event["timestamp"]) - if timestamp != nil { - incomingEvent.timestamp = common.Int64Ref(int64(*timestamp)) - } - code := common.AsFloat64OrNil(event["code"]) - if code != nil { - incomingEvent.code = common.IntRef(int(*code)) - } - statusCode := common.AsFloat64OrNil(event["statusCode"]) - if statusCode != nil { - incomingEvent.statusCode = common.IntRef(int(*statusCode)) - } - - if incomingEvent.code != nil && incomingEvent.statusCode != nil { - incomingEvent.event = errorType - return incomingEvent - } - - if incomingEvent.name != nil && *incomingEvent.name == occupancy { - incomingEvent.event = occupancy - return incomingEvent - } - - incomingEvent.event = update - return incomingEvent -} diff --git a/vendor/github.com/splitio/go-split-commons/v2/push/processor.go b/vendor/github.com/splitio/go-split-commons/v2/push/processor.go deleted file mode 100644 index dcb16ee9e7..0000000000 --- a/vendor/github.com/splitio/go-split-commons/v2/push/processor.go +++ /dev/null @@ -1,112 +0,0 @@ -package push - -import ( - "errors" - "fmt" - - "github.com/splitio/go-split-commons/v2/dtos" - "github.com/splitio/go-split-commons/v2/storage" - "github.com/splitio/go-toolkit/v3/logging" -) - -const ( - segmentQueueCheck = 5000 - splitQueueCheck = 5000 - streamingPausedType = "STREAMING_PAUSED" - streamingResumedType = "STREAMING_RESUMED" - streamingDisabledType = "STREAMING_DISABLED" -) - -const ( - // StreamingPaused The SDK should stop processing incoming UPDATE-type events - streamingPaused = iota - // StreamingResumed The SDK should resume processing UPDATE-type events (if not already) - streamingResumed - // StreamingDisabled The SDK should disable streaming completely and don’t try to reconnect until the SDK is re-instantiated - streamingDisabled -) - -// Processor struct for notification processor -type Processor struct { - segmentQueue chan dtos.SegmentChangeNotification - splitQueue chan dtos.SplitChangeNotification - splitStorage storage.SplitStorageProducer - controlStatus chan<- int - logger logging.LoggerInterface -} - -// NewProcessor creates new processor -func NewProcessor(segmentQueue chan dtos.SegmentChangeNotification, splitQueue chan dtos.SplitChangeNotification, splitStorage storage.SplitStorageProducer, logger logging.LoggerInterface, controlStatus chan int) (*Processor, error) { - if cap(segmentQueue) < segmentQueueCheck { - return nil, errors.New("Small size of segmentQueue") - } - if cap(splitQueue) < splitQueueCheck { - return nil, errors.New("Small size of splitQueue") - } - if cap(controlStatus) < 1 { - return nil, errors.New("Small size for control chan") - } - - return &Processor{ - segmentQueue: segmentQueue, - splitQueue: splitQueue, - splitStorage: splitStorage, - controlStatus: controlStatus, - logger: logger, - }, nil -} - -// Process takes an incoming notification and generates appropriate notifications for it. -func (p *Processor) Process(i dtos.IncomingNotification) error { - switch i.Type { - case dtos.SplitUpdate: - if i.ChangeNumber == nil { - return errors.New("ChangeNumber could not be nil, discarded") - } - splitUpdate := dtos.NewSplitChangeNotification(i.Channel, *i.ChangeNumber) - p.splitQueue <- splitUpdate - case dtos.SegmentUpdate: - if i.ChangeNumber == nil { - return errors.New("ChangeNumber could not be nil, discarded") - } - if i.SegmentName == nil { - return errors.New("SegmentName could not be nil, discarded") - } - segmentUpdate := dtos.NewSegmentChangeNotification(i.Channel, *i.ChangeNumber, *i.SegmentName) - p.segmentQueue <- segmentUpdate - case dtos.SplitKill: - if i.ChangeNumber == nil { - return errors.New("ChangeNumber could not be nil, discarded") - } - if i.SplitName == nil { - return errors.New("SplitName could not be nil, discarded") - } - if i.DefaultTreatment == nil { - return errors.New("DefaultTreatment could not be nil, discarded") - } - splitUpdate := dtos.NewSplitChangeNotification(i.Channel, *i.ChangeNumber) - p.splitStorage.KillLocally(*i.SplitName, *i.DefaultTreatment, *i.ChangeNumber) - p.splitQueue <- splitUpdate - case dtos.Control: - if i.ControlType == nil { - return errors.New("ControlType could not be nil, discarded") - } - control := dtos.NewControlNotification(i.Channel, *i.ControlType) - switch control.ControlType { - case streamingDisabledType: - p.logger.Debug("Received notification for disabling streaming") - p.controlStatus <- streamingDisabled - case streamingPausedType: - p.logger.Debug("Received notification for pausing streaming") - p.controlStatus <- streamingPaused - case streamingResumedType: - p.logger.Debug("Received notification for resuming streaming") - p.controlStatus <- streamingResumed - default: - p.logger.Debug(fmt.Sprintf("%s Unexpected type of Control Notification", control.ControlType)) - } - default: - return fmt.Errorf("Unknown IncomingNotification type: %T", i) - } - return nil -} diff --git a/vendor/github.com/splitio/go-split-commons/v2/push/pushmanager.go b/vendor/github.com/splitio/go-split-commons/v2/push/pushmanager.go deleted file mode 100644 index 81a19ddbd4..0000000000 --- a/vendor/github.com/splitio/go-split-commons/v2/push/pushmanager.go +++ /dev/null @@ -1,370 +0,0 @@ -package push - -import ( - "errors" - "fmt" - "net/http" - "sync/atomic" - "time" - - "github.com/splitio/go-split-commons/v2/conf" - "github.com/splitio/go-split-commons/v2/dtos" - "github.com/splitio/go-split-commons/v2/service" - "github.com/splitio/go-split-commons/v2/service/api/sse" - "github.com/splitio/go-split-commons/v2/storage" - "github.com/splitio/go-toolkit/v3/common" - "github.com/splitio/go-toolkit/v3/logging" - sseStatus "github.com/splitio/go-toolkit/v3/sse" -) - -const ( - resetTimer = 120 - maxPeriod = 30 * time.Minute -) - -const ( - // Ready represents ready - Ready = iota - // PushIsDown there are no publishers for streaming - PushIsDown - // PushIsUp there are publishers presents - PushIsUp - // BackoffAuth backoff is running for authentication - BackoffAuth - // BackoffSSE backoff is running for connecting to stream - BackoffSSE - // TokenExpiration flag to restart push services - TokenExpiration - // StreamingPaused flag for pausing streaming - StreamingPaused - // StreamingResumed flag for resuming streaming - StreamingResumed - // StreamingDisabled flag for disabling streaming - StreamingDisabled - // Reconnect flag to reconnect - Reconnect - // NonRetriableError represents an error that will force switching to polling - NonRetriableError -) - -// PushManager struct for managing push services -type PushManager struct { - authClient service.AuthClient - sseClient *sse.StreamingClient - segmentWorker *SegmentUpdateWorker - splitWorker *SplitUpdateWorker - eventHandler *EventHandler - managerStatus chan<- int - streamingStatus chan int - publishers chan int - logger logging.LoggerInterface - cancelAuthBackoff chan struct{} - cancelSSEBackoff chan struct{} - cancelTokenExpiration chan struct{} - cancelStreamingWatcher chan struct{} - control chan int - status atomic.Value -} - -// NewPushManager creates new PushManager -func NewPushManager( - logger logging.LoggerInterface, - synchronizeSegmentHandler func(segmentName string, till *int64) error, - synchronizeSplitsHandler func(till *int64) error, - splitStorage storage.SplitStorage, - config *conf.AdvancedConfig, - managerStatus chan int, - authClient service.AuthClient, -) (Manager, error) { - splitQueue := make(chan dtos.SplitChangeNotification, config.SplitUpdateQueueSize) - segmentQueue := make(chan dtos.SegmentChangeNotification, config.SegmentUpdateQueueSize) - control := make(chan int, 1) - processor, err := NewProcessor(segmentQueue, splitQueue, splitStorage, logger, control) - if err != nil { - return nil, err - } - parser := NewNotificationParser(logger) - if parser == nil { - return nil, errors.New("Could not instantiate NotificationParser") - } - publishers := make(chan int, 1000) - keeper := NewKeeper(publishers) - if keeper == nil { - return nil, errors.New("Could not instantiate Keeper") - } - eventHandler := NewEventHandler(keeper, parser, processor, logger) - segmentWorker, err := NewSegmentUpdateWorker(segmentQueue, synchronizeSegmentHandler, logger) - if err != nil { - return nil, err - } - splitWorker, err := NewSplitUpdateWorker(splitQueue, synchronizeSplitsHandler, logger) - if err != nil { - return nil, err - } - - streamingStatus := make(chan int, 1000) - status := atomic.Value{} - status.Store(Ready) - return &PushManager{ - authClient: authClient, - sseClient: sse.NewStreamingClient(config, streamingStatus, logger), - segmentWorker: segmentWorker, - splitWorker: splitWorker, - managerStatus: managerStatus, - streamingStatus: streamingStatus, - eventHandler: eventHandler, - publishers: publishers, - logger: logger, - cancelAuthBackoff: make(chan struct{}, 1), - cancelSSEBackoff: make(chan struct{}, 1), - cancelTokenExpiration: make(chan struct{}, 1), - cancelStreamingWatcher: make(chan struct{}, 1), - control: control, - status: status, - }, nil -} - -func (p *PushManager) cancelStreaming() { - p.logger.Error("Error, switching to polling") - p.managerStatus <- NonRetriableError -} - -func (p *PushManager) performAuthentication(errResult chan error) *dtos.Token { - select { - case <-p.cancelAuthBackoff: - // Discarding previous msg - default: - } - tokenResult := make(chan *dtos.Token, 1) - cancelAuthBackoff := common.WithBackoffCancelling(1*time.Second, maxPeriod, func() bool { - token, err := p.authClient.Authenticate() - if err != nil { - errType, ok := err.(dtos.HTTPError) - if ok && errType.Code >= http.StatusInternalServerError { - p.managerStatus <- BackoffAuth - return false // It will continue retrying - } - errResult <- errors.New("Error authenticating") - return true - } - tokenResult <- token - return true // Result is OK, Stopping Here, no more backoff - }) - defer cancelAuthBackoff() - select { - case token := <-tokenResult: - if !token.PushEnabled { - return nil - } - return token - case err := <-errResult: - p.logger.Error(err.Error()) - return nil - case <-p.cancelAuthBackoff: - return nil - } -} - -func (p *PushManager) connectToStreaming(errResult chan error, token string, channels []string) error { - select { - case <-p.cancelSSEBackoff: - // Discarding previous msg - default: - } - sseResult := make(chan struct{}, 1) - cancelSSEBackoff := common.WithBackoffCancelling(1*time.Second, maxPeriod, func() bool { - p.sseClient.ConnectStreaming(token, channels, p.eventHandler.HandleIncomingMessage) - status := <-p.streamingStatus - switch status { - case sseStatus.OK: - sseResult <- struct{}{} - return true - case sseStatus.ErrorInternal: - p.managerStatus <- BackoffSSE - return false // It will continue retrying - default: - errResult <- errors.New("Error connecting streaming") - return true - } - }) - defer cancelSSEBackoff() - select { - case <-sseResult: - return nil - case err := <-errResult: - p.logger.Error(err.Error()) - return err - case <-p.cancelSSEBackoff: - return nil - } -} - -func (p *PushManager) fetchStreamingToken(errResult chan error) (string, []string, error) { - token := p.performAuthentication(errResult) - if token == nil { - return "", []string{}, errors.New("Could not perform authentication") - } - channels, err := token.ChannelList() - if err != nil { - return "", []string{}, errors.New("Could not perform authentication") - } - nextTokenExpiration, err := token.CalculateNextTokenExpiration() - if err != nil { - return "", []string{}, errors.New("Could not perform authentication") - } - go func() { - // Create timeout timer for calculating next token expiration - idleDuration := nextTokenExpiration - tokenExpirationTimer := time.NewTimer(idleDuration) - defer tokenExpirationTimer.Stop() - - select { - case <-tokenExpirationTimer.C: // Timedout - p.logger.Info("Token expired") - p.managerStatus <- TokenExpiration - return - case <-p.cancelTokenExpiration: - return - } - }() - return token.Token, channels, nil -} - -func (p *PushManager) streamingStatusWatcher() { - for { - select { - case status := <-p.streamingStatus: // Streaming SSE Status - switch status { - case sseStatus.ErrorKeepAlive: // On ConnectionTimedOut -> Reconnect - fallthrough - case sseStatus.ErrorInternal: // On Error >= 500 -> Reconnect - fallthrough - case sseStatus.ErrorReadingStream: // On IOF -> Reconnect - p.managerStatus <- Reconnect - default: // Whatever other errors -> Send Error to disconnect - p.cancelStreaming() - } - case publisherStatus := <-p.publishers: // Publisher Available/Not Available - switch publisherStatus { - case PublisherNotPresent: - if p.status.Load().(int) != StreamingPaused { - p.managerStatus <- PushIsDown - } - case PublisherAvailable: - if p.status.Load().(int) != StreamingPaused { - p.managerStatus <- PushIsUp - } - default: - p.logger.Debug(fmt.Sprintf("Unexpected publisher status received %d", publisherStatus)) - } - case controlStatus := <-p.control: - switch controlStatus { - case streamingPaused: - p.logger.Debug("Received Pause Streaming Notification") - if p.status.Load().(int) != StreamingPaused { - p.logger.Info("Sending Pause Streaming") - p.status.Store(StreamingPaused) - p.managerStatus <- PushIsDown - } - case streamingResumed: - p.logger.Debug("Received Resume Streaming Notification") - if p.status.Load().(int) == StreamingPaused { - p.status.Store(StreamingResumed) - publishersAvailable := p.eventHandler.keeper.Publishers("control_pri") - if publishersAvailable != nil && *publishersAvailable > 0 { - p.logger.Info("Sending Resume Streaming") - p.managerStatus <- PushIsUp - } - } - case streamingDisabled: - p.logger.Info("Received Streaming Disabled Notification") - p.managerStatus <- StreamingDisabled - default: - p.logger.Debug(fmt.Sprintf("Unexpected control status received %d", controlStatus)) - } - case <-p.cancelStreamingWatcher: // Stopping Watcher - return - } - } -} - -func (p *PushManager) drainStatus() { - select { - case <-p.cancelStreamingWatcher: // Discarding previous msg - default: - } - select { - case <-p.cancelTokenExpiration: // Discarding previous token expiration - default: - } -} - -// Start push services -func (p *PushManager) Start() { - if p.IsRunning() { - p.logger.Info("PushManager is already running, skipping Start") - return - } - p.drainStatus() - - // errResult listener for fetching token and connecting to SSE - errResult := make(chan error, 1) - token, channels, err := p.fetchStreamingToken(errResult) - if err != nil { - p.cancelStreaming() - return - } - err = p.connectToStreaming(errResult, token, channels) - if err != nil { - p.cancelStreaming() - return - } - - // Everything is good, starting workers - p.splitWorker.Start() - p.segmentWorker.Start() - - // Sending Ready - p.managerStatus <- Ready - - // Starting streaming status watcher, it will listen 1) errors in SSE, 2) publishers changes, 3) stop - go p.streamingStatusWatcher() -} - -// Stop push services -func (p *PushManager) Stop() { - p.logger.Info("Stopping Push Services") - p.cancelAuthBackoff <- struct{}{} - p.cancelSSEBackoff <- struct{}{} - p.cancelTokenExpiration <- struct{}{} - p.cancelStreamingWatcher <- struct{}{} - if p.sseClient.IsRunning() { - p.sseClient.StopStreaming(true) - } - p.StopWorkers() -} - -// IsRunning returns true if the services are running -func (p *PushManager) IsRunning() bool { - return p.sseClient.IsRunning() || p.splitWorker.IsRunning() || p.segmentWorker.IsRunning() -} - -// StopWorkers stops workers -func (p *PushManager) StopWorkers() { - if p.splitWorker.IsRunning() { - p.splitWorker.Stop() - } - if p.segmentWorker.IsRunning() { - p.segmentWorker.Stop() - } -} - -// StartWorkers starts workers -func (p *PushManager) StartWorkers() { - if !p.splitWorker.IsRunning() { - p.splitWorker.Start() - } - if !p.segmentWorker.IsRunning() { - p.segmentWorker.Start() - } -} diff --git a/vendor/github.com/splitio/go-split-commons/v2/push/segment.go b/vendor/github.com/splitio/go-split-commons/v2/push/segment.go deleted file mode 100644 index b888d3bfcb..0000000000 --- a/vendor/github.com/splitio/go-split-commons/v2/push/segment.go +++ /dev/null @@ -1,76 +0,0 @@ -package push - -import ( - "errors" - "fmt" - "sync" - "sync/atomic" - - "github.com/splitio/go-split-commons/v2/dtos" - "github.com/splitio/go-toolkit/v3/logging" -) - -// SegmentUpdateWorker struct -type SegmentUpdateWorker struct { - activeGoroutines *sync.WaitGroup - segmentQueue chan dtos.SegmentChangeNotification - handler func(segmentName string, till *int64) error - logger logging.LoggerInterface - stop chan struct{} - running atomic.Value -} - -// NewSegmentUpdateWorker creates SegmentUpdateWorker -func NewSegmentUpdateWorker(segmentQueue chan dtos.SegmentChangeNotification, handler func(segmentName string, till *int64) error, logger logging.LoggerInterface) (*SegmentUpdateWorker, error) { - if cap(segmentQueue) < 5000 { - return nil, errors.New("") - } - running := atomic.Value{} - running.Store(false) - - return &SegmentUpdateWorker{ - segmentQueue: segmentQueue, - handler: handler, - logger: logger, - stop: make(chan struct{}, 1), - running: running, - }, nil -} - -// Start starts worker -func (s *SegmentUpdateWorker) Start() { - s.logger.Debug("Started SegmentUpdateWorker") - if s.IsRunning() { - s.logger.Debug("Segment worker is already running") - return - } - s.running.Store(true) - go func() { - for { - select { - case segmentUpdate := <-s.segmentQueue: - s.logger.Debug("Received Segment update and proceding to perform fetch") - s.logger.Debug(fmt.Sprintf("SegmentName: %s\nChangeNumber: %d", segmentUpdate.SegmentName, &segmentUpdate.ChangeNumber)) - err := s.handler(segmentUpdate.SegmentName, &segmentUpdate.ChangeNumber) - if err != nil { - s.logger.Error(err) - } - case <-s.stop: - return - } - } - }() -} - -// Stop stops worker -func (s *SegmentUpdateWorker) Stop() { - if s.IsRunning() { - s.stop <- struct{}{} - s.running.Store(false) - } -} - -// IsRunning indicates if worker is running or not -func (s *SegmentUpdateWorker) IsRunning() bool { - return s.running.Load().(bool) -} diff --git a/vendor/github.com/splitio/go-split-commons/v2/push/split.go b/vendor/github.com/splitio/go-split-commons/v2/push/split.go deleted file mode 100644 index 2f5ec5c795..0000000000 --- a/vendor/github.com/splitio/go-split-commons/v2/push/split.go +++ /dev/null @@ -1,77 +0,0 @@ -package push - -import ( - "errors" - "fmt" - "sync" - "sync/atomic" - - "github.com/splitio/go-split-commons/v2/dtos" - "github.com/splitio/go-toolkit/v3/logging" -) - -// SplitUpdateWorker struct -type SplitUpdateWorker struct { - activeGoroutines *sync.WaitGroup - splitQueue chan dtos.SplitChangeNotification - handler func(till *int64) error - logger logging.LoggerInterface - stop chan struct{} - running atomic.Value -} - -// NewSplitUpdateWorker creates SplitUpdateWorker -func NewSplitUpdateWorker(splitQueue chan dtos.SplitChangeNotification, handler func(till *int64) error, logger logging.LoggerInterface) (*SplitUpdateWorker, error) { - if cap(splitQueue) < 5000 { - return nil, errors.New("") - } - running := atomic.Value{} - running.Store(false) - - return &SplitUpdateWorker{ - activeGoroutines: &sync.WaitGroup{}, - splitQueue: splitQueue, - handler: handler, - logger: logger, - running: running, - stop: make(chan struct{}, 1), - }, nil -} - -// Start starts worker -func (s *SplitUpdateWorker) Start() { - s.logger.Debug("Started SplitUpdateWorker") - if s.IsRunning() { - s.logger.Info("Split worker is already running") - return - } - s.running.Store(true) - go func() { - for { - select { - case splitUpdate := <-s.splitQueue: - s.logger.Debug("Received Split update and proceding to perform fetch") - s.logger.Debug(fmt.Sprintf("ChangeNumber: %d", splitUpdate.ChangeNumber)) - err := s.handler(&splitUpdate.ChangeNumber) - if err != nil { - s.logger.Error(err) - } - case <-s.stop: - return - } - } - }() -} - -// Stop stops worker -func (s *SplitUpdateWorker) Stop() { - if s.IsRunning() { - s.stop <- struct{}{} - s.running.Store(false) - } -} - -// IsRunning indicates if worker is running or not -func (s *SplitUpdateWorker) IsRunning() bool { - return s.running.Load().(bool) -} diff --git a/vendor/github.com/splitio/go-split-commons/v2/service/api/sse/client.go b/vendor/github.com/splitio/go-split-commons/v2/service/api/sse/client.go deleted file mode 100644 index 0b54d41c60..0000000000 --- a/vendor/github.com/splitio/go-split-commons/v2/service/api/sse/client.go +++ /dev/null @@ -1,127 +0,0 @@ -package sse - -import ( - "strings" - "sync" - "sync/atomic" - - "github.com/splitio/go-split-commons/v2/conf" - "github.com/splitio/go-toolkit/v3/logging" - "github.com/splitio/go-toolkit/v3/sse" -) - -const ( - version = "1.1" - keepAlive = 120 -) - -// StreamingClient struct -type StreamingClient struct { - mutex *sync.RWMutex - sseClient *sse.SSEClient - sseStatus chan int - streamingStatus chan<- int - running atomic.Value - logger logging.LoggerInterface - stopped chan struct{} -} - -// NewStreamingClient creates new SSE Client -func NewStreamingClient(cfg *conf.AdvancedConfig, streamingStatus chan int, logger logging.LoggerInterface) *StreamingClient { - sseStatus := make(chan int, 1) - sseClient, _ := sse.NewSSEClient(cfg.StreamingServiceURL, sseStatus, keepAlive, logger) - running := atomic.Value{} - running.Store(false) - - return &StreamingClient{ - mutex: &sync.RWMutex{}, - sseClient: sseClient, - sseStatus: sseStatus, - streamingStatus: streamingStatus, - logger: logger, - running: running, - stopped: make(chan struct{}, 1), - } -} - -// ConnectStreaming connects to streaming -func (s *StreamingClient) ConnectStreaming(token string, channelList []string, handleIncomingMessage func(e map[string]interface{})) { - params := make(map[string]string) - params["channels"] = strings.Join(append(channelList), ",") - params["accessToken"] = token - params["v"] = version - - httpHandlerExited := make(chan struct{}, 1) - go func() { - s.sseClient.Do(params, handleIncomingMessage) - httpHandlerExited <- struct{}{} - }() - - // Consume remaining message in completion signaling channel if any: - select { - case <-s.stopped: - default: - } - select { - case <-s.sseStatus: - default: - } - - go func() { - defer func() { // When this goroutine exits, StopStreaming is freed - select { - case s.stopped <- struct{}{}: - default: - } - }() - for { - select { - case <-httpHandlerExited: - return - case status := <-s.sseStatus: - switch status { - case sse.OK: - s.logger.Info("SSE OK") - s.running.Store(true) - s.streamingStatus <- sse.OK - case sse.ErrorConnectToStreaming: - s.logger.Error("Error connecting to streaming") - s.streamingStatus <- sse.ErrorConnectToStreaming - case sse.ErrorKeepAlive: - s.logger.Error("Connection timed out") - s.streamingStatus <- sse.ErrorKeepAlive - case sse.ErrorOnClientCreation: - s.logger.Error("Could not create client for streaming") - s.streamingStatus <- sse.ErrorOnClientCreation - case sse.ErrorReadingStream: - s.logger.Error("Error reading streaming buffer") - s.streamingStatus <- sse.ErrorReadingStream - case sse.ErrorRequestPerformed: - s.logger.Error("Error performing request when connect to stream service") - s.streamingStatus <- sse.ErrorRequestPerformed - case sse.ErrorInternal: - s.logger.Error("Internal Error when connect to stream service") - s.streamingStatus <- sse.ErrorInternal - default: - s.logger.Error("Unexpected error occured with streaming") - s.streamingStatus <- sse.ErrorUnexpected - } - } - } - }() -} - -// StopStreaming stops streaming -func (s *StreamingClient) StopStreaming(blocking bool) { - s.sseClient.Shutdown() - s.logger.Info("Stopped streaming") - s.running.Store(false) - if blocking { - <-s.stopped - } -} - -// IsRunning returns true if it's running -func (s *StreamingClient) IsRunning() bool { - return s.running.Load().(bool) -} diff --git a/vendor/github.com/splitio/go-split-commons/v2/synchronizer/interface.go b/vendor/github.com/splitio/go-split-commons/v2/synchronizer/interface.go deleted file mode 100644 index af71ccd5b1..0000000000 --- a/vendor/github.com/splitio/go-split-commons/v2/synchronizer/interface.go +++ /dev/null @@ -1,12 +0,0 @@ -package synchronizer - -// Synchronizer interface for syncing data to and from splits servers -type Synchronizer interface { - SyncAll() error - SynchronizeSplits(till *int64) error - SynchronizeSegment(segmentName string, till *int64) error - StartPeriodicFetching() - StopPeriodicFetching() - StartPeriodicDataRecording() - StopPeriodicDataRecording() -} diff --git a/vendor/github.com/splitio/go-split-commons/v2/synchronizer/manager.go b/vendor/github.com/splitio/go-split-commons/v2/synchronizer/manager.go deleted file mode 100644 index c448be85da..0000000000 --- a/vendor/github.com/splitio/go-split-commons/v2/synchronizer/manager.go +++ /dev/null @@ -1,184 +0,0 @@ -package synchronizer - -import ( - "errors" - "sync/atomic" - - "github.com/splitio/go-split-commons/v2/conf" - "github.com/splitio/go-split-commons/v2/push" - "github.com/splitio/go-split-commons/v2/service" - "github.com/splitio/go-split-commons/v2/storage" - "github.com/splitio/go-toolkit/v3/logging" -) - -const ( - // Ready represents ready - Ready = iota - // StreamingReady ready - StreamingReady - // Error represents some error in SSE streaming - Error -) - -const ( - // Idle flags - Idle = iota - // Streaming flags - Streaming - // Polling flags - Polling -) - -// Manager struct -type Manager struct { - synchronizer Synchronizer - logger logging.LoggerInterface - config conf.AdvancedConfig - pushManager push.Manager - managerStatus chan int - streamingStatus chan int - status atomic.Value -} - -// NewSynchronizerManager creates new sync manager -func NewSynchronizerManager( - synchronizer Synchronizer, - logger logging.LoggerInterface, - config conf.AdvancedConfig, - authClient service.AuthClient, - splitStorage storage.SplitStorage, - managerStatus chan int, -) (*Manager, error) { - if managerStatus == nil || cap(managerStatus) < 1 { - return nil, errors.New("Status channel cannot be nil nor having capacity") - } - - status := atomic.Value{} - status.Store(Idle) - manager := &Manager{ - synchronizer: synchronizer, - logger: logger, - config: config, - managerStatus: managerStatus, - status: status, - } - if config.StreamingEnabled { - streamingStatus := make(chan int, 1000) - pushManager, err := push.NewPushManager(logger, synchronizer.SynchronizeSegment, synchronizer.SynchronizeSplits, splitStorage, &config, streamingStatus, authClient) - if err != nil { - return nil, err - } - manager.pushManager = pushManager - manager.streamingStatus = streamingStatus - } - - return manager, nil -} - -func (s *Manager) startPolling() { - s.status.Store(Polling) - s.pushManager.StopWorkers() - s.synchronizer.StartPeriodicFetching() -} - -// IsRunning returns true if is in Streaming or Polling -func (s *Manager) IsRunning() bool { - return s.status.Load().(int) != Idle -} - -// Start starts synchronization through Split -func (s *Manager) Start() { - if s.IsRunning() { - s.logger.Info("Manager is already running, skipping start") - return - } - select { - case <-s.managerStatus: - // Discarding previous status before starting - default: - } - err := s.synchronizer.SyncAll() - if err != nil { - s.managerStatus <- Error - return - } - s.logger.Debug("SyncAll Ready") - s.managerStatus <- Ready - s.synchronizer.StartPeriodicDataRecording() - if s.config.StreamingEnabled { - s.logger.Info("Start Streaming") - go s.pushManager.Start() - // Listens Streaming Status - for { - status := <-s.streamingStatus - switch status { - // Backoff is running -> start polling until auth is ok - case push.BackoffAuth: - fallthrough - // Backoff is running -> start polling until sse is connected - case push.BackoffSSE: - if s.status.Load().(int) != Polling { - s.logger.Info("Start periodic polling due backoff") - s.startPolling() - } - // SSE Streaming and workers are ready - case push.Ready: - // If Ready comes eventually when Backoff is done and polling is running - if s.status.Load().(int) == Polling { - s.synchronizer.StopPeriodicFetching() - } - s.logger.Info("SSE Streaming is ready") - s.status.Store(Streaming) - go s.synchronizer.SyncAll() - case push.StreamingDisabled: - fallthrough - // NonRetriableError occurs and it will switch to polling - case push.NonRetriableError: - s.pushManager.Stop() - s.logger.Info("Start periodic polling in Streaming") - s.startPolling() - return - // Publisher sends that there is no Notification Managers available - case push.PushIsDown: - // If streaming is already running, proceeding to stop workers - // and keeping SSE running - if s.status.Load().(int) == Streaming { - s.logger.Info("Start periodic polling in Streaming") - s.startPolling() - } - // Publisher sends that there are at least one Notification Manager available - case push.PushIsUp: - // If streaming is not already running, proceeding to start workers - if s.status.Load().(int) != Streaming { - s.logger.Info("Stop periodic polling") - s.pushManager.StartWorkers() - s.synchronizer.StopPeriodicFetching() - s.status.Store(Streaming) - go s.synchronizer.SyncAll() - } - // Reconnect received due error in streaming -> reconnecting - case push.Reconnect: - fallthrough - // Token expired -> reconnecting - case push.TokenExpiration: - s.pushManager.Stop() - go s.pushManager.Start() - } - } - } else { - s.logger.Info("Start periodic polling") - s.synchronizer.StartPeriodicFetching() - s.status.Store(Polling) - } -} - -// Stop stop synchronizaation through Split -func (s *Manager) Stop() { - s.logger.Info("STOPPING MANAGER TASKS") - if s.pushManager != nil && s.pushManager.IsRunning() { - s.pushManager.Stop() - } - s.synchronizer.StopPeriodicFetching() - s.synchronizer.StopPeriodicDataRecording() - s.status.Store(Idle) -} diff --git a/vendor/github.com/splitio/go-split-commons/v2/synchronizer/worker/segment/interface.go b/vendor/github.com/splitio/go-split-commons/v2/synchronizer/worker/segment/interface.go deleted file mode 100644 index fa014a7ff1..0000000000 --- a/vendor/github.com/splitio/go-split-commons/v2/synchronizer/worker/segment/interface.go +++ /dev/null @@ -1,8 +0,0 @@ -package segment - -// SegmentFetcher interface -type SegmentFetcher interface { - SynchronizeSegment(name string, till *int64) error - SynchronizeSegments() error - SegmentNames() []interface{} -} diff --git a/vendor/github.com/splitio/go-split-commons/v2/synchronizer/worker/split/interface.go b/vendor/github.com/splitio/go-split-commons/v2/synchronizer/worker/split/interface.go deleted file mode 100644 index 10bbef4123..0000000000 --- a/vendor/github.com/splitio/go-split-commons/v2/synchronizer/worker/split/interface.go +++ /dev/null @@ -1,6 +0,0 @@ -package split - -// SplitFetcher interface -type SplitFetcher interface { - SynchronizeSplits(till *int64) error -} diff --git a/vendor/github.com/splitio/go-split-commons/v2/LICENSE b/vendor/github.com/splitio/go-split-commons/v3/LICENSE similarity index 100% rename from vendor/github.com/splitio/go-split-commons/v2/LICENSE rename to vendor/github.com/splitio/go-split-commons/v3/LICENSE diff --git a/vendor/github.com/splitio/go-split-commons/v2/conf/conf.go b/vendor/github.com/splitio/go-split-commons/v3/conf/conf.go similarity index 100% rename from vendor/github.com/splitio/go-split-commons/v2/conf/conf.go rename to vendor/github.com/splitio/go-split-commons/v3/conf/conf.go diff --git a/vendor/github.com/splitio/go-split-commons/v2/conf/defaults.go b/vendor/github.com/splitio/go-split-commons/v3/conf/defaults.go similarity index 100% rename from vendor/github.com/splitio/go-split-commons/v2/conf/defaults.go rename to vendor/github.com/splitio/go-split-commons/v3/conf/defaults.go diff --git a/vendor/github.com/splitio/go-split-commons/v2/dtos/event.go b/vendor/github.com/splitio/go-split-commons/v3/dtos/event.go similarity index 100% rename from vendor/github.com/splitio/go-split-commons/v2/dtos/event.go rename to vendor/github.com/splitio/go-split-commons/v3/dtos/event.go diff --git a/vendor/github.com/splitio/go-split-commons/v2/dtos/http.go b/vendor/github.com/splitio/go-split-commons/v3/dtos/http.go similarity index 100% rename from vendor/github.com/splitio/go-split-commons/v2/dtos/http.go rename to vendor/github.com/splitio/go-split-commons/v3/dtos/http.go diff --git a/vendor/github.com/splitio/go-split-commons/v2/dtos/impression.go b/vendor/github.com/splitio/go-split-commons/v3/dtos/impression.go similarity index 100% rename from vendor/github.com/splitio/go-split-commons/v2/dtos/impression.go rename to vendor/github.com/splitio/go-split-commons/v3/dtos/impression.go diff --git a/vendor/github.com/splitio/go-split-commons/v2/dtos/metadata.go b/vendor/github.com/splitio/go-split-commons/v3/dtos/metadata.go similarity index 100% rename from vendor/github.com/splitio/go-split-commons/v2/dtos/metadata.go rename to vendor/github.com/splitio/go-split-commons/v3/dtos/metadata.go diff --git a/vendor/github.com/splitio/go-split-commons/v2/dtos/metrics.go b/vendor/github.com/splitio/go-split-commons/v3/dtos/metrics.go similarity index 100% rename from vendor/github.com/splitio/go-split-commons/v2/dtos/metrics.go rename to vendor/github.com/splitio/go-split-commons/v3/dtos/metrics.go diff --git a/vendor/github.com/splitio/go-split-commons/v2/dtos/notification.go b/vendor/github.com/splitio/go-split-commons/v3/dtos/notification.go similarity index 99% rename from vendor/github.com/splitio/go-split-commons/v2/dtos/notification.go rename to vendor/github.com/splitio/go-split-commons/v3/dtos/notification.go index 702cb53f68..e3bd5a30df 100644 --- a/vendor/github.com/splitio/go-split-commons/v2/dtos/notification.go +++ b/vendor/github.com/splitio/go-split-commons/v3/dtos/notification.go @@ -1,5 +1,6 @@ package dtos +/* const ( // SplitUpdate used when split is updated SplitUpdate = "SPLIT_UPDATE" @@ -147,3 +148,4 @@ func NewSplitKillNotification(channelName string, changeNumber int64, defaultTre SplitName: splitName, } } +*/ diff --git a/vendor/github.com/splitio/go-split-commons/v2/dtos/segment.go b/vendor/github.com/splitio/go-split-commons/v3/dtos/segment.go similarity index 100% rename from vendor/github.com/splitio/go-split-commons/v2/dtos/segment.go rename to vendor/github.com/splitio/go-split-commons/v3/dtos/segment.go diff --git a/vendor/github.com/splitio/go-split-commons/v2/dtos/split.go b/vendor/github.com/splitio/go-split-commons/v3/dtos/split.go similarity index 100% rename from vendor/github.com/splitio/go-split-commons/v2/dtos/split.go rename to vendor/github.com/splitio/go-split-commons/v3/dtos/split.go diff --git a/vendor/github.com/splitio/go-split-commons/v2/dtos/token.go b/vendor/github.com/splitio/go-split-commons/v3/dtos/token.go similarity index 100% rename from vendor/github.com/splitio/go-split-commons/v2/dtos/token.go rename to vendor/github.com/splitio/go-split-commons/v3/dtos/token.go diff --git a/vendor/github.com/splitio/go-split-commons/v2/provisional/impcounter.go b/vendor/github.com/splitio/go-split-commons/v3/provisional/impcounter.go similarity index 96% rename from vendor/github.com/splitio/go-split-commons/v2/provisional/impcounter.go rename to vendor/github.com/splitio/go-split-commons/v3/provisional/impcounter.go index 00d2d04e75..7c355174c3 100644 --- a/vendor/github.com/splitio/go-split-commons/v2/provisional/impcounter.go +++ b/vendor/github.com/splitio/go-split-commons/v3/provisional/impcounter.go @@ -3,7 +3,7 @@ package provisional import ( "sync" - "github.com/splitio/go-split-commons/v2/util" + "github.com/splitio/go-split-commons/v3/util" ) // Key struct for mapping each key to an amount diff --git a/vendor/github.com/splitio/go-split-commons/v2/provisional/imphasher.go b/vendor/github.com/splitio/go-split-commons/v3/provisional/imphasher.go similarity index 90% rename from vendor/github.com/splitio/go-split-commons/v2/provisional/imphasher.go rename to vendor/github.com/splitio/go-split-commons/v3/provisional/imphasher.go index f4a1dd54fd..df23958685 100644 --- a/vendor/github.com/splitio/go-split-commons/v2/provisional/imphasher.go +++ b/vendor/github.com/splitio/go-split-commons/v3/provisional/imphasher.go @@ -4,8 +4,8 @@ import ( "fmt" "strings" - "github.com/splitio/go-split-commons/v2/dtos" - "github.com/splitio/go-toolkit/v3/provisional/hashing" + "github.com/splitio/go-split-commons/v3/dtos" + "github.com/splitio/go-toolkit/v4/provisional/hashing" ) const hashKeyTemplate = "%s:%s:%s:%s:%d" diff --git a/vendor/github.com/splitio/go-split-commons/v2/provisional/impmanager.go b/vendor/github.com/splitio/go-split-commons/v3/provisional/impmanager.go similarity index 94% rename from vendor/github.com/splitio/go-split-commons/v2/provisional/impmanager.go rename to vendor/github.com/splitio/go-split-commons/v3/provisional/impmanager.go index 7279df7e20..44205507b2 100644 --- a/vendor/github.com/splitio/go-split-commons/v2/provisional/impmanager.go +++ b/vendor/github.com/splitio/go-split-commons/v3/provisional/impmanager.go @@ -3,9 +3,9 @@ package provisional import ( "time" - "github.com/splitio/go-split-commons/v2/conf" - "github.com/splitio/go-split-commons/v2/dtos" - "github.com/splitio/go-split-commons/v2/util" + "github.com/splitio/go-split-commons/v3/conf" + "github.com/splitio/go-split-commons/v3/dtos" + "github.com/splitio/go-split-commons/v3/util" ) const lastSeenCacheSize = 500000 // cache up to 500k impression hashes diff --git a/vendor/github.com/splitio/go-split-commons/v2/provisional/impobserver.go b/vendor/github.com/splitio/go-split-commons/v3/provisional/impobserver.go similarity index 94% rename from vendor/github.com/splitio/go-split-commons/v2/provisional/impobserver.go rename to vendor/github.com/splitio/go-split-commons/v3/provisional/impobserver.go index e9c5ef6dfd..b06af6ad8b 100644 --- a/vendor/github.com/splitio/go-split-commons/v2/provisional/impobserver.go +++ b/vendor/github.com/splitio/go-split-commons/v3/provisional/impobserver.go @@ -4,8 +4,8 @@ import ( "fmt" "sync" - "github.com/splitio/go-split-commons/v2/dtos" - "github.com/splitio/go-toolkit/v3/provisional/int64cache" + "github.com/splitio/go-split-commons/v3/dtos" + "github.com/splitio/go-toolkit/v4/provisional/int64cache" ) // ImpressionObserver is used to check wether an impression has been previously seen diff --git a/vendor/github.com/splitio/go-split-commons/v3/push/borrowed.go b/vendor/github.com/splitio/go-split-commons/v3/push/borrowed.go new file mode 100644 index 0000000000..73c9cb15a0 --- /dev/null +++ b/vendor/github.com/splitio/go-split-commons/v3/push/borrowed.go @@ -0,0 +1,13 @@ +package push + +// Borrowed synchronizer interface to break circular dependencies +type synchronizerInterface interface { + SyncAll(requestNoCache bool) error + SynchronizeSplits(till *int64, requestNoCache bool) error + LocalKill(splitName string, defaultTreatment string, changeNumber int64) + SynchronizeSegment(segmentName string, till *int64, requestNoCache bool) error + StartPeriodicFetching() + StopPeriodicFetching() + StartPeriodicDataRecording() + StopPeriodicDataRecording() +} diff --git a/vendor/github.com/splitio/go-split-commons/v3/push/constants.go b/vendor/github.com/splitio/go-split-commons/v3/push/constants.go new file mode 100644 index 0000000000..e9b4c0119b --- /dev/null +++ b/vendor/github.com/splitio/go-split-commons/v3/push/constants.go @@ -0,0 +1,14 @@ +package push + +const ( + workerStatusIdle = iota + workerStatusRunning + workerStatusShuttingDown +) + +const ( + pushManagerStatusIdle = iota + pushManagerStatusInitializing + pushManagerStatusRunning + pushManagerStatusShuttingDown +) diff --git a/vendor/github.com/splitio/go-split-commons/v3/push/manager.go b/vendor/github.com/splitio/go-split-commons/v3/push/manager.go new file mode 100644 index 0000000000..cca0bfa627 --- /dev/null +++ b/vendor/github.com/splitio/go-split-commons/v3/push/manager.go @@ -0,0 +1,237 @@ +package push + +import ( + "errors" + "fmt" + "net/http" + "sync" + "time" + + "github.com/splitio/go-split-commons/v3/conf" + "github.com/splitio/go-split-commons/v3/dtos" + "github.com/splitio/go-split-commons/v3/service" + "github.com/splitio/go-split-commons/v3/service/api/sse" + "github.com/splitio/go-toolkit/v4/common" + "github.com/splitio/go-toolkit/v4/logging" + "github.com/splitio/go-toolkit/v4/struct/traits/lifecycle" +) + +// Status update contants that will be propagated to the push manager's user +const ( + StatusUp = iota + StatusDown + StatusRetryableError + StatusNonRetryableError +) + +// ErrAlreadyRunning is the error to be returned when .Start() is called on an already running instance +var ErrAlreadyRunning = errors.New("push manager already running") + +// ErrNotRunning is the error to be returned when .Stop() is called on a non-running instance +var ErrNotRunning = errors.New("push manager not running") + +// Manager interface contains public methods for push manager +type Manager interface { + Start() error + Stop() error + StopWorkers() + StartWorkers() +} + +// ManagerImpl implements the manager interface +type ManagerImpl struct { + parser NotificationParser + sseClient sse.StreamingClient + authAPI service.AuthClient + processor Processor + statusTracker StatusTracker + feedback FeedbackLoop + nextRefresh *time.Timer + refreshTokenMutex sync.Mutex + /* + running *gtSync.AtomicBool + status int32 + shutdownWaiter chan struct{} + */ + lifecycle lifecycle.Manager + logger logging.LoggerInterface +} + +// FeedbackLoop is a type alias for the type of chan that must be supplied for push status tobe propagated +type FeedbackLoop = chan<- int64 + +// NewManager constructs a new push manager +func NewManager( + logger logging.LoggerInterface, + synchronizer synchronizerInterface, + cfg *conf.AdvancedConfig, + feedbackLoop chan<- int64, + authAPI service.AuthClient, +) (*ManagerImpl, error) { + + processor, err := NewProcessor(cfg.SplitUpdateQueueSize, cfg.SegmentUpdateQueueSize, synchronizer, logger) + if err != nil { + return nil, fmt.Errorf("error instantiating processor: %w", err) + } + + statusTracker := NewStatusTracker(logger) + parser := &NotificationParserImpl{ + logger: logger, + onSplitUpdate: processor.ProcessSplitChangeUpdate, + onSplitKill: processor.ProcessSplitKillUpdate, + onSegmentUpdate: processor.ProcessSegmentChangeUpdate, + onControlUpdate: statusTracker.HandleControl, + onOccupancyMesage: statusTracker.HandleOccupancy, + onAblyError: statusTracker.HandleAblyError, + } + + manager := &ManagerImpl{ + authAPI: authAPI, + sseClient: sse.NewStreamingClient(cfg, logger), + statusTracker: statusTracker, + feedback: feedbackLoop, + processor: processor, + parser: parser, + logger: logger, + } + manager.lifecycle.Setup() + return manager, nil +} + +// Start initiates the authentication flow and if successful initiates a connection +func (m *ManagerImpl) Start() error { + if !m.lifecycle.BeginInitialization() { + return ErrAlreadyRunning + } + m.triggerConnectionFlow() + return nil +} + +// Stop method stops the sse client and it's status monitoring goroutine +func (m *ManagerImpl) Stop() error { + if !m.lifecycle.BeginShutdown() { + return ErrNotRunning + } + m.statusTracker.NotifySSEShutdownExpected() + m.withRefreshTokenLock(func() { + if m.nextRefresh != nil { + m.nextRefresh.Stop() + } + }) + m.StopWorkers() + m.sseClient.StopStreaming() + m.lifecycle.AwaitShutdownComplete() + return nil +} + +// StartWorkers start the splits & segments workers +func (m *ManagerImpl) StartWorkers() { + m.processor.StartWorkers() +} + +// StopWorkers stops the splits & segments workers +func (m *ManagerImpl) StopWorkers() { + m.processor.StopWorkers() +} + +func (m *ManagerImpl) performAuthentication() (*dtos.Token, *int64) { + token, err := m.authAPI.Authenticate() + if err != nil { + if errType, ok := err.(dtos.HTTPError); ok { + if errType.Code >= http.StatusInternalServerError { + m.logger.Error(fmt.Sprintf("Error authenticating: %s", err.Error())) + return nil, common.Int64Ref(StatusRetryableError) + } + return nil, common.Int64Ref(StatusNonRetryableError) // 400, 401, etc + } + // Not an HTTP eerror, most likely a tcp/bad connection. Should retry + return nil, common.Int64Ref(StatusRetryableError) + } + if !token.PushEnabled { + return nil, common.Int64Ref(StatusNonRetryableError) + } + return token, nil +} + +func (m *ManagerImpl) eventHandler(e sse.IncomingMessage) { + newStatus, err := m.parser.ParseAndForward(e) + if newStatus != nil { + m.feedback <- *newStatus + } else if err != nil { + m.logger.Error("error parsing message: ", err) + m.logger.Debug("failed message: ", e) + m.feedback <- StatusRetryableError + } +} + +func (m *ManagerImpl) triggerConnectionFlow() { + token, status := m.performAuthentication() + if status != nil { + m.lifecycle.AbnormalShutdown() + defer m.lifecycle.ShutdownComplete() + m.feedback <- *status + return + } + + tokenList, err := token.ChannelList() + if err != nil { + m.logger.Error("error parsing channel list: ", err) + m.lifecycle.AbnormalShutdown() + defer m.lifecycle.ShutdownComplete() + m.feedback <- StatusRetryableError + return + } + + m.statusTracker.Reset() + sseStatus := make(chan int, 100) + m.sseClient.ConnectStreaming(token.Token, sseStatus, tokenList, m.eventHandler) + go func() { + defer m.lifecycle.ShutdownComplete() + if !m.lifecycle.InitializationComplete() { + return + } + for { + message := <-sseStatus + switch message { + case sse.StatusFirstEventOk: + when, err := token.CalculateNextTokenExpiration() + if err != nil || when <= 0 { + m.logger.Warning("Failed to calculate next token expiration time. Defaulting to 50 minutes") + when = 50 * time.Minute + } + m.withRefreshTokenLock(func() { + m.nextRefresh = time.AfterFunc(when, func() { + m.logger.Info("Refreshing SSE auth token.") + m.Stop() + m.Start() + }) + }) + m.feedback <- StatusUp + case sse.StatusConnectionFailed: + m.lifecycle.AbnormalShutdown() + m.logger.Error("SSE Connection failed") + m.feedback <- StatusRetryableError + return + case sse.StatusDisconnected: + m.logger.Debug("propagating sse disconnection event") + status := m.statusTracker.HandleDisconnection() + if status != nil { // connection ended unexpectedly + m.lifecycle.AbnormalShutdown() + m.feedback <- *status + } + return + case sse.StatusUnderlyingClientInUse: + m.lifecycle.AbnormalShutdown() + m.logger.Error("unexpected error in streaming. Switching to polling") + m.feedback <- StatusNonRetryableError + return + } + } + }() +} + +func (m *ManagerImpl) withRefreshTokenLock(f func()) { + m.refreshTokenMutex.Lock() + defer m.refreshTokenMutex.Unlock() + f() +} diff --git a/vendor/github.com/splitio/go-split-commons/v3/push/parser.go b/vendor/github.com/splitio/go-split-commons/v3/push/parser.go new file mode 100644 index 0000000000..28f48da7fa --- /dev/null +++ b/vendor/github.com/splitio/go-split-commons/v3/push/parser.go @@ -0,0 +1,399 @@ +package push + +import ( + "encoding/json" + "errors" + "fmt" + "strings" + + "github.com/splitio/go-split-commons/v3/service/api/sse" + + "github.com/splitio/go-toolkit/v4/logging" +) + +// SSE event type constants +const ( + SSEEventTypeSync = "sync" + SSEEventTypeMessage = "message" + SSEEventTypeError = "error" +) + +// Message type constants +const ( + MessageTypeUpdate = iota + MessageTypeControl + MessageTypeOccupancy +) + +// Update type constants +const ( + UpdateTypeSplitChange = "SPLIT_UPDATE" + UpdateTypeSplitKill = "SPLIT_KILL" + UpdateTypeSegmentChange = "SEGMENT_UPDATE" + UpdateTypeContol = "CONTROL" +) + +// Control type constants +const ( + ControlTypeStreamingEnabled = "STREAMING_ENABLED" + ControlTypeStreamingPaused = "STREAMING_PAUSED" + ControlTypeStreamingDisabled = "STREAMING_DISABLED" +) + +const ( + occupancuName = "[meta]occupancy" + occupancyPrefix = "[?occupancy=metrics.publishers]" +) + +// ErrEmptyEvent indicates an event without message and event fields +var ErrEmptyEvent = errors.New("empty incoming event") + +// NotificationParser interface +type NotificationParser interface { + ParseAndForward(sse.IncomingMessage) (*int64, error) +} + +// NotificationParserImpl implementas the NotificationParser interface +type NotificationParserImpl struct { + logger logging.LoggerInterface + onSplitUpdate func(*SplitChangeUpdate) error + onSplitKill func(*SplitKillUpdate) error + onSegmentUpdate func(*SegmentChangeUpdate) error + onControlUpdate func(*ControlUpdate) *int64 + onOccupancyMesage func(*OccupancyMessage) *int64 + onAblyError func(*AblyError) *int64 +} + +// ParseAndForward accepts an incoming RAW event and returns a properly parsed & typed event +func (p *NotificationParserImpl) ParseAndForward(raw sse.IncomingMessage) (*int64, error) { + + if raw.Event() == "" { + if raw.ID() == "" { + return nil, ErrEmptyEvent + } + // If it has ID its a sync event, which we're not using not. Ignore. + p.logger.Debug("Ignoring sync event") + return nil, nil + } + + data := genericData{} + err := json.Unmarshal([]byte(raw.Data()), &data) + if err != nil { + return nil, fmt.Errorf("error parsing JSON: %w", err) + } + + switch raw.Event() { + case SSEEventTypeError: + return p.parseError(&data) + case SSEEventTypeMessage: + return p.parseMessage(&data) + } + + return nil, nil + +} + +func (p *NotificationParserImpl) parseError(data *genericData) (*int64, error) { + return p.onAblyError(&AblyError{ + code: data.Code, + statusCode: data.StatusCode, + message: data.Message, + href: data.Href, + timestamp: data.Timestamp, + }), nil +} + +func (p *NotificationParserImpl) parseMessage(data *genericData) (*int64, error) { + var nested genericMessageData + err := json.Unmarshal([]byte(data.Data), &nested) + if err != nil { + return nil, fmt.Errorf("error parsing message nested json data: %w", err) + } + + if data.Name == occupancuName { + return p.onOccupancyMesage(&OccupancyMessage{ + BaseMessage: BaseMessage{ + timestamp: data.Timestamp, + channel: data.Channel, + }, + publishers: nested.Metrics.Publishers, + }), nil + } + + return p.parseUpdate(data, &nested) +} + +func (p *NotificationParserImpl) parseUpdate(data *genericData, nested *genericMessageData) (*int64, error) { + if data == nil || nested == nil { + return nil, errors.New("parseUpdate: data cannot be nil") + } + + base := BaseUpdate{ + BaseMessage: BaseMessage{timestamp: data.Timestamp, channel: data.Channel}, + changeNumber: nested.ChangeNumber, + } + + switch nested.Type { + case UpdateTypeSplitChange: + return nil, p.onSplitUpdate(&SplitChangeUpdate{BaseUpdate: base}) + case UpdateTypeSplitKill: + return nil, p.onSplitKill(&SplitKillUpdate{BaseUpdate: base, splitName: nested.SplitName, defaultTreatment: nested.DefaultTreatment}) + case UpdateTypeSegmentChange: + return nil, p.onSegmentUpdate(&SegmentChangeUpdate{BaseUpdate: base, segmentName: nested.SegmentName}) + case UpdateTypeContol: + return p.onControlUpdate(&ControlUpdate{BaseMessage: base.BaseMessage, controlType: nested.ControlType}), nil + default: + // TODO: log full event in debug mode + return nil, fmt.Errorf("invalid update type: %s", nested.Type) + } +} + +// Event basic interface +type Event interface { + fmt.Stringer + EventType() string + Timestamp() int64 +} + +// SSESyncEvent represents an SSE Sync event with only id (used for resuming connections) +type SSESyncEvent struct { + id string + timestamp int64 +} + +// EventType always returns SSEEventTypeSync for SSESyncEvents +func (e *SSESyncEvent) EventType() string { return SSEEventTypeSync } + +// Timestamp returns the timestamp of the event parsing +func (e *SSESyncEvent) Timestamp() int64 { return e.timestamp } + +// String returns the string represenation of the event +func (e *SSESyncEvent) String() string { + return fmt.Sprintf("SSESync(id=%s,timestamp=%d)", e.id, e.timestamp) +} + +// AblyError struct +type AblyError struct { + code int + statusCode int + message string + href string + timestamp int64 +} + +// EventType always returns SSEEventTypeError for AblyError +func (a *AblyError) EventType() string { return SSEEventTypeError } + +// Code returns the error code +func (a *AblyError) Code() int { return a.code } + +// StatusCode returns the status code +func (a *AblyError) StatusCode() int { return a.statusCode } + +// Message returns the error message +func (a *AblyError) Message() string { return a.message } + +// Href returns the documentation link +func (a *AblyError) Href() string { return a.href } + +// Timestamp returns the error timestamp +func (a *AblyError) Timestamp() int64 { return a.timestamp } + +// IsRetryable returns whether the error is recoverable via a push subsystem restart +func (a *AblyError) IsRetryable() bool { return a.code >= 40140 && a.code <= 40149 } + +// String returns the string representation of the ably error +func (a *AblyError) String() string { + return fmt.Sprintf("AblyError(code=%d,statusCode=%d,message=%s,timestamp=%d,isRetryable=%t)", + a.code, a.statusCode, a.message, a.timestamp, a.IsRetryable()) +} + +// Message basic interface +type Message interface { + Event + MessageType() int64 + Channel() string +} + +// BaseMessage contains the basic message-specific fields and methods +type BaseMessage struct { + timestamp int64 + channel string +} + +// EventType always returns SSEEventTypeMessage for BaseMessage and embedding types +func (m *BaseMessage) EventType() string { return SSEEventTypeMessage } + +// Timestamp returns the timestamp of the message reception +func (m *BaseMessage) Timestamp() int64 { return m.timestamp } + +// Channel returns which channel the message was received in +func (m *BaseMessage) Channel() string { return m.channel } + +// OccupancyMessage contains fields & methods related to ocupancy messages +type OccupancyMessage struct { + BaseMessage + publishers int64 +} + +// MessageType always returns MessageTypeOccupancy for Occupancy messages +func (o *OccupancyMessage) MessageType() int64 { return MessageTypeOccupancy } + +// ChannelWithoutPrefix returns the original channel namem without the metadata prefix +func (o *OccupancyMessage) ChannelWithoutPrefix() string { + return strings.Replace(o.Channel(), occupancyPrefix, "", 1) +} + +// Publishers returbs the amount of publishers in the current channel +func (o *OccupancyMessage) Publishers() int64 { + return o.publishers +} + +// Strings returns the string representation of an occupancy message +func (o *OccupancyMessage) String() string { + return fmt.Sprintf("Occupancy(channel=%s,publishers=%d,timestamp=%d)", + o.Channel(), o.publishers, o.Timestamp()) +} + +// Update basic interface +type Update interface { + Message + UpdateType() string + ChangeNumber() int64 +} + +// BaseUpdate contains fields & methods related to update-based messages +type BaseUpdate struct { + BaseMessage + changeNumber int64 +} + +// MessageType alwats returns MessageType for Update messages +func (b *BaseUpdate) MessageType() int64 { return MessageTypeUpdate } + +// ChangeNumber returns the changeNumber of the update +func (b *BaseUpdate) ChangeNumber() int64 { return b.changeNumber } + +// SplitChangeUpdate represents a SplitChange notification generated in the split servers +type SplitChangeUpdate struct { + BaseUpdate +} + +// UpdateType always returns UpdateTypeSplitChange for SplitKillUpdate messages +func (u *SplitChangeUpdate) UpdateType() string { return UpdateTypeSplitChange } + +// String returns the String representation of a split change notification +func (u *SplitChangeUpdate) String() string { + return fmt.Sprintf("SplitChange(channel=%s,changeNumber=%d,timestamp=%d)", + u.Channel(), u.ChangeNumber(), u.Timestamp()) +} + +// SplitKillUpdate represents a SplitKill notification generated in the split servers +type SplitKillUpdate struct { + BaseUpdate + splitName string + defaultTreatment string +} + +// UpdateType always returns UpdateTypeSplitKill for SplitKillUpdate messages +func (u *SplitKillUpdate) UpdateType() string { return UpdateTypeSplitKill } + +// SplitName returns the name of the killed split +func (u *SplitKillUpdate) SplitName() string { return u.splitName } + +// DefaultTreatment returns the last default treatment seen in the split servers for this split +func (u *SplitKillUpdate) DefaultTreatment() string { return u.defaultTreatment } + +// ToSplitChangeUpdate Maps this kill notification to a split change one +func (u *SplitKillUpdate) ToSplitChangeUpdate() *SplitChangeUpdate { + return &SplitChangeUpdate{BaseUpdate: u.BaseUpdate} +} + +// String returns the string representation of this update +func (u *SplitKillUpdate) String() string { + return fmt.Sprintf("SplitKill(channel=%s,changeNumber=%d,splitName=%s,defaultTreatment=%s,timestamp=%d)", + u.Channel(), u.ChangeNumber(), u.SplitName(), u.DefaultTreatment(), u.Timestamp()) +} + +// SegmentChangeUpdate represents a segment change notification generated in the split servers. +type SegmentChangeUpdate struct { + BaseUpdate + segmentName string +} + +// UpdateType is always UpdateTypeSegmentChange for Segmet Updates +func (u *SegmentChangeUpdate) UpdateType() string { return UpdateTypeSegmentChange } + +// SegmentName returns the name of the updated segment +func (u *SegmentChangeUpdate) SegmentName() string { return u.segmentName } + +// String returns the string representation of a segment update notification +func (u *SegmentChangeUpdate) String() string { + return fmt.Sprintf("SegmentChange(channel=%s,changeNumber=%d,segmentName=%s,timestamp=%d", + u.Channel(), u.ChangeNumber(), u.segmentName, u.Timestamp()) +} + +// ControlUpdate represents a control notification generated by the split push subsystem +type ControlUpdate struct { + BaseMessage + controlType string +} + +// MessageType always returns MessageTypeControl for Control messages +func (u *ControlUpdate) MessageType() int64 { return MessageTypeControl } + +// ControlType returns the type of control notification received +func (u *ControlUpdate) ControlType() string { return u.controlType } + +// String returns a string representation of this notification +func (u *ControlUpdate) String() string { + return fmt.Sprintf("Control(channel=%s,type=%s,timestamp=%d)", + u.Channel(), u.controlType, u.Timestamp()) +} + +type genericData struct { + + // Error associated data + Code int `json:"code"` + StatusCode int `json:"statusCode"` + Message string `json:"message"` + Href string `json:"href"` + + ClientID string `json:"clientId"` + ID string `json:"id"` + Name string `json:"name"` + Timestamp int64 `json:"timestamp"` + Encoding string `json:"encoding"` + Channel string `json:"channel"` + Data string `json:"data"` + + //"id":"tO4rXGE4CX:0:0","timestamp":1612897630627,"encoding":"json","channel":"[?occupancy=metrics.publishers]control_sec","data":"{\"metrics\":{\"publishers\":0}}","name":"[meta]occupancy"} + +} + +type metrics struct { + Publishers int64 `json:"publishers"` +} + +type genericMessageData struct { + Metrics metrics `json:"metrics"` + Type string `json:"type"` + ChangeNumber int64 `json:"changeNumber"` + SplitName string `json:"splitName"` + DefaultTreatment string `json:"defaultTreatment"` + SegmentName string `json:"segmentName"` + ControlType string `json:"controlType"` + + // {\"type\":\"SPLIT_UPDATE\",\"changeNumber\":1612909342671}"} +} + +// Compile-type assertions of interface requirements +var _ Event = &AblyError{} +var _ Message = &OccupancyMessage{} +var _ Message = &SplitChangeUpdate{} +var _ Message = &SplitKillUpdate{} +var _ Message = &SegmentChangeUpdate{} +var _ Message = &ControlUpdate{} +var _ Update = &SplitChangeUpdate{} +var _ Update = &SplitKillUpdate{} +var _ Update = &SegmentChangeUpdate{} diff --git a/vendor/github.com/splitio/go-split-commons/v3/push/processor.go b/vendor/github.com/splitio/go-split-commons/v3/push/processor.go new file mode 100644 index 0000000000..e7233d698d --- /dev/null +++ b/vendor/github.com/splitio/go-split-commons/v3/push/processor.go @@ -0,0 +1,107 @@ +package push + +import ( + "errors" + "fmt" + + "github.com/splitio/go-toolkit/v4/logging" +) + +const ( + splitQueueMinSize = 5000 + segmentQueueMinSize = 5000 +) + +// Processor provides the interface for an update-message processor +type Processor interface { + ProcessSplitChangeUpdate(update *SplitChangeUpdate) error + ProcessSplitKillUpdate(update *SplitKillUpdate) error + ProcessSegmentChangeUpdate(update *SegmentChangeUpdate) error + StartWorkers() + StopWorkers() +} + +// ProcessorImpl struct for notification processor +type ProcessorImpl struct { + segmentQueue chan SegmentChangeUpdate + splitQueue chan SplitChangeUpdate + splitWorker *SplitUpdateWorker + segmentWorker *SegmentUpdateWorker + synchronizer synchronizerInterface + logger logging.LoggerInterface +} + +// NewProcessor creates new processor +func NewProcessor( + splitQueueSize int64, + segmentQueueSize int64, + synchronizer synchronizerInterface, + logger logging.LoggerInterface, +) (*ProcessorImpl, error) { + if segmentQueueSize < segmentQueueMinSize { + return nil, errors.New("Small size of segmentQueue") + } + if splitQueueSize < splitQueueMinSize { + return nil, errors.New("Small size of splitQueue") + } + + splitQueue := make(chan SplitChangeUpdate, splitQueueSize) + splitWorker, err := NewSplitUpdateWorker(splitQueue, synchronizer, logger) + if err != nil { + return nil, fmt.Errorf("error instantiating split worker: %w", err) + } + + segmentQueue := make(chan SegmentChangeUpdate, segmentQueueSize) + segmentWorker, err := NewSegmentUpdateWorker(segmentQueue, synchronizer, logger) + if err != nil { + return nil, fmt.Errorf("error instantiating split worker: %w", err) + } + + return &ProcessorImpl{ + splitQueue: splitQueue, + splitWorker: splitWorker, + segmentQueue: segmentQueue, + segmentWorker: segmentWorker, + synchronizer: synchronizer, + logger: logger, + }, nil +} + +// ProcessSplitChangeUpdate accepts a split change notifications and schedules a fetch +func (p *ProcessorImpl) ProcessSplitChangeUpdate(update *SplitChangeUpdate) error { + if update == nil { + return errors.New("split change update cannot be nil") + } + p.splitQueue <- *update + return nil +} + +// ProcessSplitKillUpdate accepts a split kill notification, issues a local kill and schedules a fetch +func (p *ProcessorImpl) ProcessSplitKillUpdate(update *SplitKillUpdate) error { + if update == nil { + return errors.New("split change update cannot be nil") + } + p.synchronizer.LocalKill(update.SplitName(), update.DefaultTreatment(), update.ChangeNumber()) + return p.ProcessSplitChangeUpdate(update.ToSplitChangeUpdate()) +} + +// ProcessSegmentChangeUpdate accepts a segment change notification and schedules a fetch +func (p *ProcessorImpl) ProcessSegmentChangeUpdate(update *SegmentChangeUpdate) error { + if update == nil { + return errors.New("split change update cannot be nil") + } + p.segmentQueue <- *update + return nil +} + +// StartWorkers enables split & segments workers +func (p *ProcessorImpl) StartWorkers() { + p.splitWorker.Start() + p.segmentWorker.Start() +} + +// StopWorkers pauses split & segments workers +func (p *ProcessorImpl) StopWorkers() { + p.splitWorker.Stop() + p.segmentWorker.Stop() +} diff --git a/vendor/github.com/splitio/go-split-commons/v3/push/segment.go b/vendor/github.com/splitio/go-split-commons/v3/push/segment.go new file mode 100644 index 0000000000..238ac32266 --- /dev/null +++ b/vendor/github.com/splitio/go-split-commons/v3/push/segment.go @@ -0,0 +1,82 @@ +package push + +import ( + "errors" + "fmt" + "sync/atomic" + + "github.com/splitio/go-toolkit/v4/common" + "github.com/splitio/go-toolkit/v4/logging" + "github.com/splitio/go-toolkit/v4/struct/traits/lifecycle" +) + +// SegmentUpdateWorker struct +type SegmentUpdateWorker struct { + segmentQueue chan SegmentChangeUpdate + sync synchronizerInterface + logger logging.LoggerInterface + lifecycle lifecycle.Manager +} + +// NewSegmentUpdateWorker creates SegmentUpdateWorker +func NewSegmentUpdateWorker( + segmentQueue chan SegmentChangeUpdate, + synchronizer synchronizerInterface, + logger logging.LoggerInterface, +) (*SegmentUpdateWorker, error) { + if cap(segmentQueue) < 5000 { + return nil, errors.New("") + } + running := atomic.Value{} + running.Store(false) + + worker := &SegmentUpdateWorker{ + segmentQueue: segmentQueue, + sync: synchronizer, + logger: logger, + } + worker.lifecycle.Setup() + return worker, nil +} + +// Start starts worker +func (s *SegmentUpdateWorker) Start() { + if !s.lifecycle.BeginInitialization() { + s.logger.Info("Segment worker is already running") + return + } + + go func() { + if !s.lifecycle.InitializationComplete() { + return + } + defer s.lifecycle.ShutdownComplete() + for { + select { + case segmentUpdate := <-s.segmentQueue: + s.logger.Debug("Received Segment update and proceding to perform fetch") + s.logger.Debug(fmt.Sprintf("SegmentName: %s\nChangeNumber: %d", segmentUpdate.SegmentName(), segmentUpdate.ChangeNumber())) + err := s.sync.SynchronizeSegment(segmentUpdate.SegmentName(), common.Int64Ref(segmentUpdate.ChangeNumber()), true) + if err != nil { + s.logger.Error(err) + } + case <-s.lifecycle.ShutdownRequested(): + return + } + } + }() +} + +// Stop stops worker +func (s *SegmentUpdateWorker) Stop() { + if !s.lifecycle.BeginShutdown() { + s.logger.Debug("Split worker not runnning. Ignoring.") + return + } + s.lifecycle.AwaitShutdownComplete() +} + +// IsRunning indicates if worker is running or not +func (s *SegmentUpdateWorker) IsRunning() bool { + return s.lifecycle.IsRunning() +} diff --git a/vendor/github.com/splitio/go-split-commons/v3/push/split.go b/vendor/github.com/splitio/go-split-commons/v3/push/split.go new file mode 100644 index 0000000000..472ba9c727 --- /dev/null +++ b/vendor/github.com/splitio/go-split-commons/v3/push/split.go @@ -0,0 +1,80 @@ +package push + +import ( + "errors" + "fmt" + + "github.com/splitio/go-toolkit/v4/common" + "github.com/splitio/go-toolkit/v4/logging" + "github.com/splitio/go-toolkit/v4/struct/traits/lifecycle" +) + +// SplitUpdateWorker struct +type SplitUpdateWorker struct { + splitQueue chan SplitChangeUpdate + sync synchronizerInterface + logger logging.LoggerInterface + lifecycle lifecycle.Manager +} + +// NewSplitUpdateWorker creates SplitUpdateWorker +func NewSplitUpdateWorker( + splitQueue chan SplitChangeUpdate, + synchronizer synchronizerInterface, + logger logging.LoggerInterface, +) (*SplitUpdateWorker, error) { + if cap(splitQueue) < 5000 { + return nil, errors.New("") + } + + worker := &SplitUpdateWorker{ + splitQueue: splitQueue, + sync: synchronizer, + logger: logger, + } + worker.lifecycle.Setup() + return worker, nil +} + +// Start starts worker +func (s *SplitUpdateWorker) Start() { + if !s.lifecycle.BeginInitialization() { + s.logger.Info("Split worker is already running") + return + } + + s.logger.Debug("Started SplitUpdateWorker") + go func() { + defer s.lifecycle.ShutdownComplete() + if !s.lifecycle.InitializationComplete() { + return + } + for { + select { + case splitUpdate := <-s.splitQueue: + s.logger.Debug("Received Split update and proceding to perform fetch") + s.logger.Debug(fmt.Sprintf("ChangeNumber: %d", splitUpdate.ChangeNumber())) + err := s.sync.SynchronizeSplits(common.Int64Ref(splitUpdate.ChangeNumber()), true) + if err != nil { + s.logger.Error(err) + } + case <-s.lifecycle.ShutdownRequested(): + return + } + } + }() +} + +// Stop stops worker +func (s *SplitUpdateWorker) Stop() { + if !s.lifecycle.BeginShutdown() { + s.logger.Debug("Split worker not runnning. Ignoring.") + return + } + s.lifecycle.AwaitShutdownComplete() +} + +// IsRunning indicates if worker is running or not +func (s *SplitUpdateWorker) IsRunning() bool { + return s.lifecycle.IsRunning() +} diff --git a/vendor/github.com/splitio/go-split-commons/v3/push/statustracker.go b/vendor/github.com/splitio/go-split-commons/v3/push/statustracker.go new file mode 100644 index 0000000000..411af12300 --- /dev/null +++ b/vendor/github.com/splitio/go-split-commons/v3/push/statustracker.go @@ -0,0 +1,158 @@ +package push + +import ( + "fmt" + "sync" + + "github.com/splitio/go-toolkit/v4/common" + "github.com/splitio/go-toolkit/v4/logging" +) + +// StatusTracker keeps track of the status of the push subsystem and generates appropriate status change notifications. +type StatusTracker interface { + HandleOccupancy(*OccupancyMessage) *int64 + HandleControl(*ControlUpdate) *int64 + HandleAblyError(*AblyError) *int64 + HandleDisconnection() *int64 + NotifySSEShutdownExpected() + Reset() +} + +// StatusTrackerImpl is a concrete implementation of the StatusTracker interface +type StatusTrackerImpl struct { + logger logging.LoggerInterface + mutex sync.Mutex + occupancy map[string]int64 + lastControlTimestamp int64 + lastOccupancyTimestamp int64 + lastControlMessage string + lastStatusPropagated int64 + shutdownExpected bool +} + +// NotifySSEShutdownExpected should be called when we are forcefully closing the SSE client +func (p *StatusTrackerImpl) NotifySSEShutdownExpected() { + p.mutex.Lock() + defer p.mutex.Unlock() + p.shutdownExpected = true +} + +// Reset should be called on initialization and when the a new connection is being established (to start from scratch) +func (p *StatusTrackerImpl) Reset() { + p.mutex.Lock() + defer p.mutex.Unlock() + p.occupancy = map[string]int64{"control_pri": 2, "control_sec": 2} + p.lastControlMessage = ControlTypeStreamingEnabled + p.lastStatusPropagated = StatusUp + p.shutdownExpected = false +} + +// HandleOccupancy should be called for every occupancy notification received +func (p *StatusTrackerImpl) HandleOccupancy(message *OccupancyMessage) (newStatus *int64) { + p.mutex.Lock() + defer p.mutex.Unlock() + if p.shutdownExpected { + return nil // we don't care about occupancy if we're disconnecting + } + + channel := message.ChannelWithoutPrefix() + if _, ok := p.occupancy[channel]; !ok { + p.logger.Warning(fmt.Sprintf("received occupancy on non-registered channel '%s'. Ignoring", channel)) + return nil + } + + p.lastOccupancyTimestamp = message.Timestamp() + p.occupancy[channel] = message.Publishers() + return p.updateStatus() +} + +// HandleAblyError should be called whenever an ably error is received +func (p *StatusTrackerImpl) HandleAblyError(errorEvent *AblyError) (newStatus *int64) { + p.mutex.Lock() + defer p.mutex.Unlock() + if p.shutdownExpected { + return nil // we don't care about occupancy if we're disconnecting + } + + // Regardless of whether the error is retryable or not, we're going to close the connection + p.shutdownExpected = true + + if errorEvent.IsRetryable() { + p.logger.Info("Received retryable error message. Restarting SSE connection with backoff") + return p.propagateStatus(StatusRetryableError) + } + + p.logger.Info("Received non-retryable error message. Disabling streaming") + return p.propagateStatus(StatusNonRetryableError) +} + +// HandleControl should be called whenever a control notification is received +func (p *StatusTrackerImpl) HandleControl(controlUpdate *ControlUpdate) *int64 { + p.mutex.Lock() + defer p.mutex.Unlock() + if p.shutdownExpected { + return nil // we don't care about occupancy if we're disconnecting + } + + if p.lastControlTimestamp > controlUpdate.timestamp { + p.logger.Warning("Received an old control update. Ignoring") + return nil + } + + p.lastControlMessage = controlUpdate.controlType + p.lastControlTimestamp = controlUpdate.timestamp + return p.updateStatus() +} + +// HandleDisconnection should be called whenver the SSE client gets disconnected +func (p *StatusTrackerImpl) HandleDisconnection() *int64 { + p.mutex.Lock() + defer p.mutex.Unlock() + if !p.shutdownExpected { + return p.propagateStatus(StatusRetryableError) + } + return nil +} + +// NewStatusTracker returns a new StatusTracker +func NewStatusTracker(logger logging.LoggerInterface) *StatusTrackerImpl { + tracker := &StatusTrackerImpl{logger: logger} + tracker.Reset() + return tracker +} + +func (p *StatusTrackerImpl) occupancyOk() bool { + for _, v := range p.occupancy { + if v > 0 { + return true + } + } + return false +} + +func (p *StatusTrackerImpl) updateStatus() *int64 { + if p.lastStatusPropagated == StatusUp { + if !p.occupancyOk() || p.lastControlMessage == ControlTypeStreamingPaused { + return p.propagateStatus(StatusDown) + } + if p.lastControlMessage == ControlTypeStreamingDisabled { + return p.propagateStatus(StatusNonRetryableError) + } + } + if p.lastStatusPropagated == StatusDown { + if p.occupancyOk() && p.lastControlMessage == ControlTypeStreamingEnabled { + return p.propagateStatus(StatusUp) + } + if p.lastControlMessage == ControlTypeStreamingDisabled { + return p.propagateStatus(StatusNonRetryableError) + } + } + return nil +} + +func (p *StatusTrackerImpl) propagateStatus(newStatus int64) *int64 { + p.lastStatusPropagated = newStatus + return common.Int64Ref(newStatus) +} + +var _ StatusTracker = &StatusTrackerImpl{} diff --git a/vendor/github.com/splitio/go-split-commons/v2/service/api/auth.go b/vendor/github.com/splitio/go-split-commons/v3/service/api/auth.go similarity index 78% rename from vendor/github.com/splitio/go-split-commons/v2/service/api/auth.go rename to vendor/github.com/splitio/go-split-commons/v3/service/api/auth.go index 6451ebb1de..8ee192c985 100644 --- a/vendor/github.com/splitio/go-split-commons/v2/service/api/auth.go +++ b/vendor/github.com/splitio/go-split-commons/v3/service/api/auth.go @@ -3,9 +3,9 @@ package api import ( "encoding/json" - "github.com/splitio/go-split-commons/v2/conf" - "github.com/splitio/go-split-commons/v2/dtos" - "github.com/splitio/go-toolkit/v3/logging" + "github.com/splitio/go-split-commons/v3/conf" + "github.com/splitio/go-split-commons/v3/dtos" + "github.com/splitio/go-toolkit/v4/logging" ) // AuthAPIClient struct is responsible for authenticating client for push services @@ -24,7 +24,7 @@ func NewAuthAPIClient(apikey string, cfg conf.AdvancedConfig, logger logging.Log // Authenticate performs authentication for push services func (a *AuthAPIClient) Authenticate() (*dtos.Token, error) { - raw, err := a.client.Get("/api/auth") + raw, err := a.client.Get("/api/auth", map[string]string{CacheControlHeader: CacheControlNoCache}) if err != nil { a.logger.Error("Error while authenticating for streaming", err) return nil, err diff --git a/vendor/github.com/splitio/go-split-commons/v2/service/api/client.go b/vendor/github.com/splitio/go-split-commons/v3/service/api/client.go similarity index 85% rename from vendor/github.com/splitio/go-split-commons/v2/service/api/client.go rename to vendor/github.com/splitio/go-split-commons/v3/service/api/client.go index 27ddcd6b75..e35ca0ebf8 100644 --- a/vendor/github.com/splitio/go-split-commons/v2/service/api/client.go +++ b/vendor/github.com/splitio/go-split-commons/v3/service/api/client.go @@ -9,14 +9,20 @@ import ( "net/http" "time" - "github.com/splitio/go-split-commons/v2/conf" - "github.com/splitio/go-split-commons/v2/dtos" - "github.com/splitio/go-toolkit/v3/logging" + "github.com/splitio/go-split-commons/v3/conf" + "github.com/splitio/go-split-commons/v3/dtos" + "github.com/splitio/go-toolkit/v4/logging" +) + +// Cache control header constants +const ( + CacheControlHeader = "Cache-Control" + CacheControlNoCache = "no-cache" ) // Client interface for HTTPClient type Client interface { - Get(service string) ([]byte, error) + Get(service string, headers map[string]string) ([]byte, error) Post(service string, body []byte, headers map[string]string) error } @@ -51,7 +57,7 @@ func NewHTTPClient( } // Get method is a get call to an url -func (c *HTTPClient) Get(service string) ([]byte, error) { +func (c *HTTPClient) Get(service string, headers map[string]string) ([]byte, error) { serviceURL := c.url + service c.logger.Debug("[GET] ", serviceURL) req, _ := http.NewRequest("GET", serviceURL, nil) @@ -60,15 +66,18 @@ func (c *HTTPClient) Get(service string) ([]byte, error) { c.logger.Debug("Authorization [ApiKey]: ", logging.ObfuscateAPIKey(authorization)) req.Header.Add("Accept-Encoding", "gzip") req.Header.Add("Content-Type", "application/json") + req.Header.Add("SplitSDKVersion", c.metadata.SDKVersion) + req.Header.Add("SplitSDKMachineName", c.metadata.MachineName) + req.Header.Add("SplitSDKMachineIP", c.metadata.MachineIP) + + for headerName, headerValue := range headers { + req.Header.Add(headerName, headerValue) + } c.logger.Debug(fmt.Sprintf("Headers: %v", req.Header)) req.Header.Add("Authorization", "Bearer "+authorization) - req.Header.Add("SplitSDKVersion", c.metadata.SDKVersion) - req.Header.Add("SplitSDKMachineName", c.metadata.MachineName) - req.Header.Add("SplitSDKMachineIP", c.metadata.MachineIP) - resp, err := c.httpClient.Do(req) if err != nil { c.logger.Error("Error requesting data to API: ", req.URL.String(), err.Error()) @@ -80,7 +89,10 @@ func (c *HTTPClient) Get(service string) ([]byte, error) { var reader io.ReadCloser switch resp.Header.Get("Content-Encoding") { case "gzip": - reader, _ = gzip.NewReader(resp.Body) + reader, err = gzip.NewReader(resp.Body) + if err != nil { + return nil, fmt.Errorf("error parsing gzip resopnse body: %w", err) + } defer reader.Close() default: reader = resp.Body diff --git a/vendor/github.com/splitio/go-split-commons/v2/service/api/http_fetchers.go b/vendor/github.com/splitio/go-split-commons/v3/service/api/http_fetchers.go similarity index 76% rename from vendor/github.com/splitio/go-split-commons/v2/service/api/http_fetchers.go rename to vendor/github.com/splitio/go-split-commons/v3/service/api/http_fetchers.go index 8e7859f500..d7b0d33ddc 100644 --- a/vendor/github.com/splitio/go-split-commons/v2/service/api/http_fetchers.go +++ b/vendor/github.com/splitio/go-split-commons/v3/service/api/http_fetchers.go @@ -5,9 +5,9 @@ import ( "encoding/json" "strconv" - "github.com/splitio/go-split-commons/v2/conf" - "github.com/splitio/go-split-commons/v2/dtos" - "github.com/splitio/go-toolkit/v3/logging" + "github.com/splitio/go-split-commons/v3/conf" + "github.com/splitio/go-split-commons/v3/dtos" + "github.com/splitio/go-toolkit/v4/logging" ) type httpFetcherBase struct { @@ -15,7 +15,7 @@ type httpFetcherBase struct { logger logging.LoggerInterface } -func (h *httpFetcherBase) fetchRaw(url string, since int64) ([]byte, error) { +func (h *httpFetcherBase) fetchRaw(url string, since int64, requestNoCache bool) ([]byte, error) { var bufferQuery bytes.Buffer bufferQuery.WriteString(url) @@ -23,7 +23,12 @@ func (h *httpFetcherBase) fetchRaw(url string, since int64) ([]byte, error) { bufferQuery.WriteString("?since=") bufferQuery.WriteString(strconv.FormatInt(since, 10)) } - data, err := h.client.Get(bufferQuery.String()) + + var extraHeaders map[string]string + if requestNoCache { + extraHeaders = map[string]string{CacheControlHeader: CacheControlNoCache} + } + data, err := h.client.Get(bufferQuery.String(), extraHeaders) if err != nil { return nil, err } @@ -51,8 +56,8 @@ func NewHTTPSplitFetcher( } // Fetch makes an http call to the split backend and returns the list of updated splits -func (f *HTTPSplitFetcher) Fetch(since int64) (*dtos.SplitChangesDTO, error) { - data, err := f.fetchRaw("/splitChanges", since) +func (f *HTTPSplitFetcher) Fetch(since int64, requestNoCache bool) (*dtos.SplitChangesDTO, error) { + data, err := f.fetchRaw("/splitChanges", since, requestNoCache) if err != nil { f.logger.Error("Error fetching split changes ", err) return nil, err @@ -89,12 +94,12 @@ func NewHTTPSegmentFetcher( } // Fetch issues a GET request to the split backend and returns the contents of a particular segment -func (f *HTTPSegmentFetcher) Fetch(segmentName string, since int64) (*dtos.SegmentChangesDTO, error) { +func (f *HTTPSegmentFetcher) Fetch(segmentName string, since int64, requestNoCache bool) (*dtos.SegmentChangesDTO, error) { var bufferQuery bytes.Buffer bufferQuery.WriteString("/segmentChanges/") bufferQuery.WriteString(segmentName) - data, err := f.fetchRaw(bufferQuery.String(), since) + data, err := f.fetchRaw(bufferQuery.String(), since, requestNoCache) if err != nil { f.logger.Error(err.Error()) return nil, err diff --git a/vendor/github.com/splitio/go-split-commons/v2/service/api/http_recorders.go b/vendor/github.com/splitio/go-split-commons/v3/service/api/http_recorders.go similarity index 97% rename from vendor/github.com/splitio/go-split-commons/v2/service/api/http_recorders.go rename to vendor/github.com/splitio/go-split-commons/v3/service/api/http_recorders.go index 06b2ac8bdb..0512c81265 100644 --- a/vendor/github.com/splitio/go-split-commons/v2/service/api/http_recorders.go +++ b/vendor/github.com/splitio/go-split-commons/v3/service/api/http_recorders.go @@ -3,9 +3,9 @@ package api import ( "encoding/json" - "github.com/splitio/go-split-commons/v2/conf" - "github.com/splitio/go-split-commons/v2/dtos" - "github.com/splitio/go-toolkit/v3/logging" + "github.com/splitio/go-split-commons/v3/conf" + "github.com/splitio/go-split-commons/v3/dtos" + "github.com/splitio/go-toolkit/v4/logging" ) type httpRecorderBase struct { diff --git a/vendor/github.com/splitio/go-split-commons/v3/service/api/sse/client.go b/vendor/github.com/splitio/go-split-commons/v3/service/api/sse/client.go new file mode 100644 index 0000000000..e7ce303b66 --- /dev/null +++ b/vendor/github.com/splitio/go-split-commons/v3/service/api/sse/client.go @@ -0,0 +1,123 @@ +package sse + +import ( + "errors" + "strings" + + "github.com/splitio/go-split-commons/v3/conf" + "github.com/splitio/go-toolkit/v4/logging" + "github.com/splitio/go-toolkit/v4/sse" + "github.com/splitio/go-toolkit/v4/struct/traits/lifecycle" + gtSync "github.com/splitio/go-toolkit/v4/sync" +) + +const ( + version = "1.1" + keepAlive = 70 +) + +// StreamingClient interface +type StreamingClient interface { + ConnectStreaming(token string, streamingStatus chan int, channelList []string, handleIncomingMessage func(IncomingMessage)) + StopStreaming() + IsRunning() bool +} + +// StreamingClientImpl struct +type StreamingClientImpl struct { + sseClient *sse.Client + logger logging.LoggerInterface + lifecycle lifecycle.Manager +} + +// Status constants +const ( + StatusConnectionFailed = iota + StatusUnderlyingClientInUse + StatusFirstEventOk + StatusDisconnected +) + +// IncomingMessage is an alias of sse.RawEvent +type IncomingMessage = sse.RawEvent + +// NewStreamingClient creates new SSE Client +func NewStreamingClient(cfg *conf.AdvancedConfig, logger logging.LoggerInterface) *StreamingClientImpl { + sseClient, _ := sse.NewClient(cfg.StreamingServiceURL, keepAlive, logger) + + client := &StreamingClientImpl{ + sseClient: sseClient, + logger: logger, + } + client.lifecycle.Setup() + return client +} + +// ConnectStreaming connects to streaming +func (s *StreamingClientImpl) ConnectStreaming(token string, streamingStatus chan int, channelList []string, handleIncomingMessage func(IncomingMessage)) { + + if !s.lifecycle.BeginInitialization() { + s.logger.Info("Connection is already in process/running. Ignoring") + return + } + + params := make(map[string]string) + params["channels"] = strings.Join(append(channelList), ",") + params["accessToken"] = token + params["v"] = version + + go func() { + defer s.lifecycle.ShutdownComplete() + if !s.lifecycle.InitializationComplete() { + return + } + firstEventReceived := gtSync.NewAtomicBool(false) + out := s.sseClient.Do(params, func(m IncomingMessage) { + if firstEventReceived.TestAndSet() && !m.IsError() { + streamingStatus <- StatusFirstEventOk + } + handleIncomingMessage(m) + }) + + if out == nil { // all good + streamingStatus <- StatusDisconnected + return + } + + // Something didn'g go as expected + s.lifecycle.AbnormalShutdown() + + asConnectionFailedError := &sse.ErrConnectionFailed{} + if errors.As(out, &asConnectionFailedError) { + streamingStatus <- StatusConnectionFailed + return + } + + switch out { + case sse.ErrNotIdle: + // If this happens we have a bug + streamingStatus <- StatusUnderlyingClientInUse + case sse.ErrReadingStream: + streamingStatus <- StatusDisconnected + case sse.ErrTimeout: + streamingStatus <- StatusDisconnected + default: + } + }() +} + +// StopStreaming stops streaming +func (s *StreamingClientImpl) StopStreaming() { + if !s.lifecycle.BeginShutdown() { + s.logger.Info("SSE client wrapper not running. Ignoring") + return + } + s.sseClient.Shutdown(true) + s.lifecycle.AwaitShutdownComplete() + s.logger.Info("Stopped streaming") +} + +// IsRunning returns true if the client is running +func (s *StreamingClientImpl) IsRunning() bool { + return s.lifecycle.IsRunning() +} diff --git a/vendor/github.com/splitio/go-split-commons/v2/service/interfaces.go b/vendor/github.com/splitio/go-split-commons/v3/service/interfaces.go similarity index 83% rename from vendor/github.com/splitio/go-split-commons/v2/service/interfaces.go rename to vendor/github.com/splitio/go-split-commons/v3/service/interfaces.go index 0daeefae16..a46ceaebab 100644 --- a/vendor/github.com/splitio/go-split-commons/v2/service/interfaces.go +++ b/vendor/github.com/splitio/go-split-commons/v3/service/interfaces.go @@ -1,7 +1,7 @@ package service import ( - "github.com/splitio/go-split-commons/v2/dtos" + "github.com/splitio/go-split-commons/v3/dtos" ) // AuthClient inteface to be implemneted by AuthClient @@ -11,12 +11,12 @@ type AuthClient interface { // SplitFetcher interface to be implemented by Split Fetchers type SplitFetcher interface { - Fetch(changeNumber int64) (*dtos.SplitChangesDTO, error) + Fetch(changeNumber int64, requstNoCache bool) (*dtos.SplitChangesDTO, error) } // SegmentFetcher interface to be implemented by Split Fetchers type SegmentFetcher interface { - Fetch(name string, changeNumber int64) (*dtos.SegmentChangesDTO, error) + Fetch(name string, changeNumber int64, requestNoCace bool) (*dtos.SegmentChangesDTO, error) } // ImpressionsRecorder interface to be implemented by Impressions loggers diff --git a/vendor/github.com/splitio/go-split-commons/v2/service/local/splitFetcher.go b/vendor/github.com/splitio/go-split-commons/v3/service/local/splitFetcher.go similarity index 95% rename from vendor/github.com/splitio/go-split-commons/v2/service/local/splitFetcher.go rename to vendor/github.com/splitio/go-split-commons/v3/service/local/splitFetcher.go index 638c5f611d..1c470d4938 100644 --- a/vendor/github.com/splitio/go-split-commons/v2/service/local/splitFetcher.go +++ b/vendor/github.com/splitio/go-split-commons/v3/service/local/splitFetcher.go @@ -8,8 +8,9 @@ import ( "runtime/debug" "strings" - "github.com/splitio/go-split-commons/v2/dtos" - "github.com/splitio/go-toolkit/v3/logging" + "github.com/splitio/go-split-commons/v3/dtos" + "github.com/splitio/go-split-commons/v3/service" + "github.com/splitio/go-toolkit/v4/logging" yaml "gopkg.in/yaml.v2" ) @@ -222,7 +223,7 @@ func parseSplitsYAML(data string) (d []dtos.SplitDTO) { } // Fetch parses the file and returns the appropriate structures -func (s *FileSplitFetcher) Fetch(changeNumber int64) (*dtos.SplitChangesDTO, error) { +func (s *FileSplitFetcher) Fetch(changeNumber int64, _ bool) (*dtos.SplitChangesDTO, error) { fileContents, err := ioutil.ReadFile(s.splitFile) if err != nil { return nil, err @@ -256,3 +257,5 @@ func (s *FileSplitFetcher) Fetch(changeNumber int64) (*dtos.SplitChangesDTO, err Till: till, }, nil } + +var _ service.SplitFetcher = &FileSplitFetcher{} diff --git a/vendor/github.com/splitio/go-split-commons/v2/service/split.go b/vendor/github.com/splitio/go-split-commons/v3/service/split.go similarity index 83% rename from vendor/github.com/splitio/go-split-commons/v2/service/split.go rename to vendor/github.com/splitio/go-split-commons/v3/service/split.go index 04cdf691b8..da68deb27e 100644 --- a/vendor/github.com/splitio/go-split-commons/v2/service/split.go +++ b/vendor/github.com/splitio/go-split-commons/v3/service/split.go @@ -1,10 +1,10 @@ package service import ( - "github.com/splitio/go-split-commons/v2/conf" - "github.com/splitio/go-split-commons/v2/dtos" - "github.com/splitio/go-split-commons/v2/service/api" - "github.com/splitio/go-toolkit/v3/logging" + "github.com/splitio/go-split-commons/v3/conf" + "github.com/splitio/go-split-commons/v3/dtos" + "github.com/splitio/go-split-commons/v3/service/api" + "github.com/splitio/go-toolkit/v4/logging" ) // SplitAPI struct for fetchers and recorders diff --git a/vendor/github.com/splitio/go-split-commons/v2/storage/interfaces.go b/vendor/github.com/splitio/go-split-commons/v3/storage/interfaces.go similarity index 97% rename from vendor/github.com/splitio/go-split-commons/v2/storage/interfaces.go rename to vendor/github.com/splitio/go-split-commons/v3/storage/interfaces.go index 674df3d73d..5fd848db5d 100644 --- a/vendor/github.com/splitio/go-split-commons/v2/storage/interfaces.go +++ b/vendor/github.com/splitio/go-split-commons/v3/storage/interfaces.go @@ -1,8 +1,8 @@ package storage import ( - "github.com/splitio/go-split-commons/v2/dtos" - "github.com/splitio/go-toolkit/v3/datastructures/set" + "github.com/splitio/go-split-commons/v3/dtos" + "github.com/splitio/go-toolkit/v4/datastructures/set" ) // SplitStorageProducer should be implemented by structs that offer writing splits in storage diff --git a/vendor/github.com/splitio/go-split-commons/v2/storage/metricWrapper.go b/vendor/github.com/splitio/go-split-commons/v3/storage/metricWrapper.go similarity index 98% rename from vendor/github.com/splitio/go-split-commons/v2/storage/metricWrapper.go rename to vendor/github.com/splitio/go-split-commons/v3/storage/metricWrapper.go index 03010f7f79..a3df3fcfe1 100644 --- a/vendor/github.com/splitio/go-split-commons/v2/storage/metricWrapper.go +++ b/vendor/github.com/splitio/go-split-commons/v3/storage/metricWrapper.go @@ -4,7 +4,7 @@ import ( "errors" "strings" - "github.com/splitio/go-toolkit/v3/logging" + "github.com/splitio/go-toolkit/v4/logging" ) // MetricWrapper struct diff --git a/vendor/github.com/splitio/go-split-commons/v2/storage/mocks/event.go b/vendor/github.com/splitio/go-split-commons/v3/storage/mocks/event.go similarity index 95% rename from vendor/github.com/splitio/go-split-commons/v2/storage/mocks/event.go rename to vendor/github.com/splitio/go-split-commons/v3/storage/mocks/event.go index 1b145630f5..3dad65cf18 100644 --- a/vendor/github.com/splitio/go-split-commons/v2/storage/mocks/event.go +++ b/vendor/github.com/splitio/go-split-commons/v3/storage/mocks/event.go @@ -1,6 +1,6 @@ package mocks -import "github.com/splitio/go-split-commons/v2/dtos" +import "github.com/splitio/go-split-commons/v3/dtos" // MockEventStorage is a mocked implementation of Event Storage type MockEventStorage struct { diff --git a/vendor/github.com/splitio/go-split-commons/v2/storage/mocks/impression.go b/vendor/github.com/splitio/go-split-commons/v3/storage/mocks/impression.go similarity index 95% rename from vendor/github.com/splitio/go-split-commons/v2/storage/mocks/impression.go rename to vendor/github.com/splitio/go-split-commons/v3/storage/mocks/impression.go index 88334ab0ae..ce9db40cd3 100644 --- a/vendor/github.com/splitio/go-split-commons/v2/storage/mocks/impression.go +++ b/vendor/github.com/splitio/go-split-commons/v3/storage/mocks/impression.go @@ -1,6 +1,6 @@ package mocks -import "github.com/splitio/go-split-commons/v2/dtos" +import "github.com/splitio/go-split-commons/v3/dtos" // MockImpressionStorage is a mocked implementation of Impression Storage type MockImpressionStorage struct { diff --git a/vendor/github.com/splitio/go-split-commons/v2/storage/mocks/metric.go b/vendor/github.com/splitio/go-split-commons/v3/storage/mocks/metric.go similarity index 97% rename from vendor/github.com/splitio/go-split-commons/v2/storage/mocks/metric.go rename to vendor/github.com/splitio/go-split-commons/v3/storage/mocks/metric.go index 5c65986f6f..0fd59d2cba 100644 --- a/vendor/github.com/splitio/go-split-commons/v2/storage/mocks/metric.go +++ b/vendor/github.com/splitio/go-split-commons/v3/storage/mocks/metric.go @@ -1,6 +1,6 @@ package mocks -import "github.com/splitio/go-split-commons/v2/dtos" +import "github.com/splitio/go-split-commons/v3/dtos" // MockMetricStorage is a mocked implementation of Metric Storage type MockMetricStorage struct { diff --git a/vendor/github.com/splitio/go-split-commons/v2/storage/mocks/segment.go b/vendor/github.com/splitio/go-split-commons/v3/storage/mocks/segment.go similarity index 96% rename from vendor/github.com/splitio/go-split-commons/v2/storage/mocks/segment.go rename to vendor/github.com/splitio/go-split-commons/v3/storage/mocks/segment.go index fe2feeabcb..ed8bc6da77 100644 --- a/vendor/github.com/splitio/go-split-commons/v2/storage/mocks/segment.go +++ b/vendor/github.com/splitio/go-split-commons/v3/storage/mocks/segment.go @@ -1,6 +1,6 @@ package mocks -import "github.com/splitio/go-toolkit/v3/datastructures/set" +import "github.com/splitio/go-toolkit/v4/datastructures/set" // MockSegmentStorage is a mocked implementation of Segment Storage type MockSegmentStorage struct { diff --git a/vendor/github.com/splitio/go-split-commons/v2/storage/mocks/split.go b/vendor/github.com/splitio/go-split-commons/v3/storage/mocks/split.go similarity index 95% rename from vendor/github.com/splitio/go-split-commons/v2/storage/mocks/split.go rename to vendor/github.com/splitio/go-split-commons/v3/storage/mocks/split.go index 3ffc8fa4e1..ea68f037d5 100644 --- a/vendor/github.com/splitio/go-split-commons/v2/storage/mocks/split.go +++ b/vendor/github.com/splitio/go-split-commons/v3/storage/mocks/split.go @@ -1,8 +1,8 @@ package mocks import ( - "github.com/splitio/go-split-commons/v2/dtos" - "github.com/splitio/go-toolkit/v3/datastructures/set" + "github.com/splitio/go-split-commons/v3/dtos" + "github.com/splitio/go-toolkit/v4/datastructures/set" ) // MockSplitStorage is a mocked implementation of Split Storage diff --git a/vendor/github.com/splitio/go-split-commons/v2/storage/mutexmap/metrics.go b/vendor/github.com/splitio/go-split-commons/v3/storage/mutexmap/metrics.go similarity index 98% rename from vendor/github.com/splitio/go-split-commons/v2/storage/mutexmap/metrics.go rename to vendor/github.com/splitio/go-split-commons/v3/storage/mutexmap/metrics.go index aa918ceb0e..2e7f376eec 100644 --- a/vendor/github.com/splitio/go-split-commons/v2/storage/mutexmap/metrics.go +++ b/vendor/github.com/splitio/go-split-commons/v3/storage/mutexmap/metrics.go @@ -3,7 +3,7 @@ package mutexmap import ( "sync" - "github.com/splitio/go-split-commons/v2/dtos" + "github.com/splitio/go-split-commons/v3/dtos" ) // MMMetricsStorage contains an in-memory implementation of Metrics storage diff --git a/vendor/github.com/splitio/go-split-commons/v2/storage/mutexmap/segments.go b/vendor/github.com/splitio/go-split-commons/v3/storage/mutexmap/segments.go similarity index 97% rename from vendor/github.com/splitio/go-split-commons/v2/storage/mutexmap/segments.go rename to vendor/github.com/splitio/go-split-commons/v3/storage/mutexmap/segments.go index f094e11c0f..46731658e5 100644 --- a/vendor/github.com/splitio/go-split-commons/v2/storage/mutexmap/segments.go +++ b/vendor/github.com/splitio/go-split-commons/v3/storage/mutexmap/segments.go @@ -4,7 +4,7 @@ import ( "fmt" "sync" - "github.com/splitio/go-toolkit/v3/datastructures/set" + "github.com/splitio/go-toolkit/v4/datastructures/set" ) // MMSegmentStorage contains is an in-memory implementation of segment storage diff --git a/vendor/github.com/splitio/go-split-commons/v2/storage/mutexmap/splits.go b/vendor/github.com/splitio/go-split-commons/v3/storage/mutexmap/splits.go similarity index 98% rename from vendor/github.com/splitio/go-split-commons/v2/storage/mutexmap/splits.go rename to vendor/github.com/splitio/go-split-commons/v3/storage/mutexmap/splits.go index 5278105b83..fb4a0cd273 100644 --- a/vendor/github.com/splitio/go-split-commons/v2/storage/mutexmap/splits.go +++ b/vendor/github.com/splitio/go-split-commons/v3/storage/mutexmap/splits.go @@ -3,8 +3,8 @@ package mutexmap import ( "sync" - "github.com/splitio/go-split-commons/v2/dtos" - "github.com/splitio/go-toolkit/v3/datastructures/set" + "github.com/splitio/go-split-commons/v3/dtos" + "github.com/splitio/go-toolkit/v4/datastructures/set" ) // MMSplitStorage struct contains is an in-memory implementation of split storage diff --git a/vendor/github.com/splitio/go-split-commons/v2/storage/mutexqueue/constants.go b/vendor/github.com/splitio/go-split-commons/v3/storage/mutexqueue/constants.go similarity index 100% rename from vendor/github.com/splitio/go-split-commons/v2/storage/mutexqueue/constants.go rename to vendor/github.com/splitio/go-split-commons/v3/storage/mutexqueue/constants.go diff --git a/vendor/github.com/splitio/go-split-commons/v2/storage/mutexqueue/events.go b/vendor/github.com/splitio/go-split-commons/v3/storage/mutexqueue/events.go similarity index 97% rename from vendor/github.com/splitio/go-split-commons/v2/storage/mutexqueue/events.go rename to vendor/github.com/splitio/go-split-commons/v3/storage/mutexqueue/events.go index 70565861ae..b16cff7d2d 100644 --- a/vendor/github.com/splitio/go-split-commons/v2/storage/mutexqueue/events.go +++ b/vendor/github.com/splitio/go-split-commons/v3/storage/mutexqueue/events.go @@ -5,8 +5,8 @@ import ( "fmt" "sync" - "github.com/splitio/go-split-commons/v2/dtos" - "github.com/splitio/go-toolkit/v3/logging" + "github.com/splitio/go-split-commons/v3/dtos" + "github.com/splitio/go-toolkit/v4/logging" ) // MaxAccumulatedBytes is the maximum size to accumulate in events before flush (in bytes) diff --git a/vendor/github.com/splitio/go-split-commons/v2/storage/mutexqueue/impressions.go b/vendor/github.com/splitio/go-split-commons/v3/storage/mutexqueue/impressions.go similarity index 96% rename from vendor/github.com/splitio/go-split-commons/v2/storage/mutexqueue/impressions.go rename to vendor/github.com/splitio/go-split-commons/v3/storage/mutexqueue/impressions.go index ab9d2b4eee..88cf00db13 100644 --- a/vendor/github.com/splitio/go-split-commons/v2/storage/mutexqueue/impressions.go +++ b/vendor/github.com/splitio/go-split-commons/v3/storage/mutexqueue/impressions.go @@ -4,8 +4,8 @@ import ( "container/list" "sync" - "github.com/splitio/go-split-commons/v2/dtos" - "github.com/splitio/go-toolkit/v3/logging" + "github.com/splitio/go-split-commons/v3/dtos" + "github.com/splitio/go-toolkit/v4/logging" ) // NewMQImpressionsStorage returns an instance of MQEventsStorage diff --git a/vendor/github.com/splitio/go-split-commons/v2/storage/redis/constants.go b/vendor/github.com/splitio/go-split-commons/v3/storage/redis/constants.go similarity index 100% rename from vendor/github.com/splitio/go-split-commons/v2/storage/redis/constants.go rename to vendor/github.com/splitio/go-split-commons/v3/storage/redis/constants.go diff --git a/vendor/github.com/splitio/go-split-commons/v2/storage/redis/events.go b/vendor/github.com/splitio/go-split-commons/v3/storage/redis/events.go similarity index 96% rename from vendor/github.com/splitio/go-split-commons/v2/storage/redis/events.go rename to vendor/github.com/splitio/go-split-commons/v3/storage/redis/events.go index e546079535..018441b571 100644 --- a/vendor/github.com/splitio/go-split-commons/v2/storage/redis/events.go +++ b/vendor/github.com/splitio/go-split-commons/v3/storage/redis/events.go @@ -5,10 +5,10 @@ import ( "math" "sync" - "github.com/splitio/go-split-commons/v2/dtos" - "github.com/splitio/go-toolkit/v3/logging" - "github.com/splitio/go-toolkit/v3/queuecache" - "github.com/splitio/go-toolkit/v3/redis" + "github.com/splitio/go-split-commons/v3/dtos" + "github.com/splitio/go-toolkit/v4/logging" + "github.com/splitio/go-toolkit/v4/queuecache" + "github.com/splitio/go-toolkit/v4/redis" ) // EventsStorage redis implementation of EventsStorage interface diff --git a/vendor/github.com/splitio/go-split-commons/v2/storage/redis/impressions.go b/vendor/github.com/splitio/go-split-commons/v3/storage/redis/impressions.go similarity index 97% rename from vendor/github.com/splitio/go-split-commons/v2/storage/redis/impressions.go rename to vendor/github.com/splitio/go-split-commons/v3/storage/redis/impressions.go index 1ed2721f2d..880a5b1bab 100644 --- a/vendor/github.com/splitio/go-split-commons/v2/storage/redis/impressions.go +++ b/vendor/github.com/splitio/go-split-commons/v3/storage/redis/impressions.go @@ -5,9 +5,9 @@ import ( "sync" "time" - "github.com/splitio/go-split-commons/v2/dtos" - "github.com/splitio/go-toolkit/v3/logging" - "github.com/splitio/go-toolkit/v3/redis" + "github.com/splitio/go-split-commons/v3/dtos" + "github.com/splitio/go-toolkit/v4/logging" + "github.com/splitio/go-toolkit/v4/redis" ) const impressionsTTLRefresh = time.Duration(3600) * time.Second diff --git a/vendor/github.com/splitio/go-split-commons/v2/storage/redis/metrics.go b/vendor/github.com/splitio/go-split-commons/v3/storage/redis/metrics.go similarity index 98% rename from vendor/github.com/splitio/go-split-commons/v2/storage/redis/metrics.go rename to vendor/github.com/splitio/go-split-commons/v3/storage/redis/metrics.go index 4e767b9a5c..a9a45edc0e 100644 --- a/vendor/github.com/splitio/go-split-commons/v2/storage/redis/metrics.go +++ b/vendor/github.com/splitio/go-split-commons/v3/storage/redis/metrics.go @@ -7,9 +7,9 @@ import ( "strings" "sync" - "github.com/splitio/go-split-commons/v2/dtos" - "github.com/splitio/go-toolkit/v3/logging" - "github.com/splitio/go-toolkit/v3/redis" + "github.com/splitio/go-split-commons/v3/dtos" + "github.com/splitio/go-toolkit/v4/logging" + "github.com/splitio/go-toolkit/v4/redis" ) // MetricsStorage is a redis-based implementation of split storage diff --git a/vendor/github.com/splitio/go-split-commons/v2/storage/redis/miscstorage.go b/vendor/github.com/splitio/go-split-commons/v3/storage/redis/miscstorage.go similarity index 94% rename from vendor/github.com/splitio/go-split-commons/v2/storage/redis/miscstorage.go rename to vendor/github.com/splitio/go-split-commons/v3/storage/redis/miscstorage.go index b2a8359dfd..f2c8aa14de 100644 --- a/vendor/github.com/splitio/go-split-commons/v2/storage/redis/miscstorage.go +++ b/vendor/github.com/splitio/go-split-commons/v3/storage/redis/miscstorage.go @@ -4,8 +4,8 @@ import ( "errors" "strings" - "github.com/splitio/go-toolkit/v3/logging" - "github.com/splitio/go-toolkit/v3/redis" + "github.com/splitio/go-toolkit/v4/logging" + "github.com/splitio/go-toolkit/v4/redis" ) // ErrorHashNotPresent constant diff --git a/vendor/github.com/splitio/go-split-commons/v2/storage/redis/redis.go b/vendor/github.com/splitio/go-split-commons/v3/storage/redis/redis.go similarity index 91% rename from vendor/github.com/splitio/go-split-commons/v2/storage/redis/redis.go rename to vendor/github.com/splitio/go-split-commons/v3/storage/redis/redis.go index da05b7d0b6..40d98cc240 100644 --- a/vendor/github.com/splitio/go-split-commons/v2/storage/redis/redis.go +++ b/vendor/github.com/splitio/go-split-commons/v3/storage/redis/redis.go @@ -6,10 +6,10 @@ import ( "strings" "time" - "github.com/splitio/go-split-commons/v2/conf" - "github.com/splitio/go-toolkit/v3/logging" - "github.com/splitio/go-toolkit/v3/redis" - "github.com/splitio/go-toolkit/v3/redis/helpers" + "github.com/splitio/go-split-commons/v3/conf" + "github.com/splitio/go-toolkit/v4/logging" + "github.com/splitio/go-toolkit/v4/redis" + "github.com/splitio/go-toolkit/v4/redis/helpers" ) // NewRedisClient returns a new Prefixed Redis Client diff --git a/vendor/github.com/splitio/go-split-commons/v2/storage/redis/segments.go b/vendor/github.com/splitio/go-split-commons/v3/storage/redis/segments.go similarity index 95% rename from vendor/github.com/splitio/go-split-commons/v2/storage/redis/segments.go rename to vendor/github.com/splitio/go-split-commons/v3/storage/redis/segments.go index 39cd162f97..80dddc8570 100644 --- a/vendor/github.com/splitio/go-split-commons/v2/storage/redis/segments.go +++ b/vendor/github.com/splitio/go-split-commons/v3/storage/redis/segments.go @@ -6,9 +6,9 @@ import ( "strings" "sync" - "github.com/splitio/go-toolkit/v3/datastructures/set" - "github.com/splitio/go-toolkit/v3/logging" - "github.com/splitio/go-toolkit/v3/redis" + "github.com/splitio/go-toolkit/v4/datastructures/set" + "github.com/splitio/go-toolkit/v4/logging" + "github.com/splitio/go-toolkit/v4/redis" ) // SegmentStorage is a redis implementation of a storage for segments diff --git a/vendor/github.com/splitio/go-split-commons/v2/storage/redis/splits.go b/vendor/github.com/splitio/go-split-commons/v3/storage/redis/splits.go similarity index 97% rename from vendor/github.com/splitio/go-split-commons/v2/storage/redis/splits.go rename to vendor/github.com/splitio/go-split-commons/v3/storage/redis/splits.go index c94d1a8fa5..a96b06c9e9 100644 --- a/vendor/github.com/splitio/go-split-commons/v2/storage/redis/splits.go +++ b/vendor/github.com/splitio/go-split-commons/v3/storage/redis/splits.go @@ -8,10 +8,10 @@ import ( "strings" "sync" - "github.com/splitio/go-split-commons/v2/dtos" - "github.com/splitio/go-toolkit/v3/datastructures/set" - "github.com/splitio/go-toolkit/v3/logging" - "github.com/splitio/go-toolkit/v3/redis" + "github.com/splitio/go-split-commons/v3/dtos" + "github.com/splitio/go-toolkit/v4/datastructures/set" + "github.com/splitio/go-toolkit/v4/logging" + "github.com/splitio/go-toolkit/v4/redis" ) // SplitStorage is a redis-based implementation of split storage diff --git a/vendor/github.com/splitio/go-split-commons/v3/synchronizer/interface.go b/vendor/github.com/splitio/go-split-commons/v3/synchronizer/interface.go new file mode 100644 index 0000000000..3d4cf3d8f9 --- /dev/null +++ b/vendor/github.com/splitio/go-split-commons/v3/synchronizer/interface.go @@ -0,0 +1,13 @@ +package synchronizer + +// Synchronizer interface for syncing data to and from splits servers +type Synchronizer interface { + SyncAll(requestNoCache bool) error + SynchronizeSplits(till *int64, requestNoCache bool) error + LocalKill(splitName string, defaultTreatment string, changeNumber int64) + SynchronizeSegment(segmentName string, till *int64, requestNoCache bool) error + StartPeriodicFetching() + StopPeriodicFetching() + StartPeriodicDataRecording() + StopPeriodicDataRecording() +} diff --git a/vendor/github.com/splitio/go-split-commons/v2/synchronizer/local.go b/vendor/github.com/splitio/go-split-commons/v3/synchronizer/local.go similarity index 68% rename from vendor/github.com/splitio/go-split-commons/v2/synchronizer/local.go rename to vendor/github.com/splitio/go-split-commons/v3/synchronizer/local.go index f650e68d87..7e2c51aee1 100644 --- a/vendor/github.com/splitio/go-split-commons/v2/synchronizer/local.go +++ b/vendor/github.com/splitio/go-split-commons/v3/synchronizer/local.go @@ -1,13 +1,13 @@ package synchronizer import ( - "github.com/splitio/go-split-commons/v2/dtos" - "github.com/splitio/go-split-commons/v2/service" - "github.com/splitio/go-split-commons/v2/storage" - storageMock "github.com/splitio/go-split-commons/v2/storage/mocks" - "github.com/splitio/go-split-commons/v2/synchronizer/worker/split" - "github.com/splitio/go-split-commons/v2/tasks" - "github.com/splitio/go-toolkit/v3/logging" + "github.com/splitio/go-split-commons/v3/dtos" + "github.com/splitio/go-split-commons/v3/service" + "github.com/splitio/go-split-commons/v3/storage" + storageMock "github.com/splitio/go-split-commons/v3/storage/mocks" + "github.com/splitio/go-split-commons/v3/synchronizer/worker/split" + "github.com/splitio/go-split-commons/v3/tasks" + "github.com/splitio/go-toolkit/v4/logging" ) // Local implements Local Synchronizer @@ -47,8 +47,9 @@ func NewLocal( } // SyncAll syncs splits and segments -func (s *Local) SyncAll() error { - return s.workers.SplitFetcher.SynchronizeSplits(nil) +func (s *Local) SyncAll(requestNoCache bool) error { + _, err := s.workers.SplitFetcher.SynchronizeSplits(nil, requestNoCache) + return err } // StartPeriodicFetching starts periodic fetchers tasks @@ -70,11 +71,16 @@ func (s *Local) StopPeriodicDataRecording() { } // SynchronizeSplits syncs splits -func (s *Local) SynchronizeSplits(till *int64) error { - return s.workers.SplitFetcher.SynchronizeSplits(till) +func (s *Local) SynchronizeSplits(till *int64, requestNoCache bool) error { + _, err := s.workers.SplitFetcher.SynchronizeSplits(nil, requestNoCache) + return err } // SynchronizeSegment syncs segment -func (s *Local) SynchronizeSegment(name string, till *int64) error { +func (s *Local) SynchronizeSegment(name string, till *int64, _ bool) error { return nil } + +// LocalKill does nothing +func (s *Local) LocalKill(splitName string, defaultTreatment string, changeNumber int64) { +} diff --git a/vendor/github.com/splitio/go-split-commons/v3/synchronizer/manager.go b/vendor/github.com/splitio/go-split-commons/v3/synchronizer/manager.go new file mode 100644 index 0000000000..fcde38edf0 --- /dev/null +++ b/vendor/github.com/splitio/go-split-commons/v3/synchronizer/manager.go @@ -0,0 +1,207 @@ +package synchronizer + +import ( + "errors" + "sync/atomic" + "time" + + "github.com/splitio/go-split-commons/v3/conf" + "github.com/splitio/go-split-commons/v3/push" + "github.com/splitio/go-split-commons/v3/service" + "github.com/splitio/go-split-commons/v3/storage" + "github.com/splitio/go-toolkit/v4/backoff" + "github.com/splitio/go-toolkit/v4/logging" + "github.com/splitio/go-toolkit/v4/struct/traits/lifecycle" +) + +const ( + // Ready represents ready + Ready = iota + // StreamingReady ready + StreamingReady + // Error represents some error in SSE streaming + Error +) + +// Operation mode constants +const ( + Streaming = iota + Polling +) + +// Manager interface +type Manager interface { + Start() + Stop() + IsRunning() bool +} + +// ManagerImpl struct +type ManagerImpl struct { + synchronizer Synchronizer + logger logging.LoggerInterface + config conf.AdvancedConfig + pushManager push.Manager + managerStatus chan int + streamingStatus chan int64 + operationMode int32 + lifecycle lifecycle.Manager + backoff backoff.Interface +} + +// NewSynchronizerManager creates new sync manager +func NewSynchronizerManager( + synchronizer Synchronizer, + logger logging.LoggerInterface, + config conf.AdvancedConfig, + authClient service.AuthClient, + splitStorage storage.SplitStorage, + managerStatus chan int, +) (*ManagerImpl, error) { + if managerStatus == nil || cap(managerStatus) < 1 { + return nil, errors.New("Status channel cannot be nil nor having capacity") + } + + manager := &ManagerImpl{ + backoff: backoff.New(), + synchronizer: synchronizer, + logger: logger, + config: config, + managerStatus: managerStatus, + } + manager.lifecycle.Setup() + if config.StreamingEnabled { + streamingStatus := make(chan int64, 1000) + pushManager, err := push.NewManager(logger, synchronizer, &config, streamingStatus, authClient) + if err != nil { + return nil, err + } + manager.pushManager = pushManager + manager.streamingStatus = streamingStatus + } + + return manager, nil +} + +// IsRunning returns true if is in Streaming or Polling +func (s *ManagerImpl) IsRunning() bool { + return s.lifecycle.IsRunning() +} + +// Start starts synchronization through Split +func (s *ManagerImpl) Start() { + if !s.lifecycle.BeginInitialization() { + s.logger.Info("Manager is already running, skipping start") + return + } + + // It's safe to drain the channel here, since it's guaranteed that the manager status is "starting" + // push manager is still stopped + for len(s.managerStatus) > 0 { + <-s.managerStatus + } + err := s.synchronizer.SyncAll(false) + if err != nil { + defer s.lifecycle.ShutdownComplete() + s.managerStatus <- Error + return + } + + if !s.lifecycle.InitializationComplete() { + defer s.lifecycle.ShutdownComplete() + return + } + s.logger.Debug("SyncAll Ready") + s.managerStatus <- Ready + s.synchronizer.StartPeriodicDataRecording() + + if !s.config.StreamingEnabled { + s.logger.Info("SDK initialized in polling mode") + s.startPolling() + go func() { // create a goroutine that stops everything (the same way the streaming status watcher would) + <-s.lifecycle.ShutdownRequested() + s.stop() + }() + return + } + + // Start streaming + s.logger.Info("SDK Initialized in streaming mode") + s.pushManager.Start() + go s.pushStatusWatcher() +} + +func (s *ManagerImpl) stop() { + if s.pushManager != nil { + s.pushManager.Stop() + } + s.synchronizer.StopPeriodicFetching() + s.synchronizer.StopPeriodicDataRecording() + s.lifecycle.ShutdownComplete() +} + +// Stop stop synchronizaation through Split +func (s *ManagerImpl) Stop() { + if !s.lifecycle.BeginShutdown() { + s.logger.Info("sync manager not yet running, skipping shutdown.") + return + } + + s.logger.Info("Stopping all synchronization tasks") + s.lifecycle.AwaitShutdownComplete() +} + +func (s *ManagerImpl) pushStatusWatcher() { + defer s.stop() + for { + select { + case <-s.lifecycle.ShutdownRequested(): + return + case status := <-s.streamingStatus: + switch status { + case push.StatusUp: + s.stopPolling() + s.logger.Info("streaming up and running") + s.enableStreaming() + s.synchronizer.SyncAll(true) + case push.StatusDown: + s.logger.Info("streaming down, switchin to polling") + s.synchronizer.SyncAll(false) + s.pauseStreaming() + s.startPolling() + case push.StatusRetryableError: + howLong := s.backoff.Next() + s.logger.Error("retryable error in streaming subsystem. Switching to polling and retrying in ", howLong, " seconds") + s.pushManager.Stop() + s.synchronizer.SyncAll(false) + s.startPolling() + time.Sleep(howLong) + s.pushManager.Start() + case push.StatusNonRetryableError: + s.logger.Error("non retryable error in streaming subsystem. Switching to polling until next SDK initialization") + s.pushManager.Stop() + s.synchronizer.SyncAll(false) + s.startPolling() + } + } + } +} + +func (s *ManagerImpl) startPolling() { + atomic.StoreInt32(&s.operationMode, Polling) + s.synchronizer.StartPeriodicFetching() +} + +func (s *ManagerImpl) stopPolling() { + s.synchronizer.StopPeriodicFetching() +} + +func (s *ManagerImpl) pauseStreaming() { + s.pushManager.StartWorkers() +} + +func (s *ManagerImpl) enableStreaming() { + s.pushManager.StartWorkers() + atomic.StoreInt32(&s.operationMode, Streaming) + s.backoff.Reset() +} diff --git a/vendor/github.com/splitio/go-split-commons/v2/synchronizer/synchronizer.go b/vendor/github.com/splitio/go-split-commons/v3/synchronizer/synchronizer.go similarity index 67% rename from vendor/github.com/splitio/go-split-commons/v2/synchronizer/synchronizer.go rename to vendor/github.com/splitio/go-split-commons/v3/synchronizer/synchronizer.go index 4b68f3e36f..6cd8fcbe3d 100644 --- a/vendor/github.com/splitio/go-split-commons/v2/synchronizer/synchronizer.go +++ b/vendor/github.com/splitio/go-split-commons/v3/synchronizer/synchronizer.go @@ -1,16 +1,16 @@ package synchronizer import ( - "github.com/splitio/go-split-commons/v2/conf" - "github.com/splitio/go-split-commons/v2/synchronizer/worker/event" - "github.com/splitio/go-split-commons/v2/synchronizer/worker/impression" - "github.com/splitio/go-split-commons/v2/synchronizer/worker/impressionscount" - "github.com/splitio/go-split-commons/v2/synchronizer/worker/metric" - "github.com/splitio/go-split-commons/v2/synchronizer/worker/segment" - "github.com/splitio/go-split-commons/v2/synchronizer/worker/split" - "github.com/splitio/go-split-commons/v2/tasks" - "github.com/splitio/go-toolkit/v3/asynctask" - "github.com/splitio/go-toolkit/v3/logging" + "github.com/splitio/go-split-commons/v3/conf" + "github.com/splitio/go-split-commons/v3/synchronizer/worker/event" + "github.com/splitio/go-split-commons/v3/synchronizer/worker/impression" + "github.com/splitio/go-split-commons/v3/synchronizer/worker/impressionscount" + "github.com/splitio/go-split-commons/v3/synchronizer/worker/metric" + "github.com/splitio/go-split-commons/v3/synchronizer/worker/segment" + "github.com/splitio/go-split-commons/v3/synchronizer/worker/split" + "github.com/splitio/go-split-commons/v3/tasks" + "github.com/splitio/go-toolkit/v4/asynctask" + "github.com/splitio/go-toolkit/v4/logging" ) // SplitTasks struct for tasks @@ -25,8 +25,8 @@ type SplitTasks struct { // Workers struct for workers type Workers struct { - SplitFetcher split.SplitFetcher - SegmentFetcher segment.SegmentFetcher + SplitFetcher split.Updater + SegmentFetcher segment.Updater TelemetryRecorder metric.MetricRecorder ImpressionRecorder impression.ImpressionRecorder EventRecorder event.EventRecorder @@ -83,12 +83,12 @@ func (s *SynchronizerImpl) dataFlusher() { } // SyncAll syncs splits and segments -func (s *SynchronizerImpl) SyncAll() error { - err := s.workers.SplitFetcher.SynchronizeSplits(nil) +func (s *SynchronizerImpl) SyncAll(requestNoCache bool) error { + _, err := s.workers.SplitFetcher.SynchronizeSplits(nil, requestNoCache) if err != nil { return err } - return s.workers.SegmentFetcher.SynchronizeSegments() + return s.workers.SegmentFetcher.SynchronizeSegments(requestNoCache) } // StartPeriodicFetching starts periodic fetchers tasks @@ -148,11 +148,32 @@ func (s *SynchronizerImpl) StopPeriodicDataRecording() { } // SynchronizeSplits syncs splits -func (s *SynchronizerImpl) SynchronizeSplits(till *int64) error { - return s.workers.SplitFetcher.SynchronizeSplits(till) +func (s *SynchronizerImpl) SynchronizeSplits(till *int64, requstNoCache bool) error { + referencedSegments, err := s.workers.SplitFetcher.SynchronizeSplits(till, requstNoCache) + for _, segment := range s.filterCachedSegments(referencedSegments) { + go s.SynchronizeSegment(segment, nil, true) // send segment to workerpool (queue is bypassed) + } + return err +} + +func (s *SynchronizerImpl) filterCachedSegments(segmentsReferenced []string) []string { + toRet := make([]string, 0, len(segmentsReferenced)) + for _, name := range segmentsReferenced { + if !s.workers.SegmentFetcher.IsSegmentCached(name) { + toRet = append(toRet, name) + } + } + return toRet +} + +// LocalKill locally kills a split +func (s *SynchronizerImpl) LocalKill(splitName string, defaultTreatment string, changeNumber int64) { + s.workers.SplitFetcher.LocalKill(splitName, defaultTreatment, changeNumber) } // SynchronizeSegment syncs segment -func (s *SynchronizerImpl) SynchronizeSegment(name string, till *int64) error { - return s.workers.SegmentFetcher.SynchronizeSegment(name, till) +func (s *SynchronizerImpl) SynchronizeSegment(name string, till *int64, requstNoCache bool) error { + return s.workers.SegmentFetcher.SynchronizeSegment(name, till, requstNoCache) } + +var _ Synchronizer = &SynchronizerImpl{} diff --git a/vendor/github.com/splitio/go-split-commons/v2/synchronizer/worker/event/interface.go b/vendor/github.com/splitio/go-split-commons/v3/synchronizer/worker/event/interface.go similarity index 100% rename from vendor/github.com/splitio/go-split-commons/v2/synchronizer/worker/event/interface.go rename to vendor/github.com/splitio/go-split-commons/v3/synchronizer/worker/event/interface.go diff --git a/vendor/github.com/splitio/go-split-commons/v2/synchronizer/worker/event/single.go b/vendor/github.com/splitio/go-split-commons/v3/synchronizer/worker/event/single.go similarity index 86% rename from vendor/github.com/splitio/go-split-commons/v2/synchronizer/worker/event/single.go rename to vendor/github.com/splitio/go-split-commons/v3/synchronizer/worker/event/single.go index 10202ebe28..678aa5cfae 100644 --- a/vendor/github.com/splitio/go-split-commons/v2/synchronizer/worker/event/single.go +++ b/vendor/github.com/splitio/go-split-commons/v3/synchronizer/worker/event/single.go @@ -2,13 +2,14 @@ package event import ( "errors" + "strconv" "time" - "github.com/splitio/go-split-commons/v2/dtos" - "github.com/splitio/go-split-commons/v2/service" - "github.com/splitio/go-split-commons/v2/storage" - "github.com/splitio/go-split-commons/v2/util" - "github.com/splitio/go-toolkit/v3/logging" + "github.com/splitio/go-split-commons/v3/dtos" + "github.com/splitio/go-split-commons/v3/service" + "github.com/splitio/go-split-commons/v3/storage" + "github.com/splitio/go-split-commons/v3/util" + "github.com/splitio/go-toolkit/v4/logging" ) // RecorderSingle struct for event sync @@ -54,7 +55,7 @@ func (e *RecorderSingle) SynchronizeEvents(bulkSize int64) error { err = e.eventRecorder.Record(queuedEvents, e.metadata) if err != nil { if httpError, ok := err.(*dtos.HTTPError); ok { - e.metricsWrapper.StoreCounters(storage.PostEventsCounter, string(httpError.Code)) + e.metricsWrapper.StoreCounters(storage.PostEventsCounter, strconv.Itoa(httpError.Code)) } return err } diff --git a/vendor/github.com/splitio/go-split-commons/v2/synchronizer/worker/impression/interface.go b/vendor/github.com/splitio/go-split-commons/v3/synchronizer/worker/impression/interface.go similarity index 100% rename from vendor/github.com/splitio/go-split-commons/v2/synchronizer/worker/impression/interface.go rename to vendor/github.com/splitio/go-split-commons/v3/synchronizer/worker/impression/interface.go diff --git a/vendor/github.com/splitio/go-split-commons/v2/synchronizer/worker/impression/single.go b/vendor/github.com/splitio/go-split-commons/v3/synchronizer/worker/impression/single.go similarity index 90% rename from vendor/github.com/splitio/go-split-commons/v2/synchronizer/worker/impression/single.go rename to vendor/github.com/splitio/go-split-commons/v3/synchronizer/worker/impression/single.go index e220db4607..41ab507de6 100644 --- a/vendor/github.com/splitio/go-split-commons/v2/synchronizer/worker/impression/single.go +++ b/vendor/github.com/splitio/go-split-commons/v3/synchronizer/worker/impression/single.go @@ -2,14 +2,15 @@ package impression import ( "errors" + "strconv" "time" - "github.com/splitio/go-split-commons/v2/conf" - "github.com/splitio/go-split-commons/v2/dtos" - "github.com/splitio/go-split-commons/v2/service" - "github.com/splitio/go-split-commons/v2/storage" - "github.com/splitio/go-split-commons/v2/util" - "github.com/splitio/go-toolkit/v3/logging" + "github.com/splitio/go-split-commons/v3/conf" + "github.com/splitio/go-split-commons/v3/dtos" + "github.com/splitio/go-split-commons/v3/service" + "github.com/splitio/go-split-commons/v3/storage" + "github.com/splitio/go-split-commons/v3/util" + "github.com/splitio/go-toolkit/v4/logging" ) const ( @@ -95,7 +96,7 @@ func (i *RecorderSingle) SynchronizeImpressions(bulkSize int64) error { err = i.impressionRecorder.Record(bulkImpressions, i.metadata, map[string]string{splitSDKImpressionsMode: i.mode}) if err != nil { if httpError, ok := err.(*dtos.HTTPError); ok { - i.metricsWrapper.StoreCounters(storage.TestImpressionsCounter, string(httpError.Code)) + i.metricsWrapper.StoreCounters(storage.TestImpressionsCounter, strconv.Itoa(httpError.Code)) } return err } diff --git a/vendor/github.com/splitio/go-split-commons/v2/synchronizer/worker/impressionscount/interface.go b/vendor/github.com/splitio/go-split-commons/v3/synchronizer/worker/impressionscount/interface.go similarity index 100% rename from vendor/github.com/splitio/go-split-commons/v2/synchronizer/worker/impressionscount/interface.go rename to vendor/github.com/splitio/go-split-commons/v3/synchronizer/worker/impressionscount/interface.go diff --git a/vendor/github.com/splitio/go-split-commons/v2/synchronizer/worker/impressionscount/single.go b/vendor/github.com/splitio/go-split-commons/v3/synchronizer/worker/impressionscount/single.go similarity index 88% rename from vendor/github.com/splitio/go-split-commons/v2/synchronizer/worker/impressionscount/single.go rename to vendor/github.com/splitio/go-split-commons/v3/synchronizer/worker/impressionscount/single.go index 2fcc063d7e..3cc19f96fc 100644 --- a/vendor/github.com/splitio/go-split-commons/v2/synchronizer/worker/impressionscount/single.go +++ b/vendor/github.com/splitio/go-split-commons/v3/synchronizer/worker/impressionscount/single.go @@ -1,10 +1,10 @@ package impressionscount import ( - "github.com/splitio/go-split-commons/v2/dtos" - "github.com/splitio/go-split-commons/v2/provisional" - "github.com/splitio/go-split-commons/v2/service" - "github.com/splitio/go-toolkit/v3/logging" + "github.com/splitio/go-split-commons/v3/dtos" + "github.com/splitio/go-split-commons/v3/provisional" + "github.com/splitio/go-split-commons/v3/service" + "github.com/splitio/go-toolkit/v4/logging" ) // RecorderSingle struct for impressionsCount sync diff --git a/vendor/github.com/splitio/go-split-commons/v2/synchronizer/worker/metric/interface.go b/vendor/github.com/splitio/go-split-commons/v3/synchronizer/worker/metric/interface.go similarity index 100% rename from vendor/github.com/splitio/go-split-commons/v2/synchronizer/worker/metric/interface.go rename to vendor/github.com/splitio/go-split-commons/v3/synchronizer/worker/metric/interface.go diff --git a/vendor/github.com/splitio/go-split-commons/v2/synchronizer/worker/metric/single.go b/vendor/github.com/splitio/go-split-commons/v3/synchronizer/worker/metric/single.go similarity index 91% rename from vendor/github.com/splitio/go-split-commons/v2/synchronizer/worker/metric/single.go rename to vendor/github.com/splitio/go-split-commons/v3/synchronizer/worker/metric/single.go index 00c392ff67..d150466c72 100644 --- a/vendor/github.com/splitio/go-split-commons/v2/synchronizer/worker/metric/single.go +++ b/vendor/github.com/splitio/go-split-commons/v3/synchronizer/worker/metric/single.go @@ -3,9 +3,9 @@ package metric import ( "errors" - "github.com/splitio/go-split-commons/v2/dtos" - "github.com/splitio/go-split-commons/v2/service" - "github.com/splitio/go-split-commons/v2/storage" + "github.com/splitio/go-split-commons/v3/dtos" + "github.com/splitio/go-split-commons/v3/service" + "github.com/splitio/go-split-commons/v3/storage" ) // RecorderSingle struct for metric sync diff --git a/vendor/github.com/splitio/go-split-commons/v3/synchronizer/worker/segment/interface.go b/vendor/github.com/splitio/go-split-commons/v3/synchronizer/worker/segment/interface.go new file mode 100644 index 0000000000..ad140884b9 --- /dev/null +++ b/vendor/github.com/splitio/go-split-commons/v3/synchronizer/worker/segment/interface.go @@ -0,0 +1,9 @@ +package segment + +// Updater interface +type Updater interface { + SynchronizeSegment(name string, till *int64, requestNoCache bool) error + SynchronizeSegments(requestNoCache bool) error + SegmentNames() []interface{} + IsSegmentCached(segmentName string) bool +} diff --git a/vendor/github.com/splitio/go-split-commons/v2/synchronizer/worker/segment/segment.go b/vendor/github.com/splitio/go-split-commons/v3/synchronizer/worker/segment/segment.go similarity index 77% rename from vendor/github.com/splitio/go-split-commons/v2/synchronizer/worker/segment/segment.go rename to vendor/github.com/splitio/go-split-commons/v3/synchronizer/worker/segment/segment.go index 23fba583a1..3d72a5bf09 100644 --- a/vendor/github.com/splitio/go-split-commons/v2/synchronizer/worker/segment/segment.go +++ b/vendor/github.com/splitio/go-split-commons/v3/synchronizer/worker/segment/segment.go @@ -2,19 +2,20 @@ package segment import ( "fmt" + "strconv" "sync" "time" - "github.com/splitio/go-split-commons/v2/dtos" - "github.com/splitio/go-split-commons/v2/service" - "github.com/splitio/go-split-commons/v2/storage" - "github.com/splitio/go-split-commons/v2/util" - "github.com/splitio/go-toolkit/v3/datastructures/set" - "github.com/splitio/go-toolkit/v3/logging" + "github.com/splitio/go-split-commons/v3/dtos" + "github.com/splitio/go-split-commons/v3/service" + "github.com/splitio/go-split-commons/v3/storage" + "github.com/splitio/go-split-commons/v3/util" + "github.com/splitio/go-toolkit/v4/datastructures/set" + "github.com/splitio/go-toolkit/v4/logging" ) -// SegmentFetcherSimple struct for segment sync -type SegmentFetcherSimple struct { +// UpdaterImpl struct for segment sync +type UpdaterImpl struct { splitStorage storage.SplitStorageConsumer segmentStorage storage.SegmentStorage segmentFetcher service.SegmentFetcher @@ -29,8 +30,8 @@ func NewSegmentFetcher( segmentFetcher service.SegmentFetcher, metricsWrapper *storage.MetricWrapper, logger logging.LoggerInterface, -) SegmentFetcher { - return &SegmentFetcherSimple{ +) Updater { + return &UpdaterImpl{ splitStorage: splitStorage, segmentStorage: segmentStorage, segmentFetcher: segmentFetcher, @@ -39,7 +40,7 @@ func NewSegmentFetcher( } } -func (s *SegmentFetcherSimple) processUpdate(segmentChanges *dtos.SegmentChangesDTO) { +func (s *UpdaterImpl) processUpdate(segmentChanges *dtos.SegmentChangesDTO) { name := segmentChanges.Name oldSegment := s.segmentStorage.Keys(name) if oldSegment == nil { @@ -67,7 +68,7 @@ func (s *SegmentFetcherSimple) processUpdate(segmentChanges *dtos.SegmentChanges } // SynchronizeSegment syncs segment -func (s *SegmentFetcherSimple) SynchronizeSegment(name string, till *int64) error { +func (s *UpdaterImpl) SynchronizeSegment(name string, till *int64, requestNoCache bool) error { for { s.logger.Debug(fmt.Sprintf("Synchronizing segment %s", name)) changeNumber, _ := s.segmentStorage.ChangeNumber(name) @@ -79,10 +80,10 @@ func (s *SegmentFetcherSimple) SynchronizeSegment(name string, till *int64) erro } before := time.Now() - segmentChanges, err := s.segmentFetcher.Fetch(name, changeNumber) + segmentChanges, err := s.segmentFetcher.Fetch(name, changeNumber, requestNoCache) if err != nil { if httpError, ok := err.(*dtos.HTTPError); ok { - s.metricsWrapper.StoreCounters(storage.SegmentChangesCounter, string(httpError.Code)) + s.metricsWrapper.StoreCounters(storage.SegmentChangesCounter, strconv.Itoa(httpError.Code)) } return err } @@ -98,7 +99,7 @@ func (s *SegmentFetcherSimple) SynchronizeSegment(name string, till *int64) erro } // SynchronizeSegments syncs segments at once -func (s *SegmentFetcherSimple) SynchronizeSegments() error { +func (s *UpdaterImpl) SynchronizeSegments(requestNoCache bool) error { // @TODO: add delays segmentNames := s.splitStorage.SegmentNames().List() s.logger.Debug("Segment Sync", segmentNames) @@ -116,7 +117,7 @@ func (s *SegmentFetcherSimple) SynchronizeSegments() error { ready := false var err error for !ready { - err = s.SynchronizeSegment(segmentName, nil) + err = s.SynchronizeSegment(segmentName, nil, requestNoCache) if err != nil { failedSegments.Add(segmentName) } @@ -134,6 +135,12 @@ func (s *SegmentFetcherSimple) SynchronizeSegments() error { } // SegmentNames returns all segments -func (s *SegmentFetcherSimple) SegmentNames() []interface{} { +func (s *UpdaterImpl) SegmentNames() []interface{} { return s.splitStorage.SegmentNames().List() } + +// IsSegmentCached returns true if a segment exists +func (s *UpdaterImpl) IsSegmentCached(segmentName string) bool { + cn, _ := s.segmentStorage.ChangeNumber(segmentName) + return cn != -1 +} diff --git a/vendor/github.com/splitio/go-split-commons/v3/synchronizer/worker/split/interface.go b/vendor/github.com/splitio/go-split-commons/v3/synchronizer/worker/split/interface.go new file mode 100644 index 0000000000..86efe5e0bd --- /dev/null +++ b/vendor/github.com/splitio/go-split-commons/v3/synchronizer/worker/split/interface.go @@ -0,0 +1,7 @@ +package split + +// Updater interface +type Updater interface { + SynchronizeSplits(till *int64, requestNoCache bool) ([]string, error) + LocalKill(splitName string, defaultTreatment string, changeNumber int64) +} diff --git a/vendor/github.com/splitio/go-split-commons/v2/synchronizer/worker/split/split.go b/vendor/github.com/splitio/go-split-commons/v3/synchronizer/worker/split/split.go similarity index 52% rename from vendor/github.com/splitio/go-split-commons/v2/synchronizer/worker/split/split.go rename to vendor/github.com/splitio/go-split-commons/v3/synchronizer/worker/split/split.go index e35d6e1eff..82447364b7 100644 --- a/vendor/github.com/splitio/go-split-commons/v2/synchronizer/worker/split/split.go +++ b/vendor/github.com/splitio/go-split-commons/v3/synchronizer/worker/split/split.go @@ -1,17 +1,22 @@ package split import ( + "strconv" "time" - "github.com/splitio/go-split-commons/v2/dtos" - "github.com/splitio/go-split-commons/v2/service" - "github.com/splitio/go-split-commons/v2/storage" - "github.com/splitio/go-split-commons/v2/util" - "github.com/splitio/go-toolkit/v3/logging" + "github.com/splitio/go-split-commons/v3/dtos" + "github.com/splitio/go-split-commons/v3/service" + "github.com/splitio/go-split-commons/v3/storage" + "github.com/splitio/go-split-commons/v3/util" + "github.com/splitio/go-toolkit/v4/logging" ) -// SplitFetcherSimple struct for split sync -type SplitFetcherSimple struct { +const ( + matcherTypeInSegment = "IN_SEGMENT" +) + +// UpdaterImpl struct for split sync +type UpdaterImpl struct { splitStorage storage.SplitStorage splitFetcher service.SplitFetcher metricsWrapper *storage.MetricWrapper @@ -24,8 +29,8 @@ func NewSplitFetcher( splitFetcher service.SplitFetcher, metricsWrapper *storage.MetricWrapper, logger logging.LoggerInterface, -) SplitFetcher { - return &SplitFetcherSimple{ +) *UpdaterImpl { + return &UpdaterImpl{ splitStorage: splitStorage, splitFetcher: splitFetcher, metricsWrapper: metricsWrapper, @@ -33,7 +38,7 @@ func NewSplitFetcher( } } -func (s *SplitFetcherSimple) processUpdate(splits *dtos.SplitChangesDTO) { +func (s *UpdaterImpl) processUpdate(splits *dtos.SplitChangesDTO) { inactiveSplits := make([]dtos.SplitDTO, 0) activeSplits := make([]dtos.SplitDTO, 0) for _, split := range splits.Splits { @@ -54,31 +59,58 @@ func (s *SplitFetcherSimple) processUpdate(splits *dtos.SplitChangesDTO) { } // SynchronizeSplits syncs splits -func (s *SplitFetcherSimple) SynchronizeSplits(till *int64) error { +func (s *UpdaterImpl) SynchronizeSplits(till *int64, requestNoCache bool) ([]string, error) { // @TODO: add delays + + segments := make([]string, 0) for { changeNumber, _ := s.splitStorage.ChangeNumber() if changeNumber == 0 { changeNumber = -1 } if till != nil && *till < changeNumber { - return nil + return segments, nil } before := time.Now() - splits, err := s.splitFetcher.Fetch(changeNumber) + splits, err := s.splitFetcher.Fetch(changeNumber, requestNoCache) if err != nil { if httpError, ok := err.(*dtos.HTTPError); ok { - s.metricsWrapper.StoreCounters(storage.SplitChangesCounter, string(httpError.Code)) + s.metricsWrapper.StoreCounters(storage.SplitChangesCounter, strconv.Itoa(httpError.Code)) } - return err + return segments, err } s.processUpdate(splits) + segments = append(segments, extractSegments(splits)...) bucket := util.Bucket(time.Now().Sub(before).Nanoseconds()) s.metricsWrapper.StoreCounters(storage.SplitChangesCounter, "ok") s.metricsWrapper.StoreLatencies(storage.SplitChangesLatency, bucket) if splits.Till == splits.Since || (till != nil && splits.Till >= *till) { - return nil + return segments, nil } } } + +func extractSegments(splits *dtos.SplitChangesDTO) []string { + names := make(map[string]struct{}) + for _, split := range splits.Splits { + for _, cond := range split.Conditions { + for _, matcher := range cond.MatcherGroup.Matchers { + if matcher.MatcherType == matcherTypeInSegment && matcher.UserDefinedSegment != nil { + names[matcher.UserDefinedSegment.SegmentName] = struct{}{} + } + } + } + } + + toRet := make([]string, 0, len(names)) + for name := range names { + toRet = append(toRet, name) + } + return toRet +} + +// LocalKill marks a spit as killed in local storage +func (s *UpdaterImpl) LocalKill(splitName string, defaultTreatment string, changeNumber int64) { + s.splitStorage.KillLocally(splitName, defaultTreatment, changeNumber) +} diff --git a/vendor/github.com/splitio/go-split-commons/v2/tasks/eventsync.go b/vendor/github.com/splitio/go-split-commons/v3/tasks/eventsync.go similarity index 86% rename from vendor/github.com/splitio/go-split-commons/v2/tasks/eventsync.go rename to vendor/github.com/splitio/go-split-commons/v3/tasks/eventsync.go index 33e17a6ad7..2ae22d1e86 100644 --- a/vendor/github.com/splitio/go-split-commons/v2/tasks/eventsync.go +++ b/vendor/github.com/splitio/go-split-commons/v3/tasks/eventsync.go @@ -2,11 +2,10 @@ package tasks import ( "fmt" - "sync" - "github.com/splitio/go-split-commons/v2/synchronizer/worker/event" - "github.com/splitio/go-toolkit/v3/asynctask" - "github.com/splitio/go-toolkit/v3/logging" + "github.com/splitio/go-split-commons/v3/synchronizer/worker/event" + "github.com/splitio/go-toolkit/v4/asynctask" + "github.com/splitio/go-toolkit/v4/logging" ) // NewRecordEventsTask creates a new events recording task @@ -47,6 +46,5 @@ func NewRecordEventsTasks( return MultipleTask{ logger: logger, tasks: tasks, - wg: &sync.WaitGroup{}, } } diff --git a/vendor/github.com/splitio/go-split-commons/v2/tasks/impressionscountsync.go b/vendor/github.com/splitio/go-split-commons/v3/tasks/impressionscountsync.go similarity index 79% rename from vendor/github.com/splitio/go-split-commons/v2/tasks/impressionscountsync.go rename to vendor/github.com/splitio/go-split-commons/v3/tasks/impressionscountsync.go index 9fa38a0055..fdad285003 100644 --- a/vendor/github.com/splitio/go-split-commons/v2/tasks/impressionscountsync.go +++ b/vendor/github.com/splitio/go-split-commons/v3/tasks/impressionscountsync.go @@ -1,9 +1,9 @@ package tasks import ( - "github.com/splitio/go-split-commons/v2/synchronizer/worker/impressionscount" - "github.com/splitio/go-toolkit/v3/asynctask" - "github.com/splitio/go-toolkit/v3/logging" + "github.com/splitio/go-split-commons/v3/synchronizer/worker/impressionscount" + "github.com/splitio/go-toolkit/v4/asynctask" + "github.com/splitio/go-toolkit/v4/logging" ) const ( diff --git a/vendor/github.com/splitio/go-split-commons/v2/tasks/impressionsync.go b/vendor/github.com/splitio/go-split-commons/v3/tasks/impressionsync.go similarity index 87% rename from vendor/github.com/splitio/go-split-commons/v2/tasks/impressionsync.go rename to vendor/github.com/splitio/go-split-commons/v3/tasks/impressionsync.go index cbf8a4d450..42393d4fb8 100644 --- a/vendor/github.com/splitio/go-split-commons/v2/tasks/impressionsync.go +++ b/vendor/github.com/splitio/go-split-commons/v3/tasks/impressionsync.go @@ -2,11 +2,10 @@ package tasks import ( "fmt" - "sync" - "github.com/splitio/go-split-commons/v2/synchronizer/worker/impression" - "github.com/splitio/go-toolkit/v3/asynctask" - "github.com/splitio/go-toolkit/v3/logging" + "github.com/splitio/go-split-commons/v3/synchronizer/worker/impression" + "github.com/splitio/go-toolkit/v4/asynctask" + "github.com/splitio/go-toolkit/v4/logging" ) // NewRecordImpressionsTask creates a new splits fetching and storing task @@ -47,6 +46,5 @@ func NewRecordImpressionsTasks( return MultipleTask{ logger: logger, tasks: tasks, - wg: &sync.WaitGroup{}, } } diff --git a/vendor/github.com/splitio/go-split-commons/v2/tasks/interface.go b/vendor/github.com/splitio/go-split-commons/v3/tasks/interface.go similarity index 85% rename from vendor/github.com/splitio/go-split-commons/v2/tasks/interface.go rename to vendor/github.com/splitio/go-split-commons/v3/tasks/interface.go index a19a3d2d7d..35316ac720 100644 --- a/vendor/github.com/splitio/go-split-commons/v2/tasks/interface.go +++ b/vendor/github.com/splitio/go-split-commons/v3/tasks/interface.go @@ -3,7 +3,7 @@ package tasks import ( "sync" - "github.com/splitio/go-toolkit/v3/logging" + "github.com/splitio/go-toolkit/v4/logging" ) // Task interface @@ -17,7 +17,6 @@ type Task interface { type MultipleTask struct { tasks []Task logger logging.LoggerInterface - wg *sync.WaitGroup } // IsRunning method @@ -33,21 +32,22 @@ func (m MultipleTask) IsRunning() bool { // Start method func (m MultipleTask) Start() { for _, t := range m.tasks { - m.wg.Add(1) t.Start() } } // Stop method func (m MultipleTask) Stop(blocking bool) error { + wg := sync.WaitGroup{} + wg.Add(len(m.tasks)) for _, t := range m.tasks { go func(t Task) { t.Stop(blocking) - m.wg.Done() + wg.Done() }(t) } if blocking { - m.wg.Wait() + wg.Wait() } return nil } diff --git a/vendor/github.com/splitio/go-split-commons/v2/tasks/metricsync.go b/vendor/github.com/splitio/go-split-commons/v3/tasks/metricsync.go similarity index 75% rename from vendor/github.com/splitio/go-split-commons/v2/tasks/metricsync.go rename to vendor/github.com/splitio/go-split-commons/v3/tasks/metricsync.go index 93b81ffb27..d6faf5d907 100644 --- a/vendor/github.com/splitio/go-split-commons/v2/tasks/metricsync.go +++ b/vendor/github.com/splitio/go-split-commons/v3/tasks/metricsync.go @@ -1,9 +1,9 @@ package tasks import ( - "github.com/splitio/go-split-commons/v2/synchronizer/worker/metric" - "github.com/splitio/go-toolkit/v3/asynctask" - "github.com/splitio/go-toolkit/v3/logging" + "github.com/splitio/go-split-commons/v3/synchronizer/worker/metric" + "github.com/splitio/go-toolkit/v4/asynctask" + "github.com/splitio/go-toolkit/v4/logging" ) // NewRecordTelemetryTask creates a new telemtry recording task diff --git a/vendor/github.com/splitio/go-split-commons/v2/tasks/segmentsync.go b/vendor/github.com/splitio/go-split-commons/v3/tasks/segmentsync.go similarity index 84% rename from vendor/github.com/splitio/go-split-commons/v2/tasks/segmentsync.go rename to vendor/github.com/splitio/go-split-commons/v3/tasks/segmentsync.go index c0a1d9de31..8ee3d23ee1 100644 --- a/vendor/github.com/splitio/go-split-commons/v2/tasks/segmentsync.go +++ b/vendor/github.com/splitio/go-split-commons/v3/tasks/segmentsync.go @@ -5,14 +5,14 @@ import ( "fmt" "sync/atomic" - "github.com/splitio/go-split-commons/v2/synchronizer/worker/segment" - "github.com/splitio/go-toolkit/v3/asynctask" - "github.com/splitio/go-toolkit/v3/logging" - "github.com/splitio/go-toolkit/v3/workerpool" + "github.com/splitio/go-split-commons/v3/synchronizer/worker/segment" + "github.com/splitio/go-toolkit/v4/asynctask" + "github.com/splitio/go-toolkit/v4/logging" + "github.com/splitio/go-toolkit/v4/workerpool" ) func updateSegments( - fetcher segment.SegmentFetcher, + fetcher segment.Updater, admin *workerpool.WorkerAdmin, logger logging.LoggerInterface, ) error { @@ -36,7 +36,7 @@ func updateSegments( // NewFetchSegmentsTask creates a new segment fetching and storing task func NewFetchSegmentsTask( - fetcher segment.SegmentFetcher, + fetcher segment.Updater, period int, workerCount int, queueSize int, @@ -53,7 +53,7 @@ func NewFetchSegmentsTask( worker := NewSegmentWorker( fmt.Sprintf("SegmentWorker_%d", i), 0, - fetcher.SynchronizeSegment, + func(n string, t *int64) error { return fetcher.SynchronizeSegment(n, t, false) }, ) admin.Load().(*workerpool.WorkerAdmin).AddWorker(worker) } diff --git a/vendor/github.com/splitio/go-split-commons/v2/tasks/splitsync.go b/vendor/github.com/splitio/go-split-commons/v3/tasks/splitsync.go similarity index 58% rename from vendor/github.com/splitio/go-split-commons/v2/tasks/splitsync.go rename to vendor/github.com/splitio/go-split-commons/v3/tasks/splitsync.go index 4d1abdadf8..c5b50d3df6 100644 --- a/vendor/github.com/splitio/go-split-commons/v2/tasks/splitsync.go +++ b/vendor/github.com/splitio/go-split-commons/v3/tasks/splitsync.go @@ -1,19 +1,20 @@ package tasks import ( - "github.com/splitio/go-split-commons/v2/synchronizer/worker/split" - "github.com/splitio/go-toolkit/v3/asynctask" - "github.com/splitio/go-toolkit/v3/logging" + "github.com/splitio/go-split-commons/v3/synchronizer/worker/split" + "github.com/splitio/go-toolkit/v4/asynctask" + "github.com/splitio/go-toolkit/v4/logging" ) // NewFetchSplitsTask creates a new splits fetching and storing task func NewFetchSplitsTask( - fetcher split.SplitFetcher, + fetcher split.Updater, period int, logger logging.LoggerInterface, ) *asynctask.AsyncTask { update := func(logger logging.LoggerInterface) error { - return fetcher.SynchronizeSplits(nil) + _, err := fetcher.SynchronizeSplits(nil, false) + return err } return asynctask.NewAsyncTask("UpdateSplits", update, period, nil, nil, logger) diff --git a/vendor/github.com/splitio/go-split-commons/v2/tasks/worker.go b/vendor/github.com/splitio/go-split-commons/v3/tasks/worker.go similarity index 100% rename from vendor/github.com/splitio/go-split-commons/v2/tasks/worker.go rename to vendor/github.com/splitio/go-split-commons/v3/tasks/worker.go diff --git a/vendor/github.com/splitio/go-split-commons/v2/util/metrics.go b/vendor/github.com/splitio/go-split-commons/v3/util/metrics.go similarity index 100% rename from vendor/github.com/splitio/go-split-commons/v2/util/metrics.go rename to vendor/github.com/splitio/go-split-commons/v3/util/metrics.go diff --git a/vendor/github.com/splitio/go-split-commons/v2/util/mode.go b/vendor/github.com/splitio/go-split-commons/v3/util/mode.go similarity index 93% rename from vendor/github.com/splitio/go-split-commons/v2/util/mode.go rename to vendor/github.com/splitio/go-split-commons/v3/util/mode.go index 577917f9c0..445c37eb6a 100644 --- a/vendor/github.com/splitio/go-split-commons/v2/util/mode.go +++ b/vendor/github.com/splitio/go-split-commons/v3/util/mode.go @@ -3,7 +3,7 @@ package util import ( "strings" - "github.com/splitio/go-split-commons/v2/conf" + "github.com/splitio/go-split-commons/v3/conf" ) // ShouldAddPreviousTime returns if previous time should be set up or not depending on operationMode diff --git a/vendor/github.com/splitio/go-split-commons/v2/util/time.go b/vendor/github.com/splitio/go-split-commons/v3/util/time.go similarity index 100% rename from vendor/github.com/splitio/go-split-commons/v2/util/time.go rename to vendor/github.com/splitio/go-split-commons/v3/util/time.go diff --git a/vendor/github.com/splitio/go-toolkit/v3/sse/sse.go b/vendor/github.com/splitio/go-toolkit/v3/sse/sse.go deleted file mode 100644 index ffdc82363c..0000000000 --- a/vendor/github.com/splitio/go-toolkit/v3/sse/sse.go +++ /dev/null @@ -1,216 +0,0 @@ -package sse - -import ( - "bufio" - "bytes" - "context" - "encoding/json" - "errors" - "fmt" - "net/http" - "sync" - "sync/atomic" - "time" - - "github.com/splitio/go-toolkit/v3/logging" -) - -const ( - // OK It could connect streaming - OK = iota - // ErrorOnClientCreation Could not create client - ErrorOnClientCreation - // ErrorRequestPerformed Could not perform request - ErrorRequestPerformed - // ErrorConnectToStreaming Could not connect to streaming - ErrorConnectToStreaming - // ErrorReadingStream Error in streaming - ErrorReadingStream - // ErrorKeepAlive timedout - ErrorKeepAlive - // ErrorInternal Internal error for streaming - ErrorInternal - // ErrorUnexpected unexpected error occures - ErrorUnexpected -) - -var sseDelimiter [2]byte = [...]byte{':', ' '} -var sseData [4]byte = [...]byte{'d', 'a', 't', 'a'} -var sseKeepAlive [10]byte = [...]byte{':', 'k', 'e', 'e', 'p', 'a', 'l', 'i', 'v', 'e'} - -// SSEClient struct -type SSEClient struct { - url string - client http.Client - status chan int - shutdown chan struct{} - timeout int - logger logging.LoggerInterface -} - -// NewSSEClient creates new SSEClient -func NewSSEClient(url string, status chan int, timeout int, logger logging.LoggerInterface) (*SSEClient, error) { - if cap(status) < 1 { - return nil, errors.New("Status channel should have length") - } - if timeout < 1 { - return nil, errors.New("Timeout should be higher than 0") - } - return &SSEClient{ - url: url, - client: http.Client{}, - status: status, - shutdown: make(chan struct{}, 1), - timeout: timeout, - logger: logger, - }, nil -} - -// Shutdown stops SSE -func (l *SSEClient) Shutdown() { - select { - case l.shutdown <- struct{}{}: - default: - l.logger.Error("Shutdown already in progress") - } -} - -func parseData(raw []byte) (map[string]interface{}, error) { - data := make(map[string]interface{}) - err := json.Unmarshal(raw, &data) - if err != nil { - return nil, fmt.Errorf("error parsing json: %w", err) - } - return data, nil -} - -func (l *SSEClient) readEvent(reader *bufio.Reader) (map[string]interface{}, error) { - line, err := reader.ReadBytes('\n') - if err != nil { - return nil, err - } - - if len(line) < 2 { - return nil, nil - } - - splitted := bytes.Split(line, sseDelimiter[:]) - - if bytes.Compare(splitted[0], sseData[:]) != 0 { - return nil, nil - } - - raw := bytes.TrimSpace(splitted[1]) - l.logger.Debug("LINE:", string(line)) - data, err := parseData(raw) - if err != nil { - l.logger.Error("Error parsing event: ", err) - return nil, nil - } - - return data, nil -} - -func parseHTTPError(resp *http.Response) int { - if resp.StatusCode >= http.StatusInternalServerError { - return ErrorInternal - } - return ErrorConnectToStreaming -} - -// Do starts streaming -func (l *SSEClient) Do(params map[string]string, callback func(e map[string]interface{})) { - select { - case <-l.shutdown: - // Skipping previous shutdown - default: - } - ctx, cancel := context.WithCancel(context.Background()) - shouldRun := atomic.Value{} - shouldRun.Store(false) - activeGoroutines := sync.WaitGroup{} - defer func() { - l.logger.Info("SSE streaming exiting") - shouldRun.Store(false) - cancel() - activeGoroutines.Wait() - }() - - req, err := http.NewRequest("GET", l.url, nil) - if err != nil { - l.logger.Error(err) - l.status <- ErrorOnClientCreation - return - } - req = req.WithContext(ctx) - query := req.URL.Query() - - for key, value := range params { - query.Add(key, value) - } - req.URL.RawQuery = query.Encode() - req.Header.Set("Accept", "text/event-stream") - - resp, err := l.client.Do(req) - if err != nil { - l.logger.Error(err) - l.status <- ErrorRequestPerformed - return - } - - if resp.StatusCode != 200 { - l.status <- parseHTTPError(resp) - return - } - defer resp.Body.Close() - - l.status <- OK - reader := bufio.NewReader(resp.Body) - - eventChannel := make(chan map[string]interface{}, 1000) - shouldRun.Store(true) - go func() { - for shouldRun.Load().(bool) { - event, err := l.readEvent(reader) - if err != nil { - if shouldRun.Load().(bool) { - l.logger.Error(err) - } - close(eventChannel) - return - } - eventChannel <- event - } - }() - - // Create timeout timer in case SSE dont receive notifications or keepalive messages - idleDuration := time.Duration(l.timeout) * time.Second - keepAliveTimer := time.NewTimer(idleDuration) - defer keepAliveTimer.Stop() - - for { - // Resetting timer - keepAliveTimer.Reset(idleDuration) - - select { - case <-l.shutdown: - l.logger.Info("Shutting down listener") - return - case event, ok := <-eventChannel: - if !ok { - l.status <- ErrorReadingStream - return - } - if event != nil { - activeGoroutines.Add(1) - go func() { - defer activeGoroutines.Done() - callback(event) - }() - } - case <-keepAliveTimer.C: // Timedout - l.status <- ErrorKeepAlive - return - } - } -} diff --git a/vendor/github.com/splitio/go-toolkit/v3/LICENSE b/vendor/github.com/splitio/go-toolkit/v4/LICENSE similarity index 100% rename from vendor/github.com/splitio/go-toolkit/v3/LICENSE rename to vendor/github.com/splitio/go-toolkit/v4/LICENSE diff --git a/vendor/github.com/splitio/go-toolkit/v3/asynctask/asynctasks.go b/vendor/github.com/splitio/go-toolkit/v4/asynctask/asynctasks.go similarity index 55% rename from vendor/github.com/splitio/go-toolkit/v3/asynctask/asynctasks.go rename to vendor/github.com/splitio/go-toolkit/v4/asynctask/asynctasks.go index ad3f4b91a1..c475f25dbf 100644 --- a/vendor/github.com/splitio/go-toolkit/v3/asynctask/asynctasks.go +++ b/vendor/github.com/splitio/go-toolkit/v4/asynctask/asynctasks.go @@ -2,81 +2,66 @@ package asynctask import ( "fmt" - "sync/atomic" "time" - "github.com/splitio/go-toolkit/v3/logging" + "github.com/splitio/go-toolkit/v4/logging" + "github.com/splitio/go-toolkit/v4/struct/traits/lifecycle" ) // AsyncTask is a struct that wraps tasks that should run periodically and can be remotely stopped & started, // as well as making it's status (running/stopped) available. type AsyncTask struct { - task func(l logging.LoggerInterface) error - name string - running atomic.Value - incoming chan int - period int - onInit func(l logging.LoggerInterface) error - onStop func(l logging.LoggerInterface) - logger logging.LoggerInterface - finished atomic.Value - finishChan chan struct{} + lifecycle lifecycle.Manager + task func(l logging.LoggerInterface) error + name string + incoming chan int + period int + onInit func(l logging.LoggerInterface) error + onStop func(l logging.LoggerInterface) + logger logging.LoggerInterface } const ( - taskMessageStop = iota - taskMessageWakeup + taskMessageWakeup = iota ) -func (t *AsyncTask) _running() bool { - res, ok := t.running.Load().(bool) - if !ok { - t.logger.Error("Error parsing async task status flag") - return false - } - return res -} - // Start initiates the task. It wraps the execution in a closure guarded by a call to recover() in order // to prevent the main application from crashin if something goes wrong while the sdk interacts with the backend. func (t *AsyncTask) Start() { - if t._running() { + if !t.lifecycle.BeginInitialization() { if t.logger != nil { - t.logger.Warning("Task %s is already running. Aborting new execution.", t.name) + t.logger.Warning(fmt.Sprintf("Task %s is not idle. Aborting new execution.", t.name)) } return } - t.running.Store(true) go func() { - defer func() { - t.finished.Store(true) - t.finishChan <- struct{}{} - }() defer func() { if r := recover(); r != nil { - t.running.Store(false) if t.logger != nil { t.logger.Error(fmt.Sprintf( - "AsyncTask %s is panicking! Delaying execution for %d seconds (1 period)", + "AsyncTask %s is panicking! shutting down. Consider restarting this instance and raising an issue", t.name, - t.period, )) t.logger.Error(r) } - time.Sleep(time.Duration(t.period) * time.Second) } }() + defer t.lifecycle.ShutdownComplete() + if !t.lifecycle.InitializationComplete() { + return + } + // If there's an initialization function, execute it if t.onInit != nil { err := t.onInit(t.logger) - if err != nil { - // If something goes wrong during initialization, abort. + if err != nil { // If something goes wrong during initialization, abort. if t.logger != nil { t.logger.Error(err.Error()) } + t.lifecycle.AbnormalShutdown() return } } @@ -86,8 +71,19 @@ func (t *AsyncTask) Start() { taskTimer := time.NewTimer(idleDuration) defer taskTimer.Stop() + if t.onStop != nil { + defer t.onStop(t.logger) + } + // Task execution - for t._running() { + for { + select { + case <-t.lifecycle.ShutdownRequested(): + return + case <-t.incoming: // wake up signal + case <-taskTimer.C: // Timedout + } + // Run the wrapped task and handle the returned error if any. err := t.task(t.logger) if err != nil && t.logger != nil { @@ -96,22 +92,6 @@ func (t *AsyncTask) Start() { // Resetting timer taskTimer.Reset(idleDuration) - - // Wait for either a timeout or an interruption (can be a stop signal or a wake up) - select { - case msg := <-t.incoming: - switch msg { - case taskMessageStop: - t.running.Store(false) - case taskMessageWakeup: - } - case <-taskTimer.C: // Timedout - } - } - - // Post-execution cleanup - if t.onStop != nil { - t.onStop(t.logger) } }() } @@ -127,19 +107,12 @@ func (t *AsyncTask) sendSignal(signal int) error { // Stop executes onStop hook if any, blocks until its done (if blocking = true) and prevents future executions of the task. func (t *AsyncTask) Stop(blocking bool) error { - - if !t._running() || t.finished.Load().(bool) { - // Task already stopped - return nil - } - if err := t.sendSignal(taskMessageStop); err != nil { - // If the signal couldnt be sent, return error! - return err + if !t.lifecycle.BeginShutdown() { + return fmt.Errorf("task '%s' not running", t.name) } if blocking { - // If blocking was set to true, wait until an empty strcut is pushed into the channel - <-t.finishChan + t.lifecycle.AwaitShutdownComplete() } return nil } @@ -151,7 +124,7 @@ func (t *AsyncTask) WakeUp() error { // IsRunning returns true if the task is currently running func (t *AsyncTask) IsRunning() bool { - return t._running() + return t.lifecycle.IsRunning() } // NewAsyncTask creates a new task and returns a pointer to it @@ -164,16 +137,14 @@ func NewAsyncTask( logger logging.LoggerInterface, ) *AsyncTask { t := AsyncTask{ - name: name, - task: task, - period: period, - onInit: onInit, - onStop: onStop, - logger: logger, - incoming: make(chan int, 10), - finishChan: make(chan struct{}, 1), + name: name, + task: task, + period: period, + onInit: onInit, + onStop: onStop, + logger: logger, + incoming: make(chan int, 10), } - t.running.Store(false) - t.finished.Store(false) + t.lifecycle.Setup() return &t } diff --git a/vendor/github.com/splitio/go-toolkit/v4/backoff/backoff.go b/vendor/github.com/splitio/go-toolkit/v4/backoff/backoff.go new file mode 100644 index 0000000000..8e193d7ca5 --- /dev/null +++ b/vendor/github.com/splitio/go-toolkit/v4/backoff/backoff.go @@ -0,0 +1,35 @@ +package backoff + +import ( + "math" + "sync/atomic" + "time" +) + +// Interface is the backoff interface +type Interface interface { + Next() time.Duration + Reset() +} + +// Impl implements the Backoff interface +type Impl struct { + base int64 + current int64 +} + +// Next returns how long to wait and updates the current count +func (b *Impl) Next() time.Duration { + current := atomic.AddInt64(&b.current, 1) + return time.Duration(math.Pow(float64(b.base), float64(current))) * time.Second +} + +// Reset sets the current count to 0 +func (b *Impl) Reset() { + atomic.StoreInt64(&b.current, 0) +} + +// New creates a new Backoffer +func New() *Impl { + return &Impl{base: 2} +} diff --git a/vendor/github.com/splitio/go-toolkit/v3/common/interface.go b/vendor/github.com/splitio/go-toolkit/v4/common/interface.go similarity index 100% rename from vendor/github.com/splitio/go-toolkit/v3/common/interface.go rename to vendor/github.com/splitio/go-toolkit/v4/common/interface.go diff --git a/vendor/github.com/splitio/go-toolkit/v3/common/iterutil.go b/vendor/github.com/splitio/go-toolkit/v4/common/iterutil.go similarity index 100% rename from vendor/github.com/splitio/go-toolkit/v3/common/iterutil.go rename to vendor/github.com/splitio/go-toolkit/v4/common/iterutil.go diff --git a/vendor/github.com/splitio/go-toolkit/v3/common/refutil.go b/vendor/github.com/splitio/go-toolkit/v4/common/refutil.go similarity index 100% rename from vendor/github.com/splitio/go-toolkit/v3/common/refutil.go rename to vendor/github.com/splitio/go-toolkit/v4/common/refutil.go diff --git a/vendor/github.com/splitio/go-toolkit/v3/common/sliceutil.go b/vendor/github.com/splitio/go-toolkit/v4/common/sliceutil.go similarity index 100% rename from vendor/github.com/splitio/go-toolkit/v3/common/sliceutil.go rename to vendor/github.com/splitio/go-toolkit/v4/common/sliceutil.go diff --git a/vendor/github.com/splitio/go-toolkit/v3/common/strutil.go b/vendor/github.com/splitio/go-toolkit/v4/common/strutil.go similarity index 100% rename from vendor/github.com/splitio/go-toolkit/v3/common/strutil.go rename to vendor/github.com/splitio/go-toolkit/v4/common/strutil.go diff --git a/vendor/github.com/splitio/go-toolkit/v3/common/timeutil.go b/vendor/github.com/splitio/go-toolkit/v4/common/timeutil.go similarity index 100% rename from vendor/github.com/splitio/go-toolkit/v3/common/timeutil.go rename to vendor/github.com/splitio/go-toolkit/v4/common/timeutil.go diff --git a/vendor/github.com/splitio/go-toolkit/v3/datastructures/set/functions.go b/vendor/github.com/splitio/go-toolkit/v4/datastructures/set/functions.go similarity index 100% rename from vendor/github.com/splitio/go-toolkit/v3/datastructures/set/functions.go rename to vendor/github.com/splitio/go-toolkit/v4/datastructures/set/functions.go diff --git a/vendor/github.com/splitio/go-toolkit/v3/datastructures/set/implementations.go b/vendor/github.com/splitio/go-toolkit/v4/datastructures/set/implementations.go similarity index 100% rename from vendor/github.com/splitio/go-toolkit/v3/datastructures/set/implementations.go rename to vendor/github.com/splitio/go-toolkit/v4/datastructures/set/implementations.go diff --git a/vendor/github.com/splitio/go-toolkit/v3/datastructures/set/set.go b/vendor/github.com/splitio/go-toolkit/v4/datastructures/set/set.go similarity index 100% rename from vendor/github.com/splitio/go-toolkit/v3/datastructures/set/set.go rename to vendor/github.com/splitio/go-toolkit/v4/datastructures/set/set.go diff --git a/vendor/github.com/splitio/go-toolkit/v3/injection/container.go b/vendor/github.com/splitio/go-toolkit/v4/injection/container.go similarity index 100% rename from vendor/github.com/splitio/go-toolkit/v3/injection/container.go rename to vendor/github.com/splitio/go-toolkit/v4/injection/container.go diff --git a/vendor/github.com/splitio/go-toolkit/v3/logging/functions.go b/vendor/github.com/splitio/go-toolkit/v4/logging/functions.go similarity index 100% rename from vendor/github.com/splitio/go-toolkit/v3/logging/functions.go rename to vendor/github.com/splitio/go-toolkit/v4/logging/functions.go diff --git a/vendor/github.com/splitio/go-toolkit/v3/logging/interface.go b/vendor/github.com/splitio/go-toolkit/v4/logging/interface.go similarity index 100% rename from vendor/github.com/splitio/go-toolkit/v3/logging/interface.go rename to vendor/github.com/splitio/go-toolkit/v4/logging/interface.go diff --git a/vendor/github.com/splitio/go-toolkit/v3/logging/levels.go b/vendor/github.com/splitio/go-toolkit/v4/logging/levels.go similarity index 100% rename from vendor/github.com/splitio/go-toolkit/v3/logging/levels.go rename to vendor/github.com/splitio/go-toolkit/v4/logging/levels.go diff --git a/vendor/github.com/splitio/go-toolkit/v3/logging/logging.go b/vendor/github.com/splitio/go-toolkit/v4/logging/logging.go similarity index 100% rename from vendor/github.com/splitio/go-toolkit/v3/logging/logging.go rename to vendor/github.com/splitio/go-toolkit/v4/logging/logging.go diff --git a/vendor/github.com/splitio/go-toolkit/v3/logging/rotate.go b/vendor/github.com/splitio/go-toolkit/v4/logging/rotate.go similarity index 100% rename from vendor/github.com/splitio/go-toolkit/v3/logging/rotate.go rename to vendor/github.com/splitio/go-toolkit/v4/logging/rotate.go diff --git a/vendor/github.com/splitio/go-toolkit/v3/nethelpers/ip.go b/vendor/github.com/splitio/go-toolkit/v4/nethelpers/ip.go similarity index 100% rename from vendor/github.com/splitio/go-toolkit/v3/nethelpers/ip.go rename to vendor/github.com/splitio/go-toolkit/v4/nethelpers/ip.go diff --git a/vendor/github.com/splitio/go-toolkit/v3/provisional/hashing/murmur128.go b/vendor/github.com/splitio/go-toolkit/v4/provisional/hashing/murmur128.go similarity index 100% rename from vendor/github.com/splitio/go-toolkit/v3/provisional/hashing/murmur128.go rename to vendor/github.com/splitio/go-toolkit/v4/provisional/hashing/murmur128.go diff --git a/vendor/github.com/splitio/go-toolkit/v3/provisional/int64cache/cache.go b/vendor/github.com/splitio/go-toolkit/v4/provisional/int64cache/cache.go similarity index 100% rename from vendor/github.com/splitio/go-toolkit/v3/provisional/int64cache/cache.go rename to vendor/github.com/splitio/go-toolkit/v4/provisional/int64cache/cache.go diff --git a/vendor/github.com/splitio/go-toolkit/v3/queuecache/cache.go b/vendor/github.com/splitio/go-toolkit/v4/queuecache/cache.go similarity index 100% rename from vendor/github.com/splitio/go-toolkit/v3/queuecache/cache.go rename to vendor/github.com/splitio/go-toolkit/v4/queuecache/cache.go diff --git a/vendor/github.com/splitio/go-toolkit/v3/redis/helpers/helpers.go b/vendor/github.com/splitio/go-toolkit/v4/redis/helpers/helpers.go similarity index 89% rename from vendor/github.com/splitio/go-toolkit/v3/redis/helpers/helpers.go rename to vendor/github.com/splitio/go-toolkit/v4/redis/helpers/helpers.go index 7db01b9ecb..aa1d97a267 100644 --- a/vendor/github.com/splitio/go-toolkit/v3/redis/helpers/helpers.go +++ b/vendor/github.com/splitio/go-toolkit/v4/redis/helpers/helpers.go @@ -3,7 +3,7 @@ package helpers import ( "fmt" - "github.com/splitio/go-toolkit/v3/redis" + "github.com/splitio/go-toolkit/v4/redis" ) const ( diff --git a/vendor/github.com/splitio/go-toolkit/v3/redis/prefixedclient.go b/vendor/github.com/splitio/go-toolkit/v4/redis/prefixedclient.go similarity index 100% rename from vendor/github.com/splitio/go-toolkit/v3/redis/prefixedclient.go rename to vendor/github.com/splitio/go-toolkit/v4/redis/prefixedclient.go diff --git a/vendor/github.com/splitio/go-toolkit/v3/redis/types.go b/vendor/github.com/splitio/go-toolkit/v4/redis/types.go similarity index 100% rename from vendor/github.com/splitio/go-toolkit/v3/redis/types.go rename to vendor/github.com/splitio/go-toolkit/v4/redis/types.go diff --git a/vendor/github.com/splitio/go-toolkit/v3/redis/wrapper.go b/vendor/github.com/splitio/go-toolkit/v4/redis/wrapper.go similarity index 100% rename from vendor/github.com/splitio/go-toolkit/v3/redis/wrapper.go rename to vendor/github.com/splitio/go-toolkit/v4/redis/wrapper.go diff --git a/vendor/github.com/splitio/go-toolkit/v4/sse/errors.go b/vendor/github.com/splitio/go-toolkit/v4/sse/errors.go new file mode 100644 index 0000000000..a65c33d134 --- /dev/null +++ b/vendor/github.com/splitio/go-toolkit/v4/sse/errors.go @@ -0,0 +1,31 @@ +package sse + +import ( + "errors" +) + +// ErrNotIdle is the error tor eturn when Do() gets called on an already running client. +var ErrNotIdle = errors.New("sse client already running") + +// ErrReadingStream is the error to return when channel event channel is closed because of an error reading the stream +var ErrReadingStream = errors.New("sse channel closed") + +// ErrTimeout is the error to return when keepalive timeout is exceeded +var ErrTimeout = errors.New("timeout exceeeded") + +// ErrConnectionFailed contains a nested error +type ErrConnectionFailed struct { + wrapped error +} + +// Error returns the error as a string +func (e *ErrConnectionFailed) Error() string { + return "error connecting: " + e.wrapped.Error() +} + +// Unwrap returns the wrapped error +func (e *ErrConnectionFailed) Unwrap() error { + return e.wrapped +} + +var _ error = &ErrConnectionFailed{} diff --git a/vendor/github.com/splitio/go-toolkit/v4/sse/event.go b/vendor/github.com/splitio/go-toolkit/v4/sse/event.go new file mode 100644 index 0000000000..e0474b0f3d --- /dev/null +++ b/vendor/github.com/splitio/go-toolkit/v4/sse/event.go @@ -0,0 +1,120 @@ +package sse + +import ( + "strconv" + "strings" + "sync" +) + +const ( + sseDelimiter = ":" + sseData = "data" + sseEvent = "event" + sseID = "id" + sseRetry = "retry" +) + +// RawEvent interface contains the methods that expose the incoming SSE properties +type RawEvent interface { + ID() string + Event() string + Data() string + Retry() int64 + IsError() bool + IsEmpty() bool +} + +// RawEventImpl represents an incoming SSE event +type RawEventImpl struct { + id string + event string + data string + retry int64 +} + +// ID returns the event id +func (r *RawEventImpl) ID() string { return r.id } + +// Event returns the event type +func (r *RawEventImpl) Event() string { return r.event } + +// Data returns the event associated data +func (r *RawEventImpl) Data() string { return r.data } + +// Retry returns the expected retry time +func (r *RawEventImpl) Retry() int64 { return r.retry } + +// IsError returns true if the message is an error +func (r *RawEventImpl) IsError() bool { return r.event == "error" } + +// IsEmpty returns true if the event contains no id, event type and data +func (r *RawEventImpl) IsEmpty() bool { return r.event == "" && r.id == "" && r.data == "" } + +// EventBuilder interface +type EventBuilder interface { + AddLine(string) + Build() *RawEventImpl +} + +// EventBuilderImpl implenets the EventBuilder interface. Used to parse incoming event lines +type EventBuilderImpl struct { + includesComment bool + mutex sync.Mutex + lines []string +} + +// AddLine adds a new line belonging to the currently being processed event +func (b *EventBuilderImpl) AddLine(line string) { + if strings.HasPrefix(line, sseDelimiter) { + // Ignore comments + return + } + + b.mutex.Lock() + defer b.mutex.Unlock() + b.lines = append(b.lines, line) +} + +// Build processes all the added lines and builds the event +func (b *EventBuilderImpl) Build() *RawEventImpl { + b.mutex.Lock() + defer b.mutex.Unlock() + + if len(b.lines) == 0 { // Empty event + return &RawEventImpl{} + } + + e := &RawEventImpl{} + for _, line := range b.lines { + splitted := strings.SplitN(line, sseDelimiter, 2) + if len(splitted) != 2 { + // TODO: log invalid line. + continue + } + + switch splitted[0] { + case sseID: + e.id = strings.TrimSpace(splitted[1]) + case sseData: + e.data = strings.TrimSpace(splitted[1]) + case sseEvent: + e.event = strings.TrimSpace(splitted[1]) + case sseRetry: + e.retry, _ = strconv.ParseInt(strings.TrimSpace(splitted[1]), 10, 64) + } + } + + return e +} + +// Reset clears the lines accepted +func (b *EventBuilderImpl) Reset() { + b.mutex.Lock() + defer b.mutex.Unlock() + b.lines = []string{} +} + +// NewEventBuilder constructs a new event builder +func NewEventBuilder() *EventBuilderImpl { + return &EventBuilderImpl{lines: []string{}} +} diff --git a/vendor/github.com/splitio/go-toolkit/v4/sse/sse.go b/vendor/github.com/splitio/go-toolkit/v4/sse/sse.go new file mode 100644 index 0000000000..f924ed58e1 --- /dev/null +++ b/vendor/github.com/splitio/go-toolkit/v4/sse/sse.go @@ -0,0 +1,174 @@ +package sse + +import ( + "bufio" + "context" + "errors" + "fmt" + "net/http" + "sync" + "time" + + "github.com/splitio/go-toolkit/v4/logging" + "github.com/splitio/go-toolkit/v4/struct/traits/lifecycle" +) + +const ( + statusIdle = iota + statusRunning + statusShuttingDown + + endOfLineChar = '\n' + endOfLineStr = "\n" +) + +// Client struct +type Client struct { + lifecycle lifecycle.Manager + url string + client http.Client + timeout time.Duration + logger logging.LoggerInterface +} + +// NewClient creates new SSEClient +func NewClient(url string, timeout int, logger logging.LoggerInterface) (*Client, error) { + if timeout < 1 { + return nil, errors.New("Timeout should be higher than 0") + } + + client := &Client{ + url: url, + client: http.Client{}, + timeout: time.Duration(timeout) * time.Second, + logger: logger, + } + client.lifecycle.Setup() + return client, nil +} + +func (l *Client) readEvents(in *bufio.Reader, out chan<- RawEvent) { + eventBuilder := NewEventBuilder() + for { + line, err := in.ReadString(endOfLineChar) + l.logger.Debug("Incoming SSE line: ", line) + if err != nil { + if l.lifecycle.IsRunning() { // If it's supposed to be running, log an error + l.logger.Error(err) + } + close(out) + return + } + if line != endOfLineStr { + eventBuilder.AddLine(line) + continue + + } + l.logger.Debug("Building SSE event") + if event := eventBuilder.Build(); event != nil { + out <- event + } + eventBuilder.Reset() + } +} + +// Do starts streaming +func (l *Client) Do(params map[string]string, callback func(e RawEvent)) error { + + if !l.lifecycle.BeginInitialization() { + return ErrNotIdle + } + + activeGoroutines := sync.WaitGroup{} + + ctx, cancel := context.WithCancel(context.Background()) + defer func() { + l.logger.Info("SSE streaming exiting") + cancel() + activeGoroutines.Wait() + l.lifecycle.ShutdownComplete() + }() + + req, err := l.buildCancellableRequest(ctx, params) + if err != nil { + return &ErrConnectionFailed{wrapped: fmt.Errorf("error building request: %w", err)} + } + + resp, err := l.client.Do(req) + if err != nil { + return &ErrConnectionFailed{wrapped: fmt.Errorf("error issuing request: %w", err)} + } + if resp.StatusCode != 200 { + return &ErrConnectionFailed{wrapped: fmt.Errorf("sse request status code: %d", resp.StatusCode)} + } + defer resp.Body.Close() + + if !l.lifecycle.InitializationComplete() { + return nil + } + + reader := bufio.NewReader(resp.Body) + eventChannel := make(chan RawEvent, 1000) + go l.readEvents(reader, eventChannel) + + // Create timeout timer in case SSE dont receive notifications or keepalive messages + keepAliveTimer := time.NewTimer(l.timeout) + defer keepAliveTimer.Stop() + + for { + select { + case <-l.lifecycle.ShutdownRequested(): + l.logger.Info("Shutting down listener") + return nil + case event, ok := <-eventChannel: + keepAliveTimer.Reset(l.timeout) + if !ok { + if l.lifecycle.IsRunning() { + return ErrReadingStream + } + return nil + } + + if event.IsEmpty() { + continue // don't forward empty/comment events + } + activeGoroutines.Add(1) + go func() { + defer activeGoroutines.Done() + callback(event) + }() + case <-keepAliveTimer.C: // Timeout + l.logger.Warning("SSE idle timeout.") + l.lifecycle.AbnormalShutdown() + return ErrTimeout + } + } +} + +// Shutdown stops SSE +func (l *Client) Shutdown(blocking bool) { + if !l.lifecycle.BeginShutdown() { + l.logger.Info("SSE client stopped or shutdown in progress. Ignoring.") + return + } + + if blocking { + l.lifecycle.AwaitShutdownComplete() + } +} + +func (l *Client) buildCancellableRequest(ctx context.Context, params map[string]string) (*http.Request, error) { + req, err := http.NewRequest("GET", l.url, nil) + if err != nil { + return nil, fmt.Errorf("error instantiating request: %w", err) + } + req = req.WithContext(ctx) + query := req.URL.Query() + + for key, value := range params { + query.Add(key, value) + } + req.URL.RawQuery = query.Encode() + req.Header.Set("Accept", "text/event-stream") + return req, nil +} diff --git a/vendor/github.com/splitio/go-toolkit/v4/struct/traits/lifecycle/lifecycle.go b/vendor/github.com/splitio/go-toolkit/v4/struct/traits/lifecycle/lifecycle.go new file mode 100644 index 0000000000..765b7bcb46 --- /dev/null +++ b/vendor/github.com/splitio/go-toolkit/v4/struct/traits/lifecycle/lifecycle.go @@ -0,0 +1,108 @@ +package lifecycle + +import ( + "sync" + "sync/atomic" +) + +// Status constants +const ( + StatusIdle = iota + StatusStarting + StatusInitializationCancelled + StatusRunning + StatusStopping +) + +// Status type alias +type Status = int32 + +// Manager is a trait to be embedded in structs that manage the lifecycle of goroutines. +// The trait enables the struct to easily switch between states and await proper shutdown +type Manager struct { + status int32 + c *sync.Cond + shutdown chan struct{} +} + +// Setup must be called in the struct constructor +func (l *Manager) Setup() { + l.c = sync.NewCond(&sync.Mutex{}) + l.shutdown = make(chan struct{}, 1) +} + +// BeginInitialization should be called in the .Start() method (or whichever begins the async work) +func (l *Manager) BeginInitialization() bool { + return atomic.CompareAndSwapInt32(&l.status, StatusIdle, StatusStarting) +} + +// InitializationComplete should be called just prior to the `go ...` directive starting the async work +func (l *Manager) InitializationComplete() bool { + if !atomic.CompareAndSwapInt32(&l.status, StatusStarting, StatusRunning) { + atomic.StoreInt32(&l.status, StatusStopping) + return false + } + return true +} + +// BeginShutdown should be called on the .Stop() method or whichever makes a request for the async work to stop +func (l *Manager) BeginShutdown() bool { + // If we're currently initializing but not yet running, just change the status. + if atomic.CompareAndSwapInt32(&l.status, StatusStarting, StatusInitializationCancelled) { + return true + } + + if !atomic.CompareAndSwapInt32(&l.status, StatusRunning, StatusStopping) { + return false + } + + l.shutdown <- struct{}{} + return true +} + +// ShutdownComplete should be called just before the goroutine exits. (ie: it should be the FIRST deferred func) +func (l *Manager) ShutdownComplete() { + // clean up status channel in case a Stop occurred while the task was exiting on its own + select { + case <-l.shutdown: + default: + } + + l.c.L.Lock() + atomic.StoreInt32(&l.status, StatusIdle) + l.c.Broadcast() + l.c.L.Unlock() +} + +// AwaitShutdownComplete can be called in case you need to join against the goroutine's end +func (l *Manager) AwaitShutdownComplete() { + for { + l.c.L.Lock() + if atomic.LoadInt32(&l.status) == StatusIdle { + l.c.L.Unlock() + return + } + l.c.Wait() + l.c.L.Unlock() + } +} + +// ShutdownRequested should be queried in a select statement, which should react by terminating the goroutine +func (l *Manager) ShutdownRequested() <-chan struct{} { + return l.shutdown +} + +// AbnormalShutdown should be called when the goroutine exits without Stop being called. +func (l *Manager) AbnormalShutdown() { + atomic.CompareAndSwapInt32(&l.status, StatusRunning, StatusStopping) +} + +// Status Returns the current status as an int32 constant +func (l *Manager) Status() int32 { + return atomic.LoadInt32(&l.status) +} + +// IsRunning returns true if the BG work is still going on +func (l *Manager) IsRunning() bool { + return atomic.LoadInt32(&l.status) == StatusRunning +} diff --git a/vendor/github.com/splitio/go-toolkit/v4/sync/atomicbool.go b/vendor/github.com/splitio/go-toolkit/v4/sync/atomicbool.go new file mode 100644 index 0000000000..fef5b859b4 --- /dev/null +++ b/vendor/github.com/splitio/go-toolkit/v4/sync/atomicbool.go @@ -0,0 +1,41 @@ +package sync + +import ( + "sync/atomic" +) + +const ( + falseValue = 0 + trueValue = 1 +) + +type AtomicBool struct { + value uint32 +} + +func (b *AtomicBool) Set() { + atomic.StoreUint32(&b.value, trueValue) +} + +func (b *AtomicBool) Unset() { + atomic.StoreUint32(&b.value, falseValue) +} + +func (b *AtomicBool) IsSet() bool { + return atomic.LoadUint32(&b.value) == trueValue +} + +func (b *AtomicBool) TestAndSet() bool { + return atomic.CompareAndSwapUint32(&b.value, falseValue, trueValue) +} + +func (b *AtomicBool) TestAndClear() bool { + return atomic.CompareAndSwapUint32(&b.value, trueValue, falseValue) +} + +func NewAtomicBool(initialValue bool) *AtomicBool { + if initialValue { + return &AtomicBool{value: trueValue} + } + return &AtomicBool{} +} diff --git a/vendor/github.com/splitio/go-toolkit/v3/workerpool/workerpool.go b/vendor/github.com/splitio/go-toolkit/v4/workerpool/workerpool.go similarity index 52% rename from vendor/github.com/splitio/go-toolkit/v3/workerpool/workerpool.go rename to vendor/github.com/splitio/go-toolkit/v4/workerpool/workerpool.go index 6e29e46c23..fcd0026ab1 100644 --- a/vendor/github.com/splitio/go-toolkit/v3/workerpool/workerpool.go +++ b/vendor/github.com/splitio/go-toolkit/v4/workerpool/workerpool.go @@ -2,9 +2,11 @@ package workerpool import ( "fmt" - "github.com/splitio/go-toolkit/v3/logging" "sync" "time" + + "github.com/splitio/go-toolkit/v4/logging" + "github.com/splitio/go-toolkit/v4/struct/traits/lifecycle" ) const ( @@ -13,11 +15,11 @@ const ( // WorkerAdmin struct handles multiple worker execution, popping jobs from a single queue type WorkerAdmin struct { - queue chan interface{} - signalsMutex sync.RWMutex - signals map[string]chan int - logger logging.LoggerInterface - wg sync.WaitGroup + queue chan interface{} + mutex sync.RWMutex + //signals map[string]chan int + workers map[string]*workerWrapper + logger logging.LoggerInterface } // Worker interface should be implemented by concrete workers that will perform the actual job @@ -34,53 +36,77 @@ type Worker interface { FailureTime() int64 } -func (a *WorkerAdmin) workerWrapper(w Worker) { - a.signalsMutex.Lock() - a.signals[w.Name()] = make(chan int, 10) - a.signalsMutex.Unlock() - defer a.wg.Done() +type workerWrapper struct { + w Worker + lifecycle lifecycle.Manager + queue <-chan interface{} + logger logging.LoggerInterface +} + +func (w *workerWrapper) Start() { + if !w.lifecycle.BeginInitialization() { + w.logger.Error(fmt.Sprintf("initialization of worker '%s' aborted. Worker not idle.", w.w.Name())) + return + } + go w.do() +} + +func (w *workerWrapper) Stop(blocking bool) { + if !w.lifecycle.BeginShutdown() { + w.logger.Error(fmt.Sprintf("shutodwn of worker '%s' aborted. Worker not running.", w.w.Name())) + return + } + + if blocking { + w.lifecycle.AwaitShutdownComplete() + } +} + +func (w *workerWrapper) do() { defer func() { if r := recover(); r != nil { - a.logger.Error(fmt.Sprintf( + w.logger.Error(fmt.Sprintf( "Worker %s is panicking with the following error \"%s\" and will be shutted down.", - w.Name(), + w.w.Name(), r, )) - } - if a.signals != nil { // This should ALWAYS be the case, but just in case... we don't want to panic here. - a.signalsMutex.Lock() - delete(a.signals, w.Name()) - a.signalsMutex.Unlock() + w.lifecycle.AbnormalShutdown() } }() - defer w.Cleanup() + defer w.lifecycle.ShutdownComplete() + defer w.w.Cleanup() + if !w.lifecycle.InitializationComplete() { + return + } for { - a.signalsMutex.RLock() - signal := a.signals[w.Name()] - a.signalsMutex.RUnlock() select { - case msg := <-signal: - switch msg { - case workerSignalStop: - return - } - case msg := <-a.queue: - if err := w.DoWork(msg); err != nil { - w.OnError(err) - time.Sleep(time.Duration(w.FailureTime()) * time.Millisecond) + case <-w.lifecycle.ShutdownRequested(): + return + case msg := <-w.queue: + if err := w.w.DoWork(msg); err != nil { + w.w.OnError(err) + time.Sleep(time.Duration(w.w.FailureTime()) * time.Millisecond) } } } } +func newWorkerWraper(w Worker, logger logging.LoggerInterface, queue <-chan interface{}) *workerWrapper { + worker := &workerWrapper{w: w, queue: queue, logger: logger} + worker.lifecycle.Setup() + worker.Start() + return worker +} + // AddWorker registers a new worker in the admin func (a *WorkerAdmin) AddWorker(w Worker) { if w == nil { a.logger.Error("AddWorker called with nil") return } - a.wg.Add(1) - go a.workerWrapper(w) + a.mutex.Lock() + defer a.mutex.Unlock() + a.workers[w.Name()] = newWorkerWraper(w, a.logger, a.queue) } // QueueMessage adds a new message that will be popped by a worker and processed @@ -98,48 +124,37 @@ func (a *WorkerAdmin) QueueMessage(m interface{}) bool { } // StopWorker ends the worker's event loop, preventing it from picking further jobs -func (a *WorkerAdmin) StopWorker(name string) error { - a.signalsMutex.RLock() - c, ok := a.signals[name] - a.signalsMutex.RUnlock() +func (a *WorkerAdmin) StopWorker(name string, blocking bool) error { + a.mutex.Lock() + defer a.mutex.Unlock() + w, ok := a.workers[name] if !ok { return fmt.Errorf("Worker %s doesn't exist, hence it cannot be stopped", name) } - select { - case c <- workerSignalStop: - default: - return fmt.Errorf("Couldn't send stop signal to worker %s", name) - } + + w.Stop(blocking) + return nil } // StopAll ends all worker's event loops func (a *WorkerAdmin) StopAll(blocking bool) error { - failed := make([]string, 0) - workerNames := make([]string, 0) - - // Get worker names safely - a.signalsMutex.RLock() - for workerName := range a.signals { - workerNames = append(workerNames, workerName) - } - a.signalsMutex.RUnlock() - - for _, workerName := range workerNames { - err := a.StopWorker(workerName) - if err != nil { - a.logger.Error(err) - failed = append(failed, workerName) + wg := sync.WaitGroup{} + a.mutex.Lock() + defer a.mutex.Unlock() + for _, w := range a.workers { + if w != nil { + wg.Add(1) + go func(current *workerWrapper) { + current.Stop(true) + wg.Done() + }(w) } } - if len(failed) > 0 { - return fmt.Errorf("Workers %v failed to shutdown", failed) - } if blocking { - a.wg.Wait() + wg.Wait() } - return nil } @@ -150,16 +165,16 @@ func (a *WorkerAdmin) QueueSize() int { // IsWorkerRunning returns true if the worker exists and is currently running func (a *WorkerAdmin) IsWorkerRunning(name string) bool { - a.signalsMutex.RLock() - _, ok := a.signals[name] - a.signalsMutex.RUnlock() - return ok // We consider a worker to be running if it exists in the list of valid signal channels + a.mutex.RLock() + defer a.mutex.RUnlock() + x, ok := a.workers[name] + return ok && x.lifecycle.IsRunning() } // NewWorkerAdmin instantiates a new WorkerAdmin and returns a pointer to it. func NewWorkerAdmin(queueSize int, logger logging.LoggerInterface) *WorkerAdmin { return &WorkerAdmin{ - signals: make(map[string]chan int, 0), + workers: make(map[string]*workerWrapper, 0), logger: logger, queue: make(chan interface{}, queueSize), } diff --git a/vendor/modules.txt b/vendor/modules.txt index 7bed20a366..bc1fd362bf 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -568,7 +568,7 @@ github.com/sirupsen/logrus github.com/spf13/cobra # github.com/spf13/pflag v1.0.5 github.com/spf13/pflag -# github.com/splitio/go-client/v6 v6.0.1 +# github.com/splitio/go-client/v6 v6.0.2 ## explicit github.com/splitio/go-client/v6/splitio github.com/splitio/go-client/v6/splitio/client @@ -582,42 +582,47 @@ github.com/splitio/go-client/v6/splitio/engine/grammar/matchers/datatypes github.com/splitio/go-client/v6/splitio/engine/hash github.com/splitio/go-client/v6/splitio/impressionListener # github.com/splitio/go-split-commons/v2 v2.0.1 -github.com/splitio/go-split-commons/v2/conf -github.com/splitio/go-split-commons/v2/dtos -github.com/splitio/go-split-commons/v2/provisional -github.com/splitio/go-split-commons/v2/push -github.com/splitio/go-split-commons/v2/service -github.com/splitio/go-split-commons/v2/service/api -github.com/splitio/go-split-commons/v2/service/api/sse -github.com/splitio/go-split-commons/v2/service/local -github.com/splitio/go-split-commons/v2/storage -github.com/splitio/go-split-commons/v2/storage/mocks -github.com/splitio/go-split-commons/v2/storage/mutexmap -github.com/splitio/go-split-commons/v2/storage/mutexqueue -github.com/splitio/go-split-commons/v2/storage/redis -github.com/splitio/go-split-commons/v2/synchronizer -github.com/splitio/go-split-commons/v2/synchronizer/worker/event -github.com/splitio/go-split-commons/v2/synchronizer/worker/impression -github.com/splitio/go-split-commons/v2/synchronizer/worker/impressionscount -github.com/splitio/go-split-commons/v2/synchronizer/worker/metric -github.com/splitio/go-split-commons/v2/synchronizer/worker/segment -github.com/splitio/go-split-commons/v2/synchronizer/worker/split -github.com/splitio/go-split-commons/v2/tasks -github.com/splitio/go-split-commons/v2/util -# github.com/splitio/go-toolkit/v3 v3.0.1 -github.com/splitio/go-toolkit/v3/asynctask -github.com/splitio/go-toolkit/v3/common -github.com/splitio/go-toolkit/v3/datastructures/set -github.com/splitio/go-toolkit/v3/injection -github.com/splitio/go-toolkit/v3/logging -github.com/splitio/go-toolkit/v3/nethelpers -github.com/splitio/go-toolkit/v3/provisional/hashing -github.com/splitio/go-toolkit/v3/provisional/int64cache -github.com/splitio/go-toolkit/v3/queuecache -github.com/splitio/go-toolkit/v3/redis -github.com/splitio/go-toolkit/v3/redis/helpers -github.com/splitio/go-toolkit/v3/sse -github.com/splitio/go-toolkit/v3/workerpool +## explicit +# github.com/splitio/go-split-commons/v3 v3.0.0 +github.com/splitio/go-split-commons/v3/conf +github.com/splitio/go-split-commons/v3/dtos +github.com/splitio/go-split-commons/v3/provisional +github.com/splitio/go-split-commons/v3/push +github.com/splitio/go-split-commons/v3/service +github.com/splitio/go-split-commons/v3/service/api +github.com/splitio/go-split-commons/v3/service/api/sse +github.com/splitio/go-split-commons/v3/service/local +github.com/splitio/go-split-commons/v3/storage +github.com/splitio/go-split-commons/v3/storage/mocks +github.com/splitio/go-split-commons/v3/storage/mutexmap +github.com/splitio/go-split-commons/v3/storage/mutexqueue +github.com/splitio/go-split-commons/v3/storage/redis +github.com/splitio/go-split-commons/v3/synchronizer +github.com/splitio/go-split-commons/v3/synchronizer/worker/event +github.com/splitio/go-split-commons/v3/synchronizer/worker/impression +github.com/splitio/go-split-commons/v3/synchronizer/worker/impressionscount +github.com/splitio/go-split-commons/v3/synchronizer/worker/metric +github.com/splitio/go-split-commons/v3/synchronizer/worker/segment +github.com/splitio/go-split-commons/v3/synchronizer/worker/split +github.com/splitio/go-split-commons/v3/tasks +github.com/splitio/go-split-commons/v3/util +# github.com/splitio/go-toolkit/v4 v4.0.0 +github.com/splitio/go-toolkit/v4/asynctask +github.com/splitio/go-toolkit/v4/backoff +github.com/splitio/go-toolkit/v4/common +github.com/splitio/go-toolkit/v4/datastructures/set +github.com/splitio/go-toolkit/v4/injection +github.com/splitio/go-toolkit/v4/logging +github.com/splitio/go-toolkit/v4/nethelpers +github.com/splitio/go-toolkit/v4/provisional/hashing +github.com/splitio/go-toolkit/v4/provisional/int64cache +github.com/splitio/go-toolkit/v4/queuecache +github.com/splitio/go-toolkit/v4/redis +github.com/splitio/go-toolkit/v4/redis/helpers +github.com/splitio/go-toolkit/v4/sse +github.com/splitio/go-toolkit/v4/struct/traits/lifecycle +github.com/splitio/go-toolkit/v4/sync +github.com/splitio/go-toolkit/v4/workerpool # github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf github.com/ssor/bom # github.com/steveyen/gtreap v0.1.0