From cbb85bf50da93fc787e5d13d3860f1e8743bddbe Mon Sep 17 00:00:00 2001 From: Italo Lelis de Vietro Date: Thu, 27 Oct 2016 00:23:00 +0200 Subject: [PATCH 01/74] Basic structure --- .gitignore | 26 ++++++++++++++++++++++++++ .travis.yml | 14 ++++++++++++++ Dockerfile | 12 ++++++++++++ Makefile | 31 +++++++++++++++++++++++++++++++ docker-compose.yml | 17 +++++++++++++++++ 5 files changed, 100 insertions(+) create mode 100644 .gitignore create mode 100644 .travis.yml create mode 100644 Dockerfile create mode 100644 Makefile create mode 100644 docker-compose.yml diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..e0956511 --- /dev/null +++ b/.gitignore @@ -0,0 +1,26 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj/ +_test/ +vendor/ + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof +gin-bin \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..db23233a --- /dev/null +++ b/.travis.yml @@ -0,0 +1,14 @@ +language: go + +services: + - docker + +go: + - 1.6 + - 1.7 + - master + +install: + - docker-compose up -d + +script: make test diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..5ee29bac --- /dev/null +++ b/Dockerfile @@ -0,0 +1,12 @@ +FROM golang:1.7 + +ENV APP_DIR $GOPATH/src/github.com/hellofresh/goengine + +RUN mkdir -p $APP_DIR + +COPY . $APP_DIR +WORKDIR $APP_DIR + +RUN make + +CMD ["go-wrapper", "run"] \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..5c410012 --- /dev/null +++ b/Makefile @@ -0,0 +1,31 @@ +NO_COLOR=\033[0m +OK_COLOR=\033[32;01m +ERROR_COLOR=\033[31;01m +WARN_COLOR=\033[33;01m + +# This how we want to name the binary output +BINARY=goengine + +.PHONY: all clean deps install + +all: clean deps install + +deps: + @echo "$(OK_COLOR)==> Installing glide dependencies$(NO_COLOR)" + @curl https://glide.sh/get | sh + @glide install + +# Builds the project +build: + @echo "$(OK_COLOR)==> Building project$(NO_COLOR)" + @go build -o ${BINARY} + +# Installs our project: copies binaries +install: + @echo "$(OK_COLOR)==> Installing project$(NO_COLOR)" + go install -v + +# Cleans our project: deletes binaries +clean: + @echo "$(OK_COLOR)==> Cleaning project$(NO_COLOR)" + if [ -f ${BINARY} ] ; then rm ${BINARY} ; fi diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..7f6b7ebf --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,17 @@ +version: 2 +services: + + app: + build: ./ + volumes: + - ./src/github.com/hellofresh/auth-service:/go/src/github.com/hellofresh/auth-service + environment: + STORAGE_DSN: 'mongodb://mongo/goengine' + + redis: + image: redis + + mongo: + image: mongo + ports: + - "27017:27017" From c0741e67c41f95abde42b066a856de50743734d0 Mon Sep 17 00:00:00 2001 From: Italo Lelis de Vietro Date: Thu, 27 Oct 2016 00:23:15 +0200 Subject: [PATCH 02/74] Added in memory event store and tests --- eventstore/domain_message.go | 19 ++++++++++ eventstore/event_store.go | 44 +++++++++++++++++++++++ eventstore/event_store_test.go | 56 +++++++++++++++++++++++++++++ eventstore/event_stream.go | 18 ++++++++++ eventstore/eventstore_suite_test.go | 13 +++++++ eventstore/in_memory_store.go | 41 +++++++++++++++++++++ eventstore/in_memory_store_test.go | 53 +++++++++++++++++++++++++++ eventstore/mock_test.go | 17 +++++++++ 8 files changed, 261 insertions(+) create mode 100644 eventstore/domain_message.go create mode 100644 eventstore/event_store.go create mode 100644 eventstore/event_store_test.go create mode 100644 eventstore/event_stream.go create mode 100644 eventstore/eventstore_suite_test.go create mode 100644 eventstore/in_memory_store.go create mode 100644 eventstore/in_memory_store_test.go create mode 100644 eventstore/mock_test.go diff --git a/eventstore/domain_message.go b/eventstore/domain_message.go new file mode 100644 index 00000000..53c34776 --- /dev/null +++ b/eventstore/domain_message.go @@ -0,0 +1,19 @@ +package eventstore + +import "time" + +type DomainMessage struct { + ID string + version int + payload DomainEvent + recordedOn time.Time +} + +func NewDomainMessage(id string, version int, payload DomainEvent, recordedOn time.Time) *DomainMessage { + return &DomainMessage{id, version, payload, recordedOn} +} + +func RecordNow(id string, version int, payload DomainEvent) *DomainMessage { + recordedTime := time.Now() + return NewDomainMessage(id, version, payload, recordedTime) +} diff --git a/eventstore/event_store.go b/eventstore/event_store.go new file mode 100644 index 00000000..4df9e17a --- /dev/null +++ b/eventstore/event_store.go @@ -0,0 +1,44 @@ +package eventstore + +type EventStore interface { + Append(events *EventStream) + GetEventsFor(streamName StreamName, id string) *EventStream + FromVersion(streamName StreamName, id string, version int) *EventStream + CountEventsFor(streamName StreamName, id string) int +} + +type EventStoreAdapter interface { + Save(streamName StreamName, events *DomainMessage) + GetEventsFor(streamName StreamName, id string) []*DomainMessage + FromVersion(streamName StreamName, id string, version int) []*DomainMessage + CountEventsFor(streamName StreamName, id string) int +} + +type EventStoreImp struct { + adapter EventStoreAdapter +} + +func NewEventStore(adapter EventStoreAdapter) *EventStoreImp { + return &EventStoreImp{adapter} +} + +func (es *EventStoreImp) Append(events *EventStream) { + name := events.Name + for _, event := range events.Events { + es.adapter.Save(name, event) + } +} + +func (es *EventStoreImp) FromVersion(streamName StreamName, id string, version int) *EventStream { + events := es.adapter.FromVersion(streamName, id, version) + return NewEventStream(streamName, events) +} + +func (es *EventStoreImp) GetEventsFor(streamName StreamName, id string) *EventStream { + events := es.adapter.GetEventsFor(streamName, id) + return NewEventStream(streamName, events) +} + +func (es *EventStoreImp) CountEventsFor(streamName StreamName, id string) int { + return es.adapter.CountEventsFor(streamName, id) +} diff --git a/eventstore/event_store_test.go b/eventstore/event_store_test.go new file mode 100644 index 00000000..f8ebc0ba --- /dev/null +++ b/eventstore/event_store_test.go @@ -0,0 +1,56 @@ +package eventstore_test + +import ( + . "github.com/hellofresh/goengine/eventstore" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("A Event Store", func() { + var eventStream *EventStream + var store EventStore + var aggregateId string + var streamName StreamName + + adapter := NewInMemoryEventStore() + store = NewEventStore(adapter) + + BeforeEach(func() { + eventStream = nil + aggregateId = "594fb936-d646-44b5-a152-84eb4f709f20" + streamName = "test" + }) + + JustBeforeEach(func() { + var events []*DomainMessage + + events = append(events, RecordNow(aggregateId, 0, NewSomethingHappened())) + events = append(events, RecordNow(aggregateId, 1, NewSomethingHappened())) + events = append(events, RecordNow(aggregateId, 2, NewSomethingHappened())) + + eventStream = NewEventStream(streamName, events) + }) + + Describe("when something happens", func() { + It("should save an event", func() { + store.Append(eventStream) + }) + + It("should retrive the things that happened", func() { + expectedEvents := store.GetEventsFor(streamName, aggregateId) + + Expect(expectedEvents.Events).To(HaveLen(3)) + }) + + It("should count the events that happened", func() { + Expect(store.CountEventsFor(streamName, aggregateId)).Should(Equal(3)) + }) + + It("should retrieve events for version bigger then 1", func() { + expectedEvents := store.FromVersion(streamName, aggregateId, 1) + + Expect(expectedEvents.Events).To(HaveLen(2)) + }) + }) +}) diff --git a/eventstore/event_stream.go b/eventstore/event_stream.go new file mode 100644 index 00000000..edf61341 --- /dev/null +++ b/eventstore/event_stream.go @@ -0,0 +1,18 @@ +package eventstore + +import "time" + +type DomainEvent interface { + OcurredOn() time.Time +} + +type StreamName string + +type EventStream struct { + Name StreamName + Events []*DomainMessage +} + +func NewEventStream(name StreamName, events []*DomainMessage) *EventStream { + return &EventStream{name, events} +} diff --git a/eventstore/eventstore_suite_test.go b/eventstore/eventstore_suite_test.go new file mode 100644 index 00000000..649d0228 --- /dev/null +++ b/eventstore/eventstore_suite_test.go @@ -0,0 +1,13 @@ +package eventstore_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "testing" +) + +func TestGoengine(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Event Store Suite") +} diff --git a/eventstore/in_memory_store.go b/eventstore/in_memory_store.go new file mode 100644 index 00000000..a4a630d7 --- /dev/null +++ b/eventstore/in_memory_store.go @@ -0,0 +1,41 @@ +package eventstore + +type InMemoryEventStore struct { + events map[StreamName]map[string][]*DomainMessage +} + +func NewInMemoryEventStore() *InMemoryEventStore { + return &InMemoryEventStore{make(map[StreamName]map[string][]*DomainMessage)} +} + +func (s *InMemoryEventStore) Save(streamName StreamName, event *DomainMessage) { + id := event.ID + events, exists := s.events[streamName][id] + + if !exists { + s.events[streamName] = make(map[string][]*DomainMessage) + } + + s.events[streamName][id] = append(events, event) +} + +func (s *InMemoryEventStore) GetEventsFor(streamName StreamName, id string) []*DomainMessage { + return s.events[streamName][id] +} + +func (s *InMemoryEventStore) FromVersion(streamName StreamName, id string, version int) []*DomainMessage { + events := s.GetEventsFor(streamName, id) + var filtered []*DomainMessage + + for _, event := range events { + if event.version >= version { + filtered = append(filtered, event) + } + } + + return filtered +} + +func (s *InMemoryEventStore) CountEventsFor(streamName StreamName, id string) int { + return len(s.GetEventsFor(streamName, id)) +} diff --git a/eventstore/in_memory_store_test.go b/eventstore/in_memory_store_test.go new file mode 100644 index 00000000..688b759c --- /dev/null +++ b/eventstore/in_memory_store_test.go @@ -0,0 +1,53 @@ +package eventstore_test + +import ( + . "github.com/hellofresh/goengine/eventstore" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("In Memory Event Store", func() { + var events []DomainEvent + var inMemory *InMemoryEventStore = NewInMemoryEventStore() + var aggregateId string + var streamName StreamName + + BeforeEach(func() { + events = nil // clear the slice before each execution + aggregateId = "594fb936-d646-44b5-a152-84eb4f709f20" + streamName = "test" + }) + + JustBeforeEach(func() { + events = append(events, NewSomethingHappened()) + events = append(events, NewSomethingHappened()) + events = append(events, NewSomethingHappened()) + events = append(events, NewSomethingHappened()) + }) + + Describe("when something happens", func() { + It("should save an event", func() { + for version, event := range events { + message := RecordNow(aggregateId, version, event) + inMemory.Save(streamName, message) + } + }) + + It("should retrive the things that happened", func() { + expectedEvents := inMemory.GetEventsFor(streamName, aggregateId) + + Expect(expectedEvents).To(HaveLen(4)) + }) + + It("should count the events that happened", func() { + Expect(inMemory.CountEventsFor(streamName, aggregateId)).Should(Equal(4)) + }) + + It("should retrieve events for version bigger then 1", func() { + expectedEvents := inMemory.FromVersion(streamName, aggregateId, 1) + + Expect(expectedEvents).To(HaveLen(3)) + }) + }) +}) diff --git a/eventstore/mock_test.go b/eventstore/mock_test.go new file mode 100644 index 00000000..e1aefbdc --- /dev/null +++ b/eventstore/mock_test.go @@ -0,0 +1,17 @@ +package eventstore_test + +import ( + "time" +) + +type SomethingHappened struct { + ocurredOn time.Time +} + +func NewSomethingHappened() *SomethingHappened { + return &SomethingHappened{time.Now()} +} + +func (e *SomethingHappened) OcurredOn() time.Time { + return e.ocurredOn +} From ae69d952be0c4654bc18ffacfd80f9e2121b925c Mon Sep 17 00:00:00 2001 From: Italo Lelis de Vietro Date: Thu, 27 Oct 2016 00:29:57 +0200 Subject: [PATCH 03/74] Added basic readme --- CONTRIBUTING.md | 71 +++++++++++++++++++++++++++++++++++++++++++++++++ LICENSE | 21 +++++++++++++++ README.md | 45 +++++++++++++++++++++++++++++++ 3 files changed, 137 insertions(+) create mode 100644 CONTRIBUTING.md create mode 100644 LICENSE create mode 100644 README.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..532f1457 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,71 @@ +# Request for contributions + +Please contribute to this repository if any of the following is true: +- You have expertise in community development, communication, or education +- You want open source communities to be more collaborative and inclusive +- You want to help lower the burden to first time contributors + +# How to contribute + +Prerequisites: + +- familiarity with [GitHub PRs](https://help.github.com/articles/using-pull-requests) (pull requests) and issues +- knowledge of Markdown for editing `.md` documents + +In particular, this community seeks the following types of contributions: + +- ideas: participate in an Issues thread or start your own to have your voice +heard +- resources: submit a PR to add to [docs README.md](README.md) with links to related content +- outline sections: help us ensure that this repository is comprehensive. if +there is a topic that is overlooked, please add it, even if it is just a stub +in the form of a header and single sentence. Initially, most things fall into +this category +- write: contribute your expertise in an area by helping us expand the included +content +- copy editing: fix typos, clarify language, and generally improve the quality +of the content +- formatting: help keep content easy to read with consistent formatting +- code: Fix issues or contribute new features to this or any related projects + +# Conduct + +We are committed to providing a friendly, safe and welcoming environment for +all, regardless of gender, sexual orientation, disability, ethnicity, religion, +or similar personal characteristic. + +Please be kind and courteous. There's no need to be mean or rude. +Respect that people have differences of opinion and that every design or +implementation choice carries a trade-off and numerous costs. There is seldom +a right answer, merely an optimal answer given a set of values and +circumstances. + +Please keep unstructured critique to a minimum. If you have solid ideas you +want to experiment with, make a fork and see how it works. + +We will exclude you from interaction if you insult, demean or harass anyone. +That is not welcome behavior. We interpret the term "harassment" as +including the definition in the +[Citizen Code of Conduct](http://citizencodeofconduct.org/); +if you have any lack of clarity about what might be included in that concept, +please read their definition. In particular, we don't tolerate behavior that +excludes people in socially marginalized groups. + +Private harassment is also unacceptable. No matter who you are, if you feel +you have been or are being harassed or made uncomfortable by a community +member, please contact one of the +[hellofresh](https://github.com/orgs/hellofresh/people) core team +immediately. Whether you're a regular contributor or a newcomer, we care about +making this community a safe place for you and we've got your back. + +Likewise any spamming, trolling, flaming, baiting or other attention-stealing +behavior is not welcome. + +# Communication + +GitHub issues are the primary way for communicating about specific proposed +changes to this project. + +In both contexts, please follow the conduct guidelines above. Language issues +are often contentious and we'd like to keep discussion brief, civil and focused +on what we're actually doing, not wandering off into too much imaginary stuff. \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..1f507892 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 HelloFresh + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 00000000..5b9d18da --- /dev/null +++ b/README.md @@ -0,0 +1,45 @@ +

+ + + +

+ +# hellofresh/engine + +[![Build Status](https://travis-ci.org/hellofresh/goengine.svg?branch=master)](https://travis-ci.org/hellofresh/goengine) + +Welcome to HelloFresh GoEngine!! + +GoEngine provides you all the capabilities to build an Event sourced application in go +This was based on the initial project [Engine](https://github.com/hellofresh/engine) for PHP + +## Components + +Engine is divided in a few small independent components. + +* [CommandBus](src/commandbus/README.md) +* [EventBus](src/eventbus/README.md) +* [EventDispatcher](src/eventdispatcher/README.md) +* [EventSourcing](src/eventsourcing/README.md) +* [EventStore](src/eventstore/README.md) + +## Install + +```sh +go get github.com/hellofresh/goengine +``` + +## Usage + +Here you can check a small tutorial of how to use this component in an orders scenario. + +[Tutorial] (docs/how_to.md) + +## Contributing + +Please see [CONTRIBUTING](CONTRIBUTING.md) for details. + +## License + +The MIT License (MIT). Please see [License File](LICENSE) for more information. + From 5306046adf2f51121632193a1cc2ebb410444fa8 Mon Sep 17 00:00:00 2001 From: Italo Lelis de Vietro Date: Thu, 27 Oct 2016 00:31:10 +0200 Subject: [PATCH 04/74] Updated link --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5b9d18da..bd8a01ff 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Welcome to HelloFresh GoEngine!! -GoEngine provides you all the capabilities to build an Event sourced application in go +GoEngine provides you all the capabilities to build an Event sourced application in go. This was based on the initial project [Engine](https://github.com/hellofresh/engine) for PHP ## Components @@ -20,7 +20,7 @@ Engine is divided in a few small independent components. * [CommandBus](src/commandbus/README.md) * [EventBus](src/eventbus/README.md) * [EventDispatcher](src/eventdispatcher/README.md) -* [EventSourcing](src/eventsourcing/README.md) +* [EventSourcing](src/eventsourcing) * [EventStore](src/eventstore/README.md) ## Install From 7de6b6bb71f31f98100a685028a03968a61806a4 Mon Sep 17 00:00:00 2001 From: Italo Lelis de Vietro Date: Thu, 27 Oct 2016 00:32:40 +0200 Subject: [PATCH 05/74] Updated links --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index bd8a01ff..d6fee65f 100644 --- a/README.md +++ b/README.md @@ -17,11 +17,11 @@ This was based on the initial project [Engine](https://github.com/hellofresh/eng Engine is divided in a few small independent components. -* [CommandBus](src/commandbus/README.md) -* [EventBus](src/eventbus/README.md) -* [EventDispatcher](src/eventdispatcher/README.md) -* [EventSourcing](src/eventsourcing) -* [EventStore](src/eventstore/README.md) +* [CommandBus](commandbus) +* [EventBus](eventbus) +* [EventDispatcher](eventdispatcher) +* [EventSourcing](eventsourcing) +* [EventStore](eventstore) ## Install From d0d0de1602b69874d26ee66b6e08ee888f3fb81d Mon Sep 17 00:00:00 2001 From: Italo Lelis de Vietro Date: Thu, 27 Oct 2016 00:36:18 +0200 Subject: [PATCH 06/74] Update test --- .travis.yml | 4 ++-- Makefile | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index db23233a..5d4e19bf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,6 @@ go: - master install: - - docker-compose up -d - + # - docker-compose up -d + script: make test diff --git a/Makefile b/Makefile index 5c410012..5e81999e 100644 --- a/Makefile +++ b/Makefile @@ -29,3 +29,9 @@ install: clean: @echo "$(OK_COLOR)==> Cleaning project$(NO_COLOR)" if [ -f ${BINARY} ] ; then rm ${BINARY} ; fi + +test: + @echo "$(OK_COLOR)==> Installign test dependencies" + go get github.com/onsi/ginkgo/ginkgo + go get github.com/onsi/gomega + ginkgo -r From f96828e2b05379d356c49b865b4fecf315d08289 Mon Sep 17 00:00:00 2001 From: Italo Lelis de Vietro Date: Sat, 29 Oct 2016 14:03:11 +0200 Subject: [PATCH 07/74] Removing dockerfile --- Dockerfile | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 5ee29bac..00000000 --- a/Dockerfile +++ /dev/null @@ -1,12 +0,0 @@ -FROM golang:1.7 - -ENV APP_DIR $GOPATH/src/github.com/hellofresh/goengine - -RUN mkdir -p $APP_DIR - -COPY . $APP_DIR -WORKDIR $APP_DIR - -RUN make - -CMD ["go-wrapper", "run"] \ No newline at end of file From 3423601c0d2f3176ac7e1cefc356257977401947 Mon Sep 17 00:00:00 2001 From: Italo Lelis de Vietro Date: Sat, 29 Oct 2016 14:03:20 +0200 Subject: [PATCH 08/74] Removing app form the docker compose --- docker-compose.yml | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 7f6b7ebf..077ecdc4 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,13 +1,6 @@ -version: 2 -services: +version: '2' +services: - app: - build: ./ - volumes: - - ./src/github.com/hellofresh/auth-service:/go/src/github.com/hellofresh/auth-service - environment: - STORAGE_DSN: 'mongodb://mongo/goengine' - redis: image: redis From 7e890dfb5f662f56606981669533dabe331f0cf9 Mon Sep 17 00:00:00 2001 From: Italo Lelis de Vietro Date: Sat, 29 Oct 2016 14:03:38 +0200 Subject: [PATCH 09/74] Updated lock --- glide.lock | 41 +++++++++++++++++++++++++++++++++++++++++ glide.yaml | 10 ++++++++++ 2 files changed, 51 insertions(+) create mode 100644 glide.lock create mode 100644 glide.yaml diff --git a/glide.lock b/glide.lock new file mode 100644 index 00000000..18a243e1 --- /dev/null +++ b/glide.lock @@ -0,0 +1,41 @@ +hash: 820280dd6a9cc7f07393743ed26e4b6a5932f544d6dd9562626d52283e2386ea +updated: 2016-10-27T11:25:26.661198153+02:00 +imports: +- name: gopkg.in/mgo.v2 + version: 3f83fa5005286a7fe593b055f0d7771a7dce4655 + subpackages: + - bson + - internal/json + - internal/sasl + - internal/scram +testImports: +- name: github.com/onsi/ginkgo + version: 462326b1628e124b23f42e87a8f2750e3c4e2d24 + subpackages: + - config + - internal/codelocation + - internal/containernode + - internal/failer + - internal/leafnodes + - internal/remote + - internal/spec + - internal/specrunner + - internal/suite + - internal/testingtproxy + - internal/writer + - reporters + - reporters/stenographer + - types +- name: github.com/onsi/gomega + version: a78ae492d53aad5a7a232d0d0462c14c400e3ee7 + subpackages: + - format + - internal/assertion + - internal/asyncassertion + - internal/testingtsupport + - matchers + - matchers/support/goraph/bipartitegraph + - matchers/support/goraph/edge + - matchers/support/goraph/node + - matchers/support/goraph/util + - types diff --git a/glide.yaml b/glide.yaml new file mode 100644 index 00000000..97849511 --- /dev/null +++ b/glide.yaml @@ -0,0 +1,10 @@ +package: github.com/hellofresh/goengine +import: +- package: gopkg.in/mgo.v2 + subpackages: + - bson +testImport: +- package: github.com/onsi/ginkgo + version: ^1.2.0 +- package: github.com/onsi/gomega + version: ^1.0.0 From c6bc757d72871516bf94e956e5d70b09eadc63a7 Mon Sep 17 00:00:00 2001 From: Italo Lelis de Vietro Date: Sat, 29 Oct 2016 14:04:32 +0200 Subject: [PATCH 10/74] Added test cmd --- Makefile | 2 +- cmd/goengine/event.go | 15 +++++++++++ cmd/goengine/main.go | 63 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 cmd/goengine/event.go create mode 100644 cmd/goengine/main.go diff --git a/Makefile b/Makefile index 5e81999e..8e585ce8 100644 --- a/Makefile +++ b/Makefile @@ -23,7 +23,7 @@ build: # Installs our project: copies binaries install: @echo "$(OK_COLOR)==> Installing project$(NO_COLOR)" - go install -v + go install -v ./cmd/goengine # Cleans our project: deletes binaries clean: diff --git a/cmd/goengine/event.go b/cmd/goengine/event.go new file mode 100644 index 00000000..9a5c45d6 --- /dev/null +++ b/cmd/goengine/event.go @@ -0,0 +1,15 @@ +package main + +import "time" + +type SomethingHappened struct { + Ocurred time.Time `json:"ocurred_on"` +} + +func NewSomethingHappened() *SomethingHappened { + return &SomethingHappened{time.Now()} +} + +func (e *SomethingHappened) OcurredOn() time.Time { + return e.Ocurred +} diff --git a/cmd/goengine/main.go b/cmd/goengine/main.go new file mode 100644 index 00000000..b3f1418d --- /dev/null +++ b/cmd/goengine/main.go @@ -0,0 +1,63 @@ +package main + +import ( + "os" + + log "github.com/Sirupsen/logrus" + "github.com/hellofresh/goengine/eventstore" + "github.com/hellofresh/goengine/serializer" + "github.com/satori/go.uuid" + + "gopkg.in/mgo.v2" +) + +func main() { + var streamName eventstore.StreamName = "test" + aggregateID := uuid.NewV4() + + mongoDSN := os.Getenv("STORAGE_DSN") + log.Infof("Connecting to the database %s", mongoDSN) + session, err := mgo.Dial(mongoDSN) + if err != nil { + log.Panic(err) + } + defer session.Close() + + // Optional. Switch the session to a monotonic behavior. + session.SetMode(mgo.Monotonic, true) + + log.Info("Setting up the event store") + registry := serializer.NewInMemmoryTypeRegistry() + registry.Register(&SomethingHappened{}) + + es := SetupEventStore(session, registry) + + log.Info("Creating the event stream") + stream := CreateEventStream(streamName, aggregateID.String()) + + err = es.Append(stream) + if nil != err { + log.Error(err) + } + + events, err := es.GetEventsFor(streamName, aggregateID.String()) + if nil != err { + log.Error(err) + } + log.Info(events) +} + +func SetupEventStore(session *mgo.Session, registry serializer.TypeRegistry) eventstore.EventStore { + adapter := eventstore.NewMongoDbEventStore(session, registry) + return eventstore.NewEventStore(adapter) +} + +func CreateEventStream(streamName eventstore.StreamName, aggregateId string) *eventstore.EventStream { + var events []*eventstore.DomainMessage + + events = append(events, eventstore.RecordNow(aggregateId, 0, NewSomethingHappened())) + events = append(events, eventstore.RecordNow(aggregateId, 1, NewSomethingHappened())) + events = append(events, eventstore.RecordNow(aggregateId, 2, NewSomethingHappened())) + + return eventstore.NewEventStream(streamName, events) +} From 2675595dd1d6ba0e6af9955b6cf2f8e783aabcf2 Mon Sep 17 00:00:00 2001 From: Italo Lelis de Vietro Date: Sat, 29 Oct 2016 14:04:55 +0200 Subject: [PATCH 11/74] Added json notation to the domain message --- eventstore/domain_message.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/eventstore/domain_message.go b/eventstore/domain_message.go index 53c34776..e8713243 100644 --- a/eventstore/domain_message.go +++ b/eventstore/domain_message.go @@ -3,10 +3,10 @@ package eventstore import "time" type DomainMessage struct { - ID string - version int - payload DomainEvent - recordedOn time.Time + ID string `json:"aggregate_id,omitempty"` + Version int `json:"version"` + Payload DomainEvent `json:"payload"` + RecordedOn time.Time `json:"recorded_on"` } func NewDomainMessage(id string, version int, payload DomainEvent, recordedOn time.Time) *DomainMessage { From db80d15b4492655c6ec8879032b304ebbf2bc54a Mon Sep 17 00:00:00 2001 From: Italo Lelis de Vietro Date: Sat, 29 Oct 2016 14:06:20 +0200 Subject: [PATCH 12/74] Event store now returns errors --- eventstore/event_store.go | 39 +++++++++++++++++++--------------- eventstore/event_store_test.go | 9 +++++--- 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/eventstore/event_store.go b/eventstore/event_store.go index 4df9e17a..23a85859 100644 --- a/eventstore/event_store.go +++ b/eventstore/event_store.go @@ -1,17 +1,17 @@ package eventstore type EventStore interface { - Append(events *EventStream) - GetEventsFor(streamName StreamName, id string) *EventStream - FromVersion(streamName StreamName, id string, version int) *EventStream - CountEventsFor(streamName StreamName, id string) int + Append(events *EventStream) error + GetEventsFor(streamName StreamName, id string) (*EventStream, error) + FromVersion(streamName StreamName, id string, version int) (*EventStream, error) + CountEventsFor(streamName StreamName, id string) (int, error) } type EventStoreAdapter interface { - Save(streamName StreamName, events *DomainMessage) - GetEventsFor(streamName StreamName, id string) []*DomainMessage - FromVersion(streamName StreamName, id string, version int) []*DomainMessage - CountEventsFor(streamName StreamName, id string) int + Save(streamName StreamName, events *DomainMessage) error + GetEventsFor(streamName StreamName, id string) ([]*DomainMessage, error) + FromVersion(streamName StreamName, id string, version int) ([]*DomainMessage, error) + CountEventsFor(streamName StreamName, id string) (int, error) } type EventStoreImp struct { @@ -22,23 +22,28 @@ func NewEventStore(adapter EventStoreAdapter) *EventStoreImp { return &EventStoreImp{adapter} } -func (es *EventStoreImp) Append(events *EventStream) { +func (es *EventStoreImp) Append(events *EventStream) error { name := events.Name for _, event := range events.Events { - es.adapter.Save(name, event) + err := es.adapter.Save(name, event) + if nil != err { + return err + } } + + return nil } -func (es *EventStoreImp) FromVersion(streamName StreamName, id string, version int) *EventStream { - events := es.adapter.FromVersion(streamName, id, version) - return NewEventStream(streamName, events) +func (es *EventStoreImp) FromVersion(streamName StreamName, id string, version int) (*EventStream, error) { + events, err := es.adapter.FromVersion(streamName, id, version) + return NewEventStream(streamName, events), err } -func (es *EventStoreImp) GetEventsFor(streamName StreamName, id string) *EventStream { - events := es.adapter.GetEventsFor(streamName, id) - return NewEventStream(streamName, events) +func (es *EventStoreImp) GetEventsFor(streamName StreamName, id string) (*EventStream, error) { + events, err := es.adapter.GetEventsFor(streamName, id) + return NewEventStream(streamName, events), err } -func (es *EventStoreImp) CountEventsFor(streamName StreamName, id string) int { +func (es *EventStoreImp) CountEventsFor(streamName StreamName, id string) (int, error) { return es.adapter.CountEventsFor(streamName, id) } diff --git a/eventstore/event_store_test.go b/eventstore/event_store_test.go index f8ebc0ba..a4eb51f8 100644 --- a/eventstore/event_store_test.go +++ b/eventstore/event_store_test.go @@ -34,12 +34,14 @@ var _ = Describe("A Event Store", func() { Describe("when something happens", func() { It("should save an event", func() { - store.Append(eventStream) + err := store.Append(eventStream) + Expect(err).To(BeNil()) }) It("should retrive the things that happened", func() { - expectedEvents := store.GetEventsFor(streamName, aggregateId) + expectedEvents, err := store.GetEventsFor(streamName, aggregateId) + Expect(err).To(BeNil()) Expect(expectedEvents.Events).To(HaveLen(3)) }) @@ -48,8 +50,9 @@ var _ = Describe("A Event Store", func() { }) It("should retrieve events for version bigger then 1", func() { - expectedEvents := store.FromVersion(streamName, aggregateId, 1) + expectedEvents, err := store.FromVersion(streamName, aggregateId, 1) + Expect(err).To(BeNil()) Expect(expectedEvents.Events).To(HaveLen(2)) }) }) From b2b61376d4a2e1f512ea75e4030c0f4010e16c7e Mon Sep 17 00:00:00 2001 From: Italo Lelis de Vietro Date: Sat, 29 Oct 2016 14:06:43 +0200 Subject: [PATCH 13/74] In memory event store now returns errors --- eventstore/in_memory_store.go | 21 ++++++++++++--------- eventstore/in_memory_store_test.go | 9 ++++++--- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/eventstore/in_memory_store.go b/eventstore/in_memory_store.go index a4a630d7..f7938c46 100644 --- a/eventstore/in_memory_store.go +++ b/eventstore/in_memory_store.go @@ -8,7 +8,7 @@ func NewInMemoryEventStore() *InMemoryEventStore { return &InMemoryEventStore{make(map[StreamName]map[string][]*DomainMessage)} } -func (s *InMemoryEventStore) Save(streamName StreamName, event *DomainMessage) { +func (s *InMemoryEventStore) Save(streamName StreamName, event *DomainMessage) error { id := event.ID events, exists := s.events[streamName][id] @@ -17,25 +17,28 @@ func (s *InMemoryEventStore) Save(streamName StreamName, event *DomainMessage) { } s.events[streamName][id] = append(events, event) + + return nil } -func (s *InMemoryEventStore) GetEventsFor(streamName StreamName, id string) []*DomainMessage { - return s.events[streamName][id] +func (s *InMemoryEventStore) GetEventsFor(streamName StreamName, id string) ([]*DomainMessage, error) { + return s.events[streamName][id], nil } -func (s *InMemoryEventStore) FromVersion(streamName StreamName, id string, version int) []*DomainMessage { - events := s.GetEventsFor(streamName, id) +func (s *InMemoryEventStore) FromVersion(streamName StreamName, id string, version int) ([]*DomainMessage, error) { + events, _ := s.GetEventsFor(streamName, id) var filtered []*DomainMessage for _, event := range events { - if event.version >= version { + if event.Version >= version { filtered = append(filtered, event) } } - return filtered + return filtered, nil } -func (s *InMemoryEventStore) CountEventsFor(streamName StreamName, id string) int { - return len(s.GetEventsFor(streamName, id)) +func (s *InMemoryEventStore) CountEventsFor(streamName StreamName, id string) (int, error) { + result, _ := s.GetEventsFor(streamName, id) + return len(result), nil } diff --git a/eventstore/in_memory_store_test.go b/eventstore/in_memory_store_test.go index 688b759c..c7cced5d 100644 --- a/eventstore/in_memory_store_test.go +++ b/eventstore/in_memory_store_test.go @@ -30,13 +30,15 @@ var _ = Describe("In Memory Event Store", func() { It("should save an event", func() { for version, event := range events { message := RecordNow(aggregateId, version, event) - inMemory.Save(streamName, message) + err := inMemory.Save(streamName, message) + Expect(err).To(BeNil()) } }) It("should retrive the things that happened", func() { - expectedEvents := inMemory.GetEventsFor(streamName, aggregateId) + expectedEvents, err := inMemory.GetEventsFor(streamName, aggregateId) + Expect(err).To(BeNil()) Expect(expectedEvents).To(HaveLen(4)) }) @@ -45,8 +47,9 @@ var _ = Describe("In Memory Event Store", func() { }) It("should retrieve events for version bigger then 1", func() { - expectedEvents := inMemory.FromVersion(streamName, aggregateId, 1) + expectedEvents, err := inMemory.FromVersion(streamName, aggregateId, 1) + Expect(err).To(BeNil()) Expect(expectedEvents).To(HaveLen(3)) }) }) From f8ee97f003bc0c0a10391fe4efb7b281c577696d Mon Sep 17 00:00:00 2001 From: Italo Lelis de Vietro Date: Sat, 29 Oct 2016 14:07:32 +0200 Subject: [PATCH 14/74] Added mongodb event store --- eventstore/mongodb_store.go | 119 ++++++++++++++++++++++++++++++++++++ serializer/type_registry.go | 81 ++++++++++++++++++++++++ 2 files changed, 200 insertions(+) create mode 100644 eventstore/mongodb_store.go create mode 100644 serializer/type_registry.go diff --git a/eventstore/mongodb_store.go b/eventstore/mongodb_store.go new file mode 100644 index 00000000..9c75bf58 --- /dev/null +++ b/eventstore/mongodb_store.go @@ -0,0 +1,119 @@ +package eventstore + +import ( + "encoding/json" + "time" + + log "github.com/Sirupsen/logrus" + "github.com/hellofresh/goengine/serializer" + + "gopkg.in/mgo.v2" + "gopkg.in/mgo.v2/bson" +) + +type EventData struct { + ID string `bson:"aggregate_id,omitempty"` + Version int `bson:"version"` + Type string `bson:"type"` + Payload string `bson:"payload"` + RecordedOn time.Time `bson:"recorded_on"` +} + +type MongoDbEventStore struct { + conn *mgo.Session + db *mgo.Database + registry serializer.TypeRegistry +} + +func NewMongoDbEventStore(conn *mgo.Session, r serializer.TypeRegistry) *MongoDbEventStore { + db := conn.DB("") + return &MongoDbEventStore{conn, db, r} +} + +func (s *MongoDbEventStore) Save(streamName StreamName, event *DomainMessage) error { + coll := s.db.C(string(streamName)) + err := s.createIndexes(coll) + if nil != err { + return err + } + + serializedPayload, err := json.Marshal(event.Payload) + if nil != err { + return err + } + + typeName, err := s.registry.TypeOf(event.Payload) + if nil != err { + return err + } + + if !s.registry.Exists(typeName.String()) { + return ErrorTypeNotRegistred + } + + eventData := &EventData{ + ID: event.ID, + Version: event.Version, + Type: typeName.String(), + Payload: string(serializedPayload), + RecordedOn: event.RecordedOn, + } + + return coll.Insert(eventData) +} + +func (s *MongoDbEventStore) GetEventsFor(streamName StreamName, id string) ([]*DomainMessage, error) { + var eventsData []*EventData + var results []*DomainMessage + + coll := s.db.C(string(streamName)) + + err := coll.Find(bson.M{"aggregate_id": id}).All(&eventsData) + + for _, eventData := range eventsData { + event, err := s.registry.Get(eventData.Type) + if nil != err { + return nil, err + } + + err = json.Unmarshal([]byte(eventData.Payload), event) + if nil != err { + return nil, err + } + + domainMessage := NewDomainMessage(eventData.ID, eventData.Version, event.(DomainEvent), eventData.RecordedOn) + log.Info(domainMessage.Payload) + results = append(results, domainMessage) + } + + return results, err +} + +func (s *MongoDbEventStore) FromVersion(streamName StreamName, id string, version int) ([]*DomainMessage, error) { + var results []*DomainMessage + coll := s.db.C(string(streamName)) + + err := coll.Find(bson.M{ + "aggregate_id": id, + "version": bson.M{"$gte": version}, + }). + Sort("-version"). + All(&results) + + return results, err +} + +func (s *MongoDbEventStore) CountEventsFor(streamName StreamName, id string) (int, error) { + return s.db.C(string(streamName)).Find(bson.M{"aggregate_id": string(streamName)}).Count() +} + +func (s *MongoDbEventStore) createIndexes(c *mgo.Collection) error { + index := mgo.Index{ + Key: []string{"aggregate_id", "version"}, + Unique: true, + DropDups: true, + Background: true, + } + + return c.EnsureIndex(index) +} diff --git a/serializer/type_registry.go b/serializer/type_registry.go new file mode 100644 index 00000000..5118b289 --- /dev/null +++ b/serializer/type_registry.go @@ -0,0 +1,81 @@ +package serializer + +import ( + "errors" + "reflect" +) + +// TypeRegistry is a registry for go types +// this is necessary since we can't create a type from +// a string and it's json. With this registry we can +// know how to create a type for that string +type TypeRegistry interface { + Register(i interface{}) error + Unregister(i interface{}) error + Exists(name string) bool + Get(name string) (interface{}, error) + TypeOf(i interface{}) (reflect.Type, error) +} + +// InMemoryTypeRegistry implements the in memory strategy +// for the registry +type InMemoryTypeRegistry struct { + types map[string]reflect.Type +} + +// NewInMemmoryTypeRegistry creates a new in memory registry +func NewInMemmoryTypeRegistry() *InMemoryTypeRegistry { + return &InMemoryTypeRegistry{make(map[string]reflect.Type)} +} + +// Register adds a type in the registry +func (tr *InMemoryTypeRegistry) Register(i interface{}) error { + t, err := tr.TypeOf(i) + if nil != err { + return err + } + + tr.types[t.String()] = t + return nil +} + +// Unregister removes a type from the registry +func (tr *InMemoryTypeRegistry) Unregister(i interface{}) error { + t, err := tr.TypeOf(i) + if nil != err { + return err + } + + delete(tr.types, t.String()) + return nil +} + +// Exists checks if a type exists in the registry +func (tr *InMemoryTypeRegistry) Exists(name string) bool { + _, exists := tr.types[name] + return exists +} + +// Get retrieves a reflect.Type based on a name +func (tr *InMemoryTypeRegistry) Get(name string) (interface{}, error) { + if typ, ok := tr.types[name]; ok { + return reflect.New(typ).Interface(), nil + } + return nil, errors.New("no one") +} + +// TypeOf returns the type of a struct checking if it's a pointer or not +func (tr *InMemoryTypeRegistry) TypeOf(i interface{}) (reflect.Type, error) { + // Convert the interface i to a reflect.Type t + t := reflect.TypeOf(i) + // Check if the input is a pointer and dereference it if yes + if t.Kind() == reflect.Ptr { + t = t.Elem() + } + // Check if the input is a struct + if t.Kind() != reflect.Struct { + return nil, errors.New("Input param is not a struct") + } + + return t, nil +} From 564f7aa554b39fda014721b3359263f30bbb63f7 Mon Sep 17 00:00:00 2001 From: Italo Lelis de Vietro Date: Sat, 29 Oct 2016 14:13:30 +0200 Subject: [PATCH 15/74] Moved errors to its own package --- errors/type.go | 9 +++++++++ eventstore/mongodb_store.go | 3 ++- serializer/type_registry.go | 7 ++++--- 3 files changed, 15 insertions(+), 4 deletions(-) create mode 100644 errors/type.go diff --git a/errors/type.go b/errors/type.go new file mode 100644 index 00000000..8cf17d52 --- /dev/null +++ b/errors/type.go @@ -0,0 +1,9 @@ +package errors + +import "errors" + +var ( + ErrorTypeNotRegistred = errors.New("The type is not registereds") + ErrorTypeNotStruct = errors.New("Input param is not a struct") + ErrorTypeNotFound = errors.New("The type was not found") +) diff --git a/eventstore/mongodb_store.go b/eventstore/mongodb_store.go index 9c75bf58..c4bc14b0 100644 --- a/eventstore/mongodb_store.go +++ b/eventstore/mongodb_store.go @@ -5,6 +5,7 @@ import ( "time" log "github.com/Sirupsen/logrus" + "github.com/hellofresh/goengine/errors" "github.com/hellofresh/goengine/serializer" "gopkg.in/mgo.v2" @@ -48,7 +49,7 @@ func (s *MongoDbEventStore) Save(streamName StreamName, event *DomainMessage) er } if !s.registry.Exists(typeName.String()) { - return ErrorTypeNotRegistred + return errors.ErrorTypeNotRegistred } eventData := &EventData{ diff --git a/serializer/type_registry.go b/serializer/type_registry.go index 5118b289..fd015cc3 100644 --- a/serializer/type_registry.go +++ b/serializer/type_registry.go @@ -1,8 +1,9 @@ package serializer import ( - "errors" "reflect" + + "github.com/hellofresh/goengine/errors" ) // TypeRegistry is a registry for go types @@ -61,7 +62,7 @@ func (tr *InMemoryTypeRegistry) Get(name string) (interface{}, error) { if typ, ok := tr.types[name]; ok { return reflect.New(typ).Interface(), nil } - return nil, errors.New("no one") + return nil, errors.ErrorTypeNotFound } // TypeOf returns the type of a struct checking if it's a pointer or not @@ -74,7 +75,7 @@ func (tr *InMemoryTypeRegistry) TypeOf(i interface{}) (reflect.Type, error) { } // Check if the input is a struct if t.Kind() != reflect.Struct { - return nil, errors.New("Input param is not a struct") + return nil, errors.ErrorTypeNotStruct } return t, nil From befe9bd0b3f028b81db00de5f914466801a4e65b Mon Sep 17 00:00:00 2001 From: Italo Lelis de Vietro Date: Sat, 29 Oct 2016 17:39:29 +0200 Subject: [PATCH 16/74] Added aggregate root --- eventsourcing/aggregate_root.go | 65 +++++++++++++++++++++++ eventsourcing/aggregate_root_test.go | 18 +++++++ eventsourcing/eventsourcing_suite_test.go | 13 +++++ eventsourcing/mock_test.go | 50 +++++++++++++++++ reflection/caller.go | 20 +++++++ 5 files changed, 166 insertions(+) create mode 100644 eventsourcing/aggregate_root.go create mode 100644 eventsourcing/aggregate_root_test.go create mode 100644 eventsourcing/eventsourcing_suite_test.go create mode 100644 eventsourcing/mock_test.go create mode 100644 reflection/caller.go diff --git a/eventsourcing/aggregate_root.go b/eventsourcing/aggregate_root.go new file mode 100644 index 00000000..0ef7bc92 --- /dev/null +++ b/eventsourcing/aggregate_root.go @@ -0,0 +1,65 @@ +package eventsourcing + +import ( + "fmt" + "reflect" + + "github.com/hellofresh/goengine/eventstore" + "github.com/hellofresh/goengine/reflection" + "github.com/pborman/uuid" +) + +type AggregateRoot struct { + ID string + version int + source interface{} + uncommitedEvents []*eventstore.DomainMessage +} + +// NewAggregateRoot constructor +func NewAggregateRoot(source interface{}) AggregateRoot { + return NewEventSourceBasedWithID(source, uuid.New()) +} + +// NewEventSourceBasedWithID constructor +func NewEventSourceBasedWithID(source interface{}, id string) AggregateRoot { + return AggregateRoot{id, 0, source, []*eventstore.DomainMessage{}} +} + +func (ar *AggregateRoot) ReconstituteFromHistory(historyEvents *eventstore.EventStream) { + +} + +func (ar *AggregateRoot) GetUncommittedEvents() []*eventstore.DomainMessage { + stream := ar.uncommitedEvents + ar.uncommitedEvents = nil + + return stream +} + +func (r *AggregateRoot) Apply(event eventstore.DomainEvent) { + t := reflect.TypeOf(event) + if t.Kind() == reflect.Ptr { + t = t.Elem() + } + + reflection.CallMethod(r.source, fmt.Sprintf("When%s", t.Name()), event) +} + +func (r *AggregateRoot) RecordThat(event eventstore.DomainEvent) { + r.version++ + r.Apply(event) + r.Record(event) +} + +func (r *AggregateRoot) Replay(historyEvents *eventstore.EventStream, version int) { + for _, event := range historyEvents.Events { + r.version = event.Version + r.Apply(event.Payload) + } +} + +func (ar *AggregateRoot) Record(event eventstore.DomainEvent) { + message := eventstore.RecordNow(ar.ID, ar.version, event) + ar.uncommitedEvents = append(ar.uncommitedEvents, message) +} diff --git a/eventsourcing/aggregate_root_test.go b/eventsourcing/aggregate_root_test.go new file mode 100644 index 00000000..8987cb32 --- /dev/null +++ b/eventsourcing/aggregate_root_test.go @@ -0,0 +1,18 @@ +package eventsourcing_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("A Recipe", func() { + Describe("when someone rate it", func() { + It("should have a recipe rated event", func() { + recipe := NewRecipe("Test") + recipe.Rate(5) + + Expect(recipe.Rating).To(Equal(5)) + Expect(len(recipe.GetUncommittedEvents())).To(Equal(2)) + }) + }) +}) diff --git a/eventsourcing/eventsourcing_suite_test.go b/eventsourcing/eventsourcing_suite_test.go new file mode 100644 index 00000000..c4b6882e --- /dev/null +++ b/eventsourcing/eventsourcing_suite_test.go @@ -0,0 +1,13 @@ +package eventsourcing_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "testing" +) + +func TestGoengine(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Event Sourcing Suite") +} diff --git a/eventsourcing/mock_test.go b/eventsourcing/mock_test.go new file mode 100644 index 00000000..1aa9a976 --- /dev/null +++ b/eventsourcing/mock_test.go @@ -0,0 +1,50 @@ +package eventsourcing_test + +import ( + "time" + + "github.com/hellofresh/goengine/eventsourcing" +) + +type RecipeCreated struct { + ocurredOn time.Time +} + +func (e RecipeCreated) OcurredOn() time.Time { + return e.ocurredOn +} + +type RecipeRated struct { + ocurredOn time.Time + Rating int +} + +func (e RecipeRated) OcurredOn() time.Time { + return e.ocurredOn +} + +type Recipe struct { + eventsourcing.AggregateRoot + Name string + Rating int +} + +func NewRecipe(name string) *Recipe { + recipe := new(Recipe) + recipe.AggregateRoot = eventsourcing.NewAggregateRoot(recipe) + recipe.RecordThat(RecipeCreated{time.Now()}) + + return recipe +} + +func (r *Recipe) Rate(rate int) { + r.RecordThat(RecipeRated{time.Now(), rate}) +} + +func (r *Recipe) WhenRecipeCreated(event RecipeCreated) { + +} + +func (r *Recipe) WhenRecipeRated(event RecipeRated) { + r.Rating = event.Rating +} diff --git a/reflection/caller.go b/reflection/caller.go new file mode 100644 index 00000000..f01032f1 --- /dev/null +++ b/reflection/caller.go @@ -0,0 +1,20 @@ +package reflection + +import "reflect" + +func CallMethod(i interface{}, methodName string, args ...interface{}) interface{} { + // check for method on pointer + method := reflect.ValueOf(i).MethodByName(methodName) + + if method.IsValid() { + var in []reflect.Value + for _, arg := range args { + in = append(in, reflect.ValueOf(arg)) + } + + return method.Call(in) + } + + // return or panic, method not found of either type + return "" +} From 77b1eb5484715ec418b1ef5985f65ac1a4f60b3e Mon Sep 17 00:00:00 2001 From: Italo Lelis de Vietro Date: Sat, 29 Oct 2016 17:41:02 +0200 Subject: [PATCH 17/74] Updated travis --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 5d4e19bf..0819a971 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,5 +10,6 @@ go: install: # - docker-compose up -d + - make deps script: make test From cc89add5e62a0b9f98cb2a33427b07b2d777b3d3 Mon Sep 17 00:00:00 2001 From: Italo Lelis de Vietro Date: Sat, 29 Oct 2016 17:53:25 +0200 Subject: [PATCH 18/74] Fixed dir structure --- .gitignore | 1 + cmd/goengine/main.go | 3 +- inmemory/eventstore.go | 46 +++++++++++++++++++ .../mongodb_store.go => mongodb/eventstore.go | 25 +++++----- {serializer => reflection}/type_registry.go | 2 +- 5 files changed, 62 insertions(+), 15 deletions(-) create mode 100644 inmemory/eventstore.go rename eventstore/mongodb_store.go => mongodb/eventstore.go (69%) rename {serializer => reflection}/type_registry.go (99%) diff --git a/.gitignore b/.gitignore index e0956511..ff91de9e 100644 --- a/.gitignore +++ b/.gitignore @@ -23,4 +23,5 @@ _testmain.go *.exe *.test *.prof +debug gin-bin \ No newline at end of file diff --git a/cmd/goengine/main.go b/cmd/goengine/main.go index b3f1418d..632f60f8 100644 --- a/cmd/goengine/main.go +++ b/cmd/goengine/main.go @@ -5,6 +5,7 @@ import ( log "github.com/Sirupsen/logrus" "github.com/hellofresh/goengine/eventstore" + "github.com/hellofresh/goengine/mongodb" "github.com/hellofresh/goengine/serializer" "github.com/satori/go.uuid" @@ -48,7 +49,7 @@ func main() { } func SetupEventStore(session *mgo.Session, registry serializer.TypeRegistry) eventstore.EventStore { - adapter := eventstore.NewMongoDbEventStore(session, registry) + adapter := mongodb.NewEventStore(session, registry) return eventstore.NewEventStore(adapter) } diff --git a/inmemory/eventstore.go b/inmemory/eventstore.go new file mode 100644 index 00000000..21447d89 --- /dev/null +++ b/inmemory/eventstore.go @@ -0,0 +1,46 @@ +package inmemory + +import "github.com/hellofresh/goengine/eventstore" + +type InMemoryEventStore struct { + events map[eventstore.StreamName]map[string][]*eventstore.DomainMessage +} + +func NewInMemoryEventStore() *InMemoryEventStore { + return &InMemoryEventStore{make(map[eventstore.StreamName]map[string][]*eventstore.DomainMessage)} +} + +func (s *InMemoryEventStore) Save(streamName eventstore.StreamName, event *eventstore.DomainMessage) error { + id := event.ID + events, exists := s.events[streamName][id] + + if !exists { + s.events[streamName] = make(map[string][]*eventstore.DomainMessage) + } + + s.events[streamName][id] = append(events, event) + + return nil +} + +func (s *InMemoryEventStore) GetEventsFor(streamName eventstore.StreamName, id string) ([]*eventstore.DomainMessage, error) { + return s.events[streamName][id], nil +} + +func (s *InMemoryEventStore) FromVersion(streamName eventstore.StreamName, id string, version int) ([]*eventstore.DomainMessage, error) { + events, _ := s.GetEventsFor(streamName, id) + var filtered []*eventstore.DomainMessage + + for _, event := range events { + if event.Version >= version { + filtered = append(filtered, event) + } + } + + return filtered, nil +} + +func (s *InMemoryEventStore) CountEventsFor(streamName eventstore.StreamName, id string) (int, error) { + result, _ := s.GetEventsFor(streamName, id) + return len(result), nil +} diff --git a/eventstore/mongodb_store.go b/mongodb/eventstore.go similarity index 69% rename from eventstore/mongodb_store.go rename to mongodb/eventstore.go index c4bc14b0..16c8f0cb 100644 --- a/eventstore/mongodb_store.go +++ b/mongodb/eventstore.go @@ -1,12 +1,12 @@ -package eventstore +package mongodb import ( "encoding/json" "time" - log "github.com/Sirupsen/logrus" "github.com/hellofresh/goengine/errors" - "github.com/hellofresh/goengine/serializer" + "github.com/hellofresh/goengine/eventstore" + "github.com/hellofresh/goengine/reflection" "gopkg.in/mgo.v2" "gopkg.in/mgo.v2/bson" @@ -23,15 +23,15 @@ type EventData struct { type MongoDbEventStore struct { conn *mgo.Session db *mgo.Database - registry serializer.TypeRegistry + registry reflection.TypeRegistry } -func NewMongoDbEventStore(conn *mgo.Session, r serializer.TypeRegistry) *MongoDbEventStore { +func NewEventStore(conn *mgo.Session, r reflection.TypeRegistry) *MongoDbEventStore { db := conn.DB("") return &MongoDbEventStore{conn, db, r} } -func (s *MongoDbEventStore) Save(streamName StreamName, event *DomainMessage) error { +func (s *MongoDbEventStore) Save(streamName eventstore.StreamName, event *eventstore.DomainMessage) error { coll := s.db.C(string(streamName)) err := s.createIndexes(coll) if nil != err { @@ -63,9 +63,9 @@ func (s *MongoDbEventStore) Save(streamName StreamName, event *DomainMessage) er return coll.Insert(eventData) } -func (s *MongoDbEventStore) GetEventsFor(streamName StreamName, id string) ([]*DomainMessage, error) { +func (s *MongoDbEventStore) GetEventsFor(streamName eventstore.StreamName, id string) ([]*eventstore.DomainMessage, error) { var eventsData []*EventData - var results []*DomainMessage + var results []*eventstore.DomainMessage coll := s.db.C(string(streamName)) @@ -82,16 +82,15 @@ func (s *MongoDbEventStore) GetEventsFor(streamName StreamName, id string) ([]*D return nil, err } - domainMessage := NewDomainMessage(eventData.ID, eventData.Version, event.(DomainEvent), eventData.RecordedOn) - log.Info(domainMessage.Payload) + domainMessage := eventstore.NewDomainMessage(eventData.ID, eventData.Version, event.(eventstore.DomainEvent), eventData.RecordedOn) results = append(results, domainMessage) } return results, err } -func (s *MongoDbEventStore) FromVersion(streamName StreamName, id string, version int) ([]*DomainMessage, error) { - var results []*DomainMessage +func (s *MongoDbEventStore) FromVersion(streamName eventstore.StreamName, id string, version int) ([]*eventstore.DomainMessage, error) { + var results []*eventstore.DomainMessage coll := s.db.C(string(streamName)) err := coll.Find(bson.M{ @@ -104,7 +103,7 @@ func (s *MongoDbEventStore) FromVersion(streamName StreamName, id string, versio return results, err } -func (s *MongoDbEventStore) CountEventsFor(streamName StreamName, id string) (int, error) { +func (s *MongoDbEventStore) CountEventsFor(streamName eventstore.StreamName, id string) (int, error) { return s.db.C(string(streamName)).Find(bson.M{"aggregate_id": string(streamName)}).Count() } diff --git a/serializer/type_registry.go b/reflection/type_registry.go similarity index 99% rename from serializer/type_registry.go rename to reflection/type_registry.go index fd015cc3..6a5bc18e 100644 --- a/serializer/type_registry.go +++ b/reflection/type_registry.go @@ -1,4 +1,4 @@ -package serializer +package reflection import ( "reflect" From a4f2144e7b235d731b246d824397eb06415ee328 Mon Sep 17 00:00:00 2001 From: Italo Lelis de Vietro Date: Sat, 29 Oct 2016 18:20:33 +0200 Subject: [PATCH 19/74] Fixed tests --- eventstore/event_store.go | 41 ---------------- eventstore/event_store_test.go | 4 +- eventstore/in_memory_store.go | 44 ----------------- eventstore/in_memory_store_test.go | 56 ---------------------- inmemory/eventstore.go | 44 ++++++++++------- inmemory/eventstore_test.go | 54 +++++++++++++++++++++ inmemory/inmemory_suite_test.go | 13 +++++ inmemory/mock_test.go | 17 +++++++ mongodb/eventstore.go | 76 +++++++++++++++++------------- 9 files changed, 158 insertions(+), 191 deletions(-) delete mode 100644 eventstore/in_memory_store.go delete mode 100644 eventstore/in_memory_store_test.go create mode 100644 inmemory/eventstore_test.go create mode 100644 inmemory/inmemory_suite_test.go create mode 100644 inmemory/mock_test.go diff --git a/eventstore/event_store.go b/eventstore/event_store.go index 23a85859..37bdb122 100644 --- a/eventstore/event_store.go +++ b/eventstore/event_store.go @@ -6,44 +6,3 @@ type EventStore interface { FromVersion(streamName StreamName, id string, version int) (*EventStream, error) CountEventsFor(streamName StreamName, id string) (int, error) } - -type EventStoreAdapter interface { - Save(streamName StreamName, events *DomainMessage) error - GetEventsFor(streamName StreamName, id string) ([]*DomainMessage, error) - FromVersion(streamName StreamName, id string, version int) ([]*DomainMessage, error) - CountEventsFor(streamName StreamName, id string) (int, error) -} - -type EventStoreImp struct { - adapter EventStoreAdapter -} - -func NewEventStore(adapter EventStoreAdapter) *EventStoreImp { - return &EventStoreImp{adapter} -} - -func (es *EventStoreImp) Append(events *EventStream) error { - name := events.Name - for _, event := range events.Events { - err := es.adapter.Save(name, event) - if nil != err { - return err - } - } - - return nil -} - -func (es *EventStoreImp) FromVersion(streamName StreamName, id string, version int) (*EventStream, error) { - events, err := es.adapter.FromVersion(streamName, id, version) - return NewEventStream(streamName, events), err -} - -func (es *EventStoreImp) GetEventsFor(streamName StreamName, id string) (*EventStream, error) { - events, err := es.adapter.GetEventsFor(streamName, id) - return NewEventStream(streamName, events), err -} - -func (es *EventStoreImp) CountEventsFor(streamName StreamName, id string) (int, error) { - return es.adapter.CountEventsFor(streamName, id) -} diff --git a/eventstore/event_store_test.go b/eventstore/event_store_test.go index a4eb51f8..0bc33f0e 100644 --- a/eventstore/event_store_test.go +++ b/eventstore/event_store_test.go @@ -2,6 +2,7 @@ package eventstore_test import ( . "github.com/hellofresh/goengine/eventstore" + "github.com/hellofresh/goengine/inmemory" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -13,8 +14,7 @@ var _ = Describe("A Event Store", func() { var aggregateId string var streamName StreamName - adapter := NewInMemoryEventStore() - store = NewEventStore(adapter) + store = inmemory.NewEventStore() BeforeEach(func() { eventStream = nil diff --git a/eventstore/in_memory_store.go b/eventstore/in_memory_store.go deleted file mode 100644 index f7938c46..00000000 --- a/eventstore/in_memory_store.go +++ /dev/null @@ -1,44 +0,0 @@ -package eventstore - -type InMemoryEventStore struct { - events map[StreamName]map[string][]*DomainMessage -} - -func NewInMemoryEventStore() *InMemoryEventStore { - return &InMemoryEventStore{make(map[StreamName]map[string][]*DomainMessage)} -} - -func (s *InMemoryEventStore) Save(streamName StreamName, event *DomainMessage) error { - id := event.ID - events, exists := s.events[streamName][id] - - if !exists { - s.events[streamName] = make(map[string][]*DomainMessage) - } - - s.events[streamName][id] = append(events, event) - - return nil -} - -func (s *InMemoryEventStore) GetEventsFor(streamName StreamName, id string) ([]*DomainMessage, error) { - return s.events[streamName][id], nil -} - -func (s *InMemoryEventStore) FromVersion(streamName StreamName, id string, version int) ([]*DomainMessage, error) { - events, _ := s.GetEventsFor(streamName, id) - var filtered []*DomainMessage - - for _, event := range events { - if event.Version >= version { - filtered = append(filtered, event) - } - } - - return filtered, nil -} - -func (s *InMemoryEventStore) CountEventsFor(streamName StreamName, id string) (int, error) { - result, _ := s.GetEventsFor(streamName, id) - return len(result), nil -} diff --git a/eventstore/in_memory_store_test.go b/eventstore/in_memory_store_test.go deleted file mode 100644 index c7cced5d..00000000 --- a/eventstore/in_memory_store_test.go +++ /dev/null @@ -1,56 +0,0 @@ -package eventstore_test - -import ( - . "github.com/hellofresh/goengine/eventstore" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" -) - -var _ = Describe("In Memory Event Store", func() { - var events []DomainEvent - var inMemory *InMemoryEventStore = NewInMemoryEventStore() - var aggregateId string - var streamName StreamName - - BeforeEach(func() { - events = nil // clear the slice before each execution - aggregateId = "594fb936-d646-44b5-a152-84eb4f709f20" - streamName = "test" - }) - - JustBeforeEach(func() { - events = append(events, NewSomethingHappened()) - events = append(events, NewSomethingHappened()) - events = append(events, NewSomethingHappened()) - events = append(events, NewSomethingHappened()) - }) - - Describe("when something happens", func() { - It("should save an event", func() { - for version, event := range events { - message := RecordNow(aggregateId, version, event) - err := inMemory.Save(streamName, message) - Expect(err).To(BeNil()) - } - }) - - It("should retrive the things that happened", func() { - expectedEvents, err := inMemory.GetEventsFor(streamName, aggregateId) - - Expect(err).To(BeNil()) - Expect(expectedEvents).To(HaveLen(4)) - }) - - It("should count the events that happened", func() { - Expect(inMemory.CountEventsFor(streamName, aggregateId)).Should(Equal(4)) - }) - - It("should retrieve events for version bigger then 1", func() { - expectedEvents, err := inMemory.FromVersion(streamName, aggregateId, 1) - - Expect(err).To(BeNil()) - Expect(expectedEvents).To(HaveLen(3)) - }) - }) -}) diff --git a/inmemory/eventstore.go b/inmemory/eventstore.go index 21447d89..b0a85427 100644 --- a/inmemory/eventstore.go +++ b/inmemory/eventstore.go @@ -6,41 +6,53 @@ type InMemoryEventStore struct { events map[eventstore.StreamName]map[string][]*eventstore.DomainMessage } -func NewInMemoryEventStore() *InMemoryEventStore { +func NewEventStore() *InMemoryEventStore { return &InMemoryEventStore{make(map[eventstore.StreamName]map[string][]*eventstore.DomainMessage)} } -func (s *InMemoryEventStore) Save(streamName eventstore.StreamName, event *eventstore.DomainMessage) error { - id := event.ID - events, exists := s.events[streamName][id] - - if !exists { - s.events[streamName] = make(map[string][]*eventstore.DomainMessage) +func (s *InMemoryEventStore) Append(events *eventstore.EventStream) error { + name := events.Name + for _, event := range events.Events { + err := s.save(name, event) + if nil != err { + return err + } } - s.events[streamName][id] = append(events, event) - return nil } -func (s *InMemoryEventStore) GetEventsFor(streamName eventstore.StreamName, id string) ([]*eventstore.DomainMessage, error) { - return s.events[streamName][id], nil +func (s *InMemoryEventStore) GetEventsFor(streamName eventstore.StreamName, id string) (*eventstore.EventStream, error) { + return eventstore.NewEventStream(streamName, s.events[streamName][id]), nil } -func (s *InMemoryEventStore) FromVersion(streamName eventstore.StreamName, id string, version int) ([]*eventstore.DomainMessage, error) { +func (s *InMemoryEventStore) FromVersion(streamName eventstore.StreamName, id string, version int) (*eventstore.EventStream, error) { events, _ := s.GetEventsFor(streamName, id) var filtered []*eventstore.DomainMessage - for _, event := range events { + for _, event := range events.Events { if event.Version >= version { filtered = append(filtered, event) } } - return filtered, nil + return eventstore.NewEventStream(streamName, filtered), nil } func (s *InMemoryEventStore) CountEventsFor(streamName eventstore.StreamName, id string) (int, error) { - result, _ := s.GetEventsFor(streamName, id) - return len(result), nil + stream, _ := s.GetEventsFor(streamName, id) + return len(stream.Events), nil +} + +func (s *InMemoryEventStore) save(streamName eventstore.StreamName, event *eventstore.DomainMessage) error { + id := event.ID + events, exists := s.events[streamName][id] + + if !exists { + s.events[streamName] = make(map[string][]*eventstore.DomainMessage) + } + + s.events[streamName][id] = append(events, event) + + return nil } diff --git a/inmemory/eventstore_test.go b/inmemory/eventstore_test.go new file mode 100644 index 00000000..55280b61 --- /dev/null +++ b/inmemory/eventstore_test.go @@ -0,0 +1,54 @@ +package inmemory_test + +import ( + . "github.com/hellofresh/goengine/eventstore" + . "github.com/hellofresh/goengine/inmemory" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("In Memory Event Store", func() { + var events []*DomainMessage + var inMemory *InMemoryEventStore = NewEventStore() + var aggregateId string + var streamName StreamName + + BeforeEach(func() { + events = nil // clear the slice before each execution + aggregateId = "eca7741f-b4c2-4fec-bfc7-be438a794be9" //uuid.New() + streamName = "test" + }) + + JustBeforeEach(func() { + events = append(events, RecordNow(aggregateId, 0, NewSomethingHappened())) + events = append(events, RecordNow(aggregateId, 1, NewSomethingHappened())) + events = append(events, RecordNow(aggregateId, 2, NewSomethingHappened())) + events = append(events, RecordNow(aggregateId, 3, NewSomethingHappened())) + }) + + Describe("when something happens", func() { + It("should save an event", func() { + err := inMemory.Append(NewEventStream(streamName, events)) + Expect(err).To(BeNil()) + }) + + It("should retrive the things that happened", func() { + stream, err := inMemory.GetEventsFor(streamName, aggregateId) + + Expect(err).To(BeNil()) + Expect(stream.Events).To(HaveLen(4)) + }) + + It("should count the events that happened", func() { + Expect(inMemory.CountEventsFor(streamName, aggregateId)).Should(Equal(4)) + }) + + It("should retrieve events for version bigger then 1", func() { + stream, err := inMemory.FromVersion(streamName, aggregateId, 1) + + Expect(err).To(BeNil()) + Expect(stream.Events).To(HaveLen(3)) + }) + }) +}) diff --git a/inmemory/inmemory_suite_test.go b/inmemory/inmemory_suite_test.go new file mode 100644 index 00000000..7fc228ea --- /dev/null +++ b/inmemory/inmemory_suite_test.go @@ -0,0 +1,13 @@ +package inmemory_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "testing" +) + +func TestGoengine(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "In Memory Suite") +} diff --git a/inmemory/mock_test.go b/inmemory/mock_test.go new file mode 100644 index 00000000..c3c5f6fe --- /dev/null +++ b/inmemory/mock_test.go @@ -0,0 +1,17 @@ +package inmemory_test + +import ( + "time" +) + +type SomethingHappened struct { + ocurredOn time.Time +} + +func NewSomethingHappened() SomethingHappened { + return SomethingHappened{time.Now()} +} + +func (e SomethingHappened) OcurredOn() time.Time { + return e.ocurredOn +} diff --git a/mongodb/eventstore.go b/mongodb/eventstore.go index 16c8f0cb..7af4ece1 100644 --- a/mongodb/eventstore.go +++ b/mongodb/eventstore.go @@ -31,39 +31,19 @@ func NewEventStore(conn *mgo.Session, r reflection.TypeRegistry) *MongoDbEventSt return &MongoDbEventStore{conn, db, r} } -func (s *MongoDbEventStore) Save(streamName eventstore.StreamName, event *eventstore.DomainMessage) error { - coll := s.db.C(string(streamName)) - err := s.createIndexes(coll) - if nil != err { - return err - } - - serializedPayload, err := json.Marshal(event.Payload) - if nil != err { - return err - } - - typeName, err := s.registry.TypeOf(event.Payload) - if nil != err { - return err - } - - if !s.registry.Exists(typeName.String()) { - return errors.ErrorTypeNotRegistred - } - - eventData := &EventData{ - ID: event.ID, - Version: event.Version, - Type: typeName.String(), - Payload: string(serializedPayload), - RecordedOn: event.RecordedOn, +func (s *MongoDbEventStore) Append(events *eventstore.EventStream) error { + name := events.Name + for _, event := range events.Events { + err := s.save(name, event) + if nil != err { + return err + } } - return coll.Insert(eventData) + return nil } -func (s *MongoDbEventStore) GetEventsFor(streamName eventstore.StreamName, id string) ([]*eventstore.DomainMessage, error) { +func (s *MongoDbEventStore) GetEventsFor(streamName eventstore.StreamName, id string) (*eventstore.EventStream, error) { var eventsData []*EventData var results []*eventstore.DomainMessage @@ -86,10 +66,10 @@ func (s *MongoDbEventStore) GetEventsFor(streamName eventstore.StreamName, id st results = append(results, domainMessage) } - return results, err + return eventstore.NewEventStream(streamName, results), err } -func (s *MongoDbEventStore) FromVersion(streamName eventstore.StreamName, id string, version int) ([]*eventstore.DomainMessage, error) { +func (s *MongoDbEventStore) FromVersion(streamName eventstore.StreamName, id string, version int) (*eventstore.EventStream, error) { var results []*eventstore.DomainMessage coll := s.db.C(string(streamName)) @@ -100,7 +80,7 @@ func (s *MongoDbEventStore) FromVersion(streamName eventstore.StreamName, id str Sort("-version"). All(&results) - return results, err + return eventstore.NewEventStream(streamName, results), err } func (s *MongoDbEventStore) CountEventsFor(streamName eventstore.StreamName, id string) (int, error) { @@ -117,3 +97,35 @@ func (s *MongoDbEventStore) createIndexes(c *mgo.Collection) error { return c.EnsureIndex(index) } + +func (s *MongoDbEventStore) save(streamName eventstore.StreamName, event *eventstore.DomainMessage) error { + coll := s.db.C(string(streamName)) + err := s.createIndexes(coll) + if nil != err { + return err + } + + serializedPayload, err := json.Marshal(event.Payload) + if nil != err { + return err + } + + typeName, err := s.registry.TypeOf(event.Payload) + if nil != err { + return err + } + + if !s.registry.Exists(typeName.String()) { + return errors.ErrorTypeNotRegistred + } + + eventData := &EventData{ + ID: event.ID, + Version: event.Version, + Type: typeName.String(), + Payload: string(serializedPayload), + RecordedOn: event.RecordedOn, + } + + return coll.Insert(eventData) +} From c3107604d23a230bd2cb99200d038ccf858999a1 Mon Sep 17 00:00:00 2001 From: Italo Lelis de Vietro Date: Sat, 29 Oct 2016 20:00:12 +0200 Subject: [PATCH 20/74] Fixed types --- cmd/goengine/main.go | 13 ++---- eventsourcing/aggregate_root.go | 7 +-- eventstore/snapshot/snapshot.go | 10 ++++ mongodb/eventstore.go | 15 ++---- reflection/caller.go | 12 +++++ reflection/type_registry.go | 82 --------------------------------- type_registry.go | 66 ++++++++++++++++++++++++++ 7 files changed, 97 insertions(+), 108 deletions(-) create mode 100644 eventstore/snapshot/snapshot.go delete mode 100644 reflection/type_registry.go create mode 100644 type_registry.go diff --git a/cmd/goengine/main.go b/cmd/goengine/main.go index 632f60f8..30e04e13 100644 --- a/cmd/goengine/main.go +++ b/cmd/goengine/main.go @@ -4,9 +4,9 @@ import ( "os" log "github.com/Sirupsen/logrus" + "github.com/hellofresh/goengine" "github.com/hellofresh/goengine/eventstore" "github.com/hellofresh/goengine/mongodb" - "github.com/hellofresh/goengine/serializer" "github.com/satori/go.uuid" "gopkg.in/mgo.v2" @@ -28,10 +28,10 @@ func main() { session.SetMode(mgo.Monotonic, true) log.Info("Setting up the event store") - registry := serializer.NewInMemmoryTypeRegistry() - registry.Register(&SomethingHappened{}) + registry := goengine.NewInMemmoryTypeRegistry() + registry.RegisterType(&SomethingHappened{}) - es := SetupEventStore(session, registry) + es := mongodb.NewEventStore(session, registry) log.Info("Creating the event stream") stream := CreateEventStream(streamName, aggregateID.String()) @@ -48,11 +48,6 @@ func main() { log.Info(events) } -func SetupEventStore(session *mgo.Session, registry serializer.TypeRegistry) eventstore.EventStore { - adapter := mongodb.NewEventStore(session, registry) - return eventstore.NewEventStore(adapter) -} - func CreateEventStream(streamName eventstore.StreamName, aggregateId string) *eventstore.EventStream { var events []*eventstore.DomainMessage diff --git a/eventsourcing/aggregate_root.go b/eventsourcing/aggregate_root.go index 0ef7bc92..910d5734 100644 --- a/eventsourcing/aggregate_root.go +++ b/eventsourcing/aggregate_root.go @@ -2,7 +2,6 @@ package eventsourcing import ( "fmt" - "reflect" "github.com/hellofresh/goengine/eventstore" "github.com/hellofresh/goengine/reflection" @@ -38,11 +37,7 @@ func (ar *AggregateRoot) GetUncommittedEvents() []*eventstore.DomainMessage { } func (r *AggregateRoot) Apply(event eventstore.DomainEvent) { - t := reflect.TypeOf(event) - if t.Kind() == reflect.Ptr { - t = t.Elem() - } - + t := reflection.TypeOf(event) reflection.CallMethod(r.source, fmt.Sprintf("When%s", t.Name()), event) } diff --git a/eventstore/snapshot/snapshot.go b/eventstore/snapshot/snapshot.go new file mode 100644 index 00000000..282ae403 --- /dev/null +++ b/eventstore/snapshot/snapshot.go @@ -0,0 +1,10 @@ +package snapshot + +import "time" + +type Snapshot struct { + version int + aggregateID string + // aggregate + createdAt time.Time +} diff --git a/mongodb/eventstore.go b/mongodb/eventstore.go index 7af4ece1..21860c1b 100644 --- a/mongodb/eventstore.go +++ b/mongodb/eventstore.go @@ -4,7 +4,7 @@ import ( "encoding/json" "time" - "github.com/hellofresh/goengine/errors" + "github.com/hellofresh/goengine" "github.com/hellofresh/goengine/eventstore" "github.com/hellofresh/goengine/reflection" @@ -23,10 +23,10 @@ type EventData struct { type MongoDbEventStore struct { conn *mgo.Session db *mgo.Database - registry reflection.TypeRegistry + registry goengine.TypeRegistry } -func NewEventStore(conn *mgo.Session, r reflection.TypeRegistry) *MongoDbEventStore { +func NewEventStore(conn *mgo.Session, r goengine.TypeRegistry) *MongoDbEventStore { db := conn.DB("") return &MongoDbEventStore{conn, db, r} } @@ -110,14 +110,7 @@ func (s *MongoDbEventStore) save(streamName eventstore.StreamName, event *events return err } - typeName, err := s.registry.TypeOf(event.Payload) - if nil != err { - return err - } - - if !s.registry.Exists(typeName.String()) { - return errors.ErrorTypeNotRegistred - } + typeName := reflection.TypeOf(event.Payload) eventData := &EventData{ ID: event.ID, diff --git a/reflection/caller.go b/reflection/caller.go index f01032f1..303118d3 100644 --- a/reflection/caller.go +++ b/reflection/caller.go @@ -18,3 +18,15 @@ func CallMethod(i interface{}, methodName string, args ...interface{}) interface // return or panic, method not found of either type return "" } + +// TypeOf returns the type of a struct checking if it's a pointer or not +func TypeOf(i interface{}) reflect.Type { + // Convert the interface i to a reflect.Type t + t := reflect.TypeOf(i) + // Check if the input is a pointer and dereference it if yes + if t.Kind() == reflect.Ptr { + t = t.Elem() + } + + return t +} diff --git a/reflection/type_registry.go b/reflection/type_registry.go deleted file mode 100644 index 6a5bc18e..00000000 --- a/reflection/type_registry.go +++ /dev/null @@ -1,82 +0,0 @@ -package reflection - -import ( - "reflect" - - "github.com/hellofresh/goengine/errors" -) - -// TypeRegistry is a registry for go types -// this is necessary since we can't create a type from -// a string and it's json. With this registry we can -// know how to create a type for that string -type TypeRegistry interface { - Register(i interface{}) error - Unregister(i interface{}) error - Exists(name string) bool - Get(name string) (interface{}, error) - TypeOf(i interface{}) (reflect.Type, error) -} - -// InMemoryTypeRegistry implements the in memory strategy -// for the registry -type InMemoryTypeRegistry struct { - types map[string]reflect.Type -} - -// NewInMemmoryTypeRegistry creates a new in memory registry -func NewInMemmoryTypeRegistry() *InMemoryTypeRegistry { - return &InMemoryTypeRegistry{make(map[string]reflect.Type)} -} - -// Register adds a type in the registry -func (tr *InMemoryTypeRegistry) Register(i interface{}) error { - t, err := tr.TypeOf(i) - if nil != err { - return err - } - - tr.types[t.String()] = t - return nil -} - -// Unregister removes a type from the registry -func (tr *InMemoryTypeRegistry) Unregister(i interface{}) error { - t, err := tr.TypeOf(i) - if nil != err { - return err - } - - delete(tr.types, t.String()) - return nil -} - -// Exists checks if a type exists in the registry -func (tr *InMemoryTypeRegistry) Exists(name string) bool { - _, exists := tr.types[name] - return exists -} - -// Get retrieves a reflect.Type based on a name -func (tr *InMemoryTypeRegistry) Get(name string) (interface{}, error) { - if typ, ok := tr.types[name]; ok { - return reflect.New(typ).Interface(), nil - } - return nil, errors.ErrorTypeNotFound -} - -// TypeOf returns the type of a struct checking if it's a pointer or not -func (tr *InMemoryTypeRegistry) TypeOf(i interface{}) (reflect.Type, error) { - // Convert the interface i to a reflect.Type t - t := reflect.TypeOf(i) - // Check if the input is a pointer and dereference it if yes - if t.Kind() == reflect.Ptr { - t = t.Elem() - } - // Check if the input is a struct - if t.Kind() != reflect.Struct { - return nil, errors.ErrorTypeNotStruct - } - - return t, nil -} diff --git a/type_registry.go b/type_registry.go new file mode 100644 index 00000000..67b59b47 --- /dev/null +++ b/type_registry.go @@ -0,0 +1,66 @@ +package goengine + +import ( + "reflect" + + + "github.com/hellofresh/goengine/errors" + "github.com/hellofresh/goengine/reflection" +) + +// TypeRegistry is a registry for go types +// this is necessary since we can't create a type from +// a string and it's json. With this registry we can +// know how to create a type for that string +type TypeRegistry interface { + GetTypeByName(string) (reflect.Type, bool) + RegisterAggregate(aggregate interface{}, events ...interface{}) + RegisterEvents(events ...interface{}) + RegisterType(interface{}) + Get(name string) (interface{}, error) +} + +// InMemoryTypeRegistry implements the in memory strategy +// for the registry +type InMemoryTypeRegistry struct { + types map[string]reflect.Type +} + +// NewInMemmoryTypeRegistry creates a new in memory registry +func NewInMemmoryTypeRegistry() *InMemoryTypeRegistry { + return &InMemoryTypeRegistry{make(map[string]reflect.Type)} +} + +// RegisterType adds a type in the registry +func (r *InMemoryTypeRegistry) RegisterType(i interface{}) { + rawType := reflection.TypeOf(i) + r.types[rawType.String()] = rawType +} + +func (r *InMemoryTypeRegistry) RegisterAggregate(aggregate interface{}, events ...interface{}) { + r.RegisterType(aggregate) + + r.RegisterEvents(events) +} + +func (r *InMemoryTypeRegistry) RegisterEvents(events ...interface{}) { + for _, event := range events { + r.RegisterType(event) + } +} + +func (r *InMemoryTypeRegistry) GetTypeByName(typeName string) (reflect.Type, bool) { + if typeValue, ok := r.types[typeName]; ok { + return typeValue, ok + } + + return nil, false +} + +// Get retrieves a reflect.Type based on a name +func (r *InMemoryTypeRegistry) Get(name string) (interface{}, error) { + if typ, ok := r.GetTypeByName(name); ok { + return reflect.New(typ).Interface(), nil + } + return nil, errors.ErrorTypeNotFound +} From 79c3e5c09969d2906164672a73c09627f10c6145 Mon Sep 17 00:00:00 2001 From: Italo Lelis de Vietro Date: Sat, 29 Oct 2016 20:03:35 +0200 Subject: [PATCH 21/74] Updated dependencies --- glide.lock | 14 ++++++++++++-- glide.yaml | 4 ++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/glide.lock b/glide.lock index 18a243e1..f39f7159 100644 --- a/glide.lock +++ b/glide.lock @@ -1,6 +1,16 @@ -hash: 820280dd6a9cc7f07393743ed26e4b6a5932f544d6dd9562626d52283e2386ea -updated: 2016-10-27T11:25:26.661198153+02:00 +hash: 938ece1d62c503bb967295ad413b00ad89b712e77e659f0554476b7c756ce305 +updated: 2016-10-29T20:02:02.431531549+02:00 imports: +- name: github.com/pborman/uuid + version: c55201b036063326c5b1b89ccfe45a184973d073 +- name: github.com/satori/go.uuid + version: 879c5887cd475cd7864858769793b2ceb0d44feb +- name: github.com/Sirupsen/logrus + version: 4b6ea7319e214d98c938f12692336f7ca9348d6b +- name: golang.org/x/sys + version: a408501be4d17ee978c04a618e7a1b22af058c0e + subpackages: + - unix - name: gopkg.in/mgo.v2 version: 3f83fa5005286a7fe593b055f0d7771a7dce4655 subpackages: diff --git a/glide.yaml b/glide.yaml index 97849511..ff5f08ca 100644 --- a/glide.yaml +++ b/glide.yaml @@ -3,6 +3,10 @@ import: - package: gopkg.in/mgo.v2 subpackages: - bson +- package: github.com/satori/go.uuid + version: ^1.1.0 +- package: github.com/Sirupsen/logrus + version: ^0.10.0 testImport: - package: github.com/onsi/ginkgo version: ^1.2.0 From 904e467a7e7baae26f99a935598ba3938066c99c Mon Sep 17 00:00:00 2001 From: Italo Lelis de Vietro Date: Sat, 29 Oct 2016 22:22:52 +0200 Subject: [PATCH 22/74] Added reconsitute to repository --- cmd/goengine/event.go | 15 ------- cmd/goengine/main.go | 43 ++++++++++--------- cmd/goengine/model.go | 60 +++++++++++++++++++++++++++ eventsourcing/aggregate_repository.go | 54 ++++++++++++++++++++++++ eventsourcing/aggregate_root.go | 55 ++++++++++++++---------- eventsourcing/mock_test.go | 4 +- type_registry.go | 16 ++++--- 7 files changed, 182 insertions(+), 65 deletions(-) delete mode 100644 cmd/goengine/event.go create mode 100644 cmd/goengine/model.go create mode 100644 eventsourcing/aggregate_repository.go diff --git a/cmd/goengine/event.go b/cmd/goengine/event.go deleted file mode 100644 index 9a5c45d6..00000000 --- a/cmd/goengine/event.go +++ /dev/null @@ -1,15 +0,0 @@ -package main - -import "time" - -type SomethingHappened struct { - Ocurred time.Time `json:"ocurred_on"` -} - -func NewSomethingHappened() *SomethingHappened { - return &SomethingHappened{time.Now()} -} - -func (e *SomethingHappened) OcurredOn() time.Time { - return e.Ocurred -} diff --git a/cmd/goengine/main.go b/cmd/goengine/main.go index 30e04e13..68b10650 100644 --- a/cmd/goengine/main.go +++ b/cmd/goengine/main.go @@ -5,16 +5,16 @@ import ( log "github.com/Sirupsen/logrus" "github.com/hellofresh/goengine" + "github.com/hellofresh/goengine/eventsourcing" "github.com/hellofresh/goengine/eventstore" "github.com/hellofresh/goengine/mongodb" - "github.com/satori/go.uuid" "gopkg.in/mgo.v2" ) func main() { + log.SetLevel(log.DebugLevel) var streamName eventstore.StreamName = "test" - aggregateID := uuid.NewV4() mongoDSN := os.Getenv("STORAGE_DSN") log.Infof("Connecting to the database %s", mongoDSN) @@ -27,33 +27,32 @@ func main() { // Optional. Switch the session to a monotonic behavior. session.SetMode(mgo.Monotonic, true) - log.Info("Setting up the event store") + log.Info("Setting up the registry") registry := goengine.NewInMemmoryTypeRegistry() - registry.RegisterType(&SomethingHappened{}) + registry.RegisterType(&RecipeCreated{}) + registry.RegisterType(&RecipeRated{}) + log.Info("Setting up the event store") es := mongodb.NewEventStore(session, registry) - log.Info("Creating the event stream") - stream := CreateEventStream(streamName, aggregateID.String()) + log.Info("Creating a recipe") + repository := eventsourcing.NewPublisherRepository(es) - err = es.Append(stream) - if nil != err { - log.Error(err) - } + log.Info("Creating a recipe") + aggregateRoot := CreateScenario(streamName) - events, err := es.GetEventsFor(streamName, aggregateID.String()) - if nil != err { - log.Error(err) - } - log.Info(events) -} + repository.Save(aggregateRoot, streamName) -func CreateEventStream(streamName eventstore.StreamName, aggregateId string) *eventstore.EventStream { - var events []*eventstore.DomainMessage + history, err := NewRecipeFromHisotry(aggregateRoot.ID, streamName, repository) + if err != nil { + log.Panic(err) + } - events = append(events, eventstore.RecordNow(aggregateId, 0, NewSomethingHappened())) - events = append(events, eventstore.RecordNow(aggregateId, 1, NewSomethingHappened())) - events = append(events, eventstore.RecordNow(aggregateId, 2, NewSomethingHappened())) + log.Info(history) +} - return eventstore.NewEventStream(streamName, events) +func CreateScenario(streamName eventstore.StreamName) *Recipe { + recipe := NewRecipe("Test Recipe") + recipe.Rate(4) + return recipe } diff --git a/cmd/goengine/model.go b/cmd/goengine/model.go new file mode 100644 index 00000000..736a6c37 --- /dev/null +++ b/cmd/goengine/model.go @@ -0,0 +1,60 @@ +package main + +import ( + "time" + + "github.com/hellofresh/goengine/eventsourcing" + "github.com/hellofresh/goengine/eventstore" +) + +type RecipeCreated struct { + ocurredOn time.Time + Name string +} + +func (e RecipeCreated) OcurredOn() time.Time { + return e.ocurredOn +} + +type RecipeRated struct { + ocurredOn time.Time + Rating int +} + +func (e RecipeRated) OcurredOn() time.Time { + return e.ocurredOn +} + +type Recipe struct { + *eventsourcing.AggregateRootBased + Name string + Rating int +} + +func NewRecipe(name string) *Recipe { + recipe := new(Recipe) + recipe.AggregateRootBased = eventsourcing.NewAggregateRootBased(recipe) + recipe.RecordThat(&RecipeCreated{time.Now(), name}) + + return recipe +} + +func NewRecipeFromHisotry(id string, streamName eventstore.StreamName, repo eventsourcing.AggregateRepository) (*Recipe, error) { + recipe := new(Recipe) + recipe.AggregateRootBased = eventsourcing.NewEventSourceBasedWithID(recipe, id) + err := repo.Reconstitute(id, recipe, streamName) + + return recipe, err +} + +func (r *Recipe) Rate(rate int) { + r.RecordThat(&RecipeRated{time.Now(), rate}) +} + +func (r *Recipe) WhenRecipeCreated(event *RecipeCreated) { + r.Name = event.Name +} + +func (r *Recipe) WhenRecipeRated(event *RecipeRated) { + r.Rating = event.Rating +} diff --git a/eventsourcing/aggregate_repository.go b/eventsourcing/aggregate_repository.go new file mode 100644 index 00000000..4cae8d8f --- /dev/null +++ b/eventsourcing/aggregate_repository.go @@ -0,0 +1,54 @@ +package eventsourcing + +import ( + log "github.com/Sirupsen/logrus" + "github.com/hellofresh/goengine/eventstore" +) + +type AggregateRepository interface { + Load(string, eventstore.StreamName) (*eventstore.EventStream, error) + Save(AggregateRoot, eventstore.StreamName) + Reconstitute(string, AggregateRoot, eventstore.StreamName) error +} + +type PublisherRepository struct { + eventStore eventstore.EventStore +} + +func NewPublisherRepository(eventStore eventstore.EventStore) *PublisherRepository { + return &PublisherRepository{eventStore} +} + +func (r *PublisherRepository) Load(id string, streamName eventstore.StreamName) (*eventstore.EventStream, error) { + log.Debugf("Loading events from %s stream for aggregate %s", streamName, id) + stream, err := r.eventStore.GetEventsFor(streamName, id) + if nil != err { + return nil, err + } + + return stream, nil +} + +func (r *PublisherRepository) Save(aggregateRoot AggregateRoot, streamName eventstore.StreamName) { + events := aggregateRoot.GetUncommittedEvents() + eventStream := eventstore.NewEventStream(streamName, events) + log.Debugf("Saving %d events to %s stream", len(events), streamName) + r.eventStore.Append(eventStream) +} + +func (r *PublisherRepository) Reconstitute(id string, source AggregateRoot, streamName eventstore.StreamName) error { + log.Debugf("Reconstituting aggregate %s from %s stream", id, streamName) + stream, err := r.Load(id, streamName) + if nil != err { + return err + } + events := stream.Events + + for _, event := range events { + source.Apply(event.Payload) + } + + source.SetVersion(events[len(events)-1].Version) + log.Debugf("Aggregate %s reconstituted", id) + return nil +} diff --git a/eventsourcing/aggregate_root.go b/eventsourcing/aggregate_root.go index 910d5734..fe42fc0d 100644 --- a/eventsourcing/aggregate_root.go +++ b/eventsourcing/aggregate_root.go @@ -3,58 +3,71 @@ package eventsourcing import ( "fmt" + log "github.com/Sirupsen/logrus" "github.com/hellofresh/goengine/eventstore" "github.com/hellofresh/goengine/reflection" "github.com/pborman/uuid" ) -type AggregateRoot struct { +type AggregateRoot interface { + GetID() string + GetVersion() int + SetVersion(int) + Apply(eventstore.DomainEvent) + GetUncommittedEvents() []*eventstore.DomainMessage +} + +type AggregateRootBased struct { ID string version int source interface{} uncommitedEvents []*eventstore.DomainMessage } -// NewAggregateRoot constructor -func NewAggregateRoot(source interface{}) AggregateRoot { +// NewAggregateRootBased constructor +func NewAggregateRootBased(source interface{}) *AggregateRootBased { return NewEventSourceBasedWithID(source, uuid.New()) } // NewEventSourceBasedWithID constructor -func NewEventSourceBasedWithID(source interface{}, id string) AggregateRoot { - return AggregateRoot{id, 0, source, []*eventstore.DomainMessage{}} +func NewEventSourceBasedWithID(source interface{}, id string) *AggregateRootBased { + return &AggregateRootBased{id, 0, source, []*eventstore.DomainMessage{}} } -func (ar *AggregateRoot) ReconstituteFromHistory(historyEvents *eventstore.EventStream) { +func (r *AggregateRootBased) GetID() string { + return r.ID +} +func (r *AggregateRootBased) GetVersion() int { + return r.version } -func (ar *AggregateRoot) GetUncommittedEvents() []*eventstore.DomainMessage { - stream := ar.uncommitedEvents - ar.uncommitedEvents = nil +func (r *AggregateRootBased) SetVersion(version int) { + r.version = version +} + +func (r *AggregateRootBased) GetUncommittedEvents() []*eventstore.DomainMessage { + stream := r.uncommitedEvents + r.uncommitedEvents = nil + log.Debugf("%d Uncommited events cleaned", len(stream)) return stream } -func (r *AggregateRoot) Apply(event eventstore.DomainEvent) { +func (r *AggregateRootBased) Apply(event eventstore.DomainEvent) { t := reflection.TypeOf(event) reflection.CallMethod(r.source, fmt.Sprintf("When%s", t.Name()), event) + log.Debugf("Event %s applied", t.Name()) } -func (r *AggregateRoot) RecordThat(event eventstore.DomainEvent) { +func (r *AggregateRootBased) RecordThat(event eventstore.DomainEvent) { r.version++ r.Apply(event) r.Record(event) } -func (r *AggregateRoot) Replay(historyEvents *eventstore.EventStream, version int) { - for _, event := range historyEvents.Events { - r.version = event.Version - r.Apply(event.Payload) - } -} - -func (ar *AggregateRoot) Record(event eventstore.DomainEvent) { - message := eventstore.RecordNow(ar.ID, ar.version, event) - ar.uncommitedEvents = append(ar.uncommitedEvents, message) +func (r *AggregateRootBased) Record(event eventstore.DomainEvent) { + message := eventstore.RecordNow(r.ID, r.version, event) + r.uncommitedEvents = append(r.uncommitedEvents, message) + log.Debug("Event recorded") } diff --git a/eventsourcing/mock_test.go b/eventsourcing/mock_test.go index 1aa9a976..5f68fe55 100644 --- a/eventsourcing/mock_test.go +++ b/eventsourcing/mock_test.go @@ -24,14 +24,14 @@ func (e RecipeRated) OcurredOn() time.Time { } type Recipe struct { - eventsourcing.AggregateRoot + *eventsourcing.AggregateRootBased Name string Rating int } func NewRecipe(name string) *Recipe { recipe := new(Recipe) - recipe.AggregateRoot = eventsourcing.NewAggregateRoot(recipe) + recipe.AggregateRootBased = eventsourcing.NewAggregateRootBased(recipe) recipe.RecordThat(RecipeCreated{time.Now()}) return recipe diff --git a/type_registry.go b/type_registry.go index 67b59b47..023c98c7 100644 --- a/type_registry.go +++ b/type_registry.go @@ -3,8 +3,9 @@ package goengine import ( "reflect" - + log "github.com/Sirupsen/logrus" "github.com/hellofresh/goengine/errors" + "github.com/hellofresh/goengine/eventsourcing" "github.com/hellofresh/goengine/reflection" ) @@ -14,10 +15,10 @@ import ( // know how to create a type for that string type TypeRegistry interface { GetTypeByName(string) (reflect.Type, bool) - RegisterAggregate(aggregate interface{}, events ...interface{}) - RegisterEvents(events ...interface{}) + RegisterAggregate(eventsourcing.AggregateRoot, ...interface{}) + RegisterEvents(...interface{}) RegisterType(interface{}) - Get(name string) (interface{}, error) + Get(string) (interface{}, error) } // InMemoryTypeRegistry implements the in memory strategy @@ -35,12 +36,15 @@ func NewInMemmoryTypeRegistry() *InMemoryTypeRegistry { func (r *InMemoryTypeRegistry) RegisterType(i interface{}) { rawType := reflection.TypeOf(i) r.types[rawType.String()] = rawType + log.Debugf("Type %s was registered", rawType.String()) } -func (r *InMemoryTypeRegistry) RegisterAggregate(aggregate interface{}, events ...interface{}) { +func (r *InMemoryTypeRegistry) RegisterAggregate(aggregate eventsourcing.AggregateRoot, events ...interface{}) { r.RegisterType(aggregate) + log.Debugf("Aggregate %s was registered", aggregate.GetID()) r.RegisterEvents(events) + log.Debugf("%s events were registered for aggregate %s", len(events), aggregate.GetID()) } func (r *InMemoryTypeRegistry) RegisterEvents(events ...interface{}) { @@ -62,5 +66,7 @@ func (r *InMemoryTypeRegistry) Get(name string) (interface{}, error) { if typ, ok := r.GetTypeByName(name); ok { return reflect.New(typ).Interface(), nil } + + log.Debugf("Type %s not found", name) return nil, errors.ErrorTypeNotFound } From 1cc502a1f072ef14c8f04dcf4fd22bca1461b01c Mon Sep 17 00:00:00 2001 From: Italo Lelis de Vietro Date: Sun, 30 Oct 2016 01:45:42 +0200 Subject: [PATCH 23/74] Making the library more "library" --- .travis.yml | 6 +++--- Makefile | 37 ------------------------------------- glide.lock | 51 --------------------------------------------------- glide.yaml | 14 -------------- 4 files changed, 3 insertions(+), 105 deletions(-) delete mode 100644 Makefile delete mode 100644 glide.lock delete mode 100644 glide.yaml diff --git a/.travis.yml b/.travis.yml index 0819a971..cf063810 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,7 @@ go: - master install: - # - docker-compose up -d - - make deps + - go get github.com/onsi/ginkgo/ginkgo + - go get github.com/onsi/gomega -script: make test +script: ginkgo -r diff --git a/Makefile b/Makefile deleted file mode 100644 index 8e585ce8..00000000 --- a/Makefile +++ /dev/null @@ -1,37 +0,0 @@ -NO_COLOR=\033[0m -OK_COLOR=\033[32;01m -ERROR_COLOR=\033[31;01m -WARN_COLOR=\033[33;01m - -# This how we want to name the binary output -BINARY=goengine - -.PHONY: all clean deps install - -all: clean deps install - -deps: - @echo "$(OK_COLOR)==> Installing glide dependencies$(NO_COLOR)" - @curl https://glide.sh/get | sh - @glide install - -# Builds the project -build: - @echo "$(OK_COLOR)==> Building project$(NO_COLOR)" - @go build -o ${BINARY} - -# Installs our project: copies binaries -install: - @echo "$(OK_COLOR)==> Installing project$(NO_COLOR)" - go install -v ./cmd/goengine - -# Cleans our project: deletes binaries -clean: - @echo "$(OK_COLOR)==> Cleaning project$(NO_COLOR)" - if [ -f ${BINARY} ] ; then rm ${BINARY} ; fi - -test: - @echo "$(OK_COLOR)==> Installign test dependencies" - go get github.com/onsi/ginkgo/ginkgo - go get github.com/onsi/gomega - ginkgo -r diff --git a/glide.lock b/glide.lock deleted file mode 100644 index f39f7159..00000000 --- a/glide.lock +++ /dev/null @@ -1,51 +0,0 @@ -hash: 938ece1d62c503bb967295ad413b00ad89b712e77e659f0554476b7c756ce305 -updated: 2016-10-29T20:02:02.431531549+02:00 -imports: -- name: github.com/pborman/uuid - version: c55201b036063326c5b1b89ccfe45a184973d073 -- name: github.com/satori/go.uuid - version: 879c5887cd475cd7864858769793b2ceb0d44feb -- name: github.com/Sirupsen/logrus - version: 4b6ea7319e214d98c938f12692336f7ca9348d6b -- name: golang.org/x/sys - version: a408501be4d17ee978c04a618e7a1b22af058c0e - subpackages: - - unix -- name: gopkg.in/mgo.v2 - version: 3f83fa5005286a7fe593b055f0d7771a7dce4655 - subpackages: - - bson - - internal/json - - internal/sasl - - internal/scram -testImports: -- name: github.com/onsi/ginkgo - version: 462326b1628e124b23f42e87a8f2750e3c4e2d24 - subpackages: - - config - - internal/codelocation - - internal/containernode - - internal/failer - - internal/leafnodes - - internal/remote - - internal/spec - - internal/specrunner - - internal/suite - - internal/testingtproxy - - internal/writer - - reporters - - reporters/stenographer - - types -- name: github.com/onsi/gomega - version: a78ae492d53aad5a7a232d0d0462c14c400e3ee7 - subpackages: - - format - - internal/assertion - - internal/asyncassertion - - internal/testingtsupport - - matchers - - matchers/support/goraph/bipartitegraph - - matchers/support/goraph/edge - - matchers/support/goraph/node - - matchers/support/goraph/util - - types diff --git a/glide.yaml b/glide.yaml deleted file mode 100644 index ff5f08ca..00000000 --- a/glide.yaml +++ /dev/null @@ -1,14 +0,0 @@ -package: github.com/hellofresh/goengine -import: -- package: gopkg.in/mgo.v2 - subpackages: - - bson -- package: github.com/satori/go.uuid - version: ^1.1.0 -- package: github.com/Sirupsen/logrus - version: ^0.10.0 -testImport: -- package: github.com/onsi/ginkgo - version: ^1.2.0 -- package: github.com/onsi/gomega - version: ^1.0.0 From 56414af241d28c60406a6a8461092c0358b11aa9 Mon Sep 17 00:00:00 2001 From: Italo Lelis de Vietro Date: Sun, 30 Oct 2016 02:13:32 +0200 Subject: [PATCH 24/74] Tyding up the mongo event store --- mongodb/eventstore.go | 88 ++++++++++++++++++++++++++++--------------- 1 file changed, 57 insertions(+), 31 deletions(-) diff --git a/mongodb/eventstore.go b/mongodb/eventstore.go index 21860c1b..0057633f 100644 --- a/mongodb/eventstore.go +++ b/mongodb/eventstore.go @@ -12,7 +12,8 @@ import ( "gopkg.in/mgo.v2/bson" ) -type EventData struct { +// MongoEvent represents an event on mongodb +type MongoEvent struct { ID string `bson:"aggregate_id,omitempty"` Version int `bson:"version"` Type string `bson:"type"` @@ -20,57 +21,61 @@ type EventData struct { RecordedOn time.Time `bson:"recorded_on"` } +// MongoDbEventStore The mongodb event store type MongoDbEventStore struct { conn *mgo.Session db *mgo.Database registry goengine.TypeRegistry } +// NewEventStore creates new MongoDB based event store func NewEventStore(conn *mgo.Session, r goengine.TypeRegistry) *MongoDbEventStore { - db := conn.DB("") - return &MongoDbEventStore{conn, db, r} + return &MongoDbEventStore{conn, conn.DB(""), r} } +// Append adds an event to the event store func (s *MongoDbEventStore) Append(events *eventstore.EventStream) error { - name := events.Name + streamName := string(events.Name) for _, event := range events.Events { - err := s.save(name, event) + mongoEvent, err := s.toMongoEvent(event) if nil != err { return err } + + coll := s.db.C(streamName) + err = s.createIndexes(coll) + if nil != err { + return err + } + + return coll.Insert(mongoEvent) } return nil } +// GetEventsFor gets events for an id on the specified stream func (s *MongoDbEventStore) GetEventsFor(streamName eventstore.StreamName, id string) (*eventstore.EventStream, error) { - var eventsData []*EventData - var results []*eventstore.DomainMessage - + var mongoEvents []*MongoEvent coll := s.db.C(string(streamName)) + err := coll.Find(bson.M{"aggregate_id": id}).All(&mongoEvents) - err := coll.Find(bson.M{"aggregate_id": id}).All(&eventsData) - - for _, eventData := range eventsData { - event, err := s.registry.Get(eventData.Type) - if nil != err { - return nil, err - } - - err = json.Unmarshal([]byte(eventData.Payload), event) + var results []*eventstore.DomainMessage + for _, mongoEvent := range mongoEvents { + domainMessage, err := s.fromMongoEvent(mongoEvent) if nil != err { return nil, err } - domainMessage := eventstore.NewDomainMessage(eventData.ID, eventData.Version, event.(eventstore.DomainEvent), eventData.RecordedOn) results = append(results, domainMessage) } return eventstore.NewEventStream(streamName, results), err } +// FromVersion gets events for an id and version on the specified stream func (s *MongoDbEventStore) FromVersion(streamName eventstore.StreamName, id string, version int) (*eventstore.EventStream, error) { - var results []*eventstore.DomainMessage + var mongoEvents []*MongoEvent coll := s.db.C(string(streamName)) err := coll.Find(bson.M{ @@ -78,11 +83,22 @@ func (s *MongoDbEventStore) FromVersion(streamName eventstore.StreamName, id str "version": bson.M{"$gte": version}, }). Sort("-version"). - All(&results) + All(&mongoEvents) + + var results []*eventstore.DomainMessage + for _, mongoEvent := range mongoEvents { + domainMessage, err := s.fromMongoEvent(mongoEvent) + if nil != err { + return nil, err + } + + results = append(results, domainMessage) + } return eventstore.NewEventStream(streamName, results), err } +// CountEventsFor counts events for an id on the specified stream func (s *MongoDbEventStore) CountEventsFor(streamName eventstore.StreamName, id string) (int, error) { return s.db.C(string(streamName)).Find(bson.M{"aggregate_id": string(streamName)}).Count() } @@ -98,27 +114,37 @@ func (s *MongoDbEventStore) createIndexes(c *mgo.Collection) error { return c.EnsureIndex(index) } -func (s *MongoDbEventStore) save(streamName eventstore.StreamName, event *eventstore.DomainMessage) error { - coll := s.db.C(string(streamName)) - err := s.createIndexes(coll) - if nil != err { - return err - } - +func (s *MongoDbEventStore) toMongoEvent(event *eventstore.DomainMessage) (*MongoEvent, error) { serializedPayload, err := json.Marshal(event.Payload) if nil != err { - return err + return nil, err } typeName := reflection.TypeOf(event.Payload) - - eventData := &EventData{ + return &MongoEvent{ ID: event.ID, Version: event.Version, Type: typeName.String(), Payload: string(serializedPayload), RecordedOn: event.RecordedOn, + }, nil +} + +func (s *MongoDbEventStore) fromMongoEvent(mongoEvent *MongoEvent) (*eventstore.DomainMessage, error) { + event, err := s.registry.Get(mongoEvent.Type) + if nil != err { + return nil, err + } + + err = json.Unmarshal([]byte(mongoEvent.Payload), event) + if nil != err { + return nil, err } - return coll.Insert(eventData) + return eventstore.NewDomainMessage( + mongoEvent.ID, + mongoEvent.Version, + event.(eventstore.DomainEvent), + mongoEvent.RecordedOn, + ), nil } From 3c21bc0c86e5735ce603cf8816e894cc79150c2d Mon Sep 17 00:00:00 2001 From: Italo Lelis de Vietro Date: Sun, 30 Oct 2016 12:23:57 +0100 Subject: [PATCH 25/74] Added go get --- .travis.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index cf063810..5a382f96 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,8 @@ go: - master install: - - go get github.com/onsi/ginkgo/ginkgo - - go get github.com/onsi/gomega + - go get -v -d + - go get github.com/onsi/ginkgo/ginkgo + - go get github.com/onsi/gomega script: ginkgo -r From 07650c169652de6fe57dfb169e2ad3be2e67662c Mon Sep 17 00:00:00 2001 From: Italo Lelis de Vietro Date: Sun, 30 Oct 2016 14:21:32 +0100 Subject: [PATCH 26/74] Added event bus and changed package structure --- aggregate_repository.go | 68 ++++++++++++++++++ .../aggregate_root.go => aggregate_root.go | 21 +++--- ...ate_root_test.go => aggregate_root_test.go | 2 +- cmd/goengine/main.go | 25 +++++-- cmd/goengine/model.go | 11 ++- .../domain_message.go => domain_message.go | 6 +- event_dispatcher_manager.go | 72 +++++++++++++++++++ event_map_dispatcher.go | 53 ++++++++++++++ eventstore/event_store.go => event_store.go | 2 +- ...event_store_test.go => event_store_test.go | 6 +- eventstore/event_stream.go => event_stream.go | 8 +-- events.go | 37 ++++++++++ eventsourcing/aggregate_repository.go | 54 -------------- eventsourcing/eventsourcing_suite_test.go | 13 ---- eventstore/mock_test.go | 17 ----- ...re_suite_test.go => goengine_suite_test.go | 4 +- inmemory/eventbus.go | 50 +++++++++++++ inmemory/eventstore.go | 24 +++---- inmemory/eventstore_test.go | 2 +- eventsourcing/mock_test.go => mock_test.go | 8 +-- mongodb/eventstore.go | 26 ++++--- {eventstore/snapshot => snapshot}/snapshot.go | 0 type_registry.go | 5 +- 23 files changed, 358 insertions(+), 156 deletions(-) create mode 100644 aggregate_repository.go rename eventsourcing/aggregate_root.go => aggregate_root.go (66%) rename eventsourcing/aggregate_root_test.go => aggregate_root_test.go (93%) rename eventstore/domain_message.go => domain_message.go (88%) create mode 100644 event_dispatcher_manager.go create mode 100644 event_map_dispatcher.go rename eventstore/event_store.go => event_store.go (93%) rename eventstore/event_store_test.go => event_store_test.go (93%) rename eventstore/event_stream.go => event_stream.go (70%) create mode 100644 events.go delete mode 100644 eventsourcing/aggregate_repository.go delete mode 100644 eventsourcing/eventsourcing_suite_test.go delete mode 100644 eventstore/mock_test.go rename eventstore/eventstore_suite_test.go => goengine_suite_test.go (71%) create mode 100644 inmemory/eventbus.go rename eventsourcing/mock_test.go => mock_test.go (78%) rename {eventstore/snapshot => snapshot}/snapshot.go (100%) diff --git a/aggregate_repository.go b/aggregate_repository.go new file mode 100644 index 00000000..f58a2b05 --- /dev/null +++ b/aggregate_repository.go @@ -0,0 +1,68 @@ +package goengine + +import ( + log "github.com/Sirupsen/logrus" +) + +type AggregateRepository interface { + Load(string, StreamName) (*EventStream, error) + Save(AggregateRoot, StreamName) error + Reconstitute(string, AggregateRoot, StreamName) error +} + +type PublisherRepository struct { + EventStore EventStore + EventBus VersionedEventPublisher +} + +func NewPublisherRepository(eventStore EventStore, eventBus VersionedEventPublisher) *PublisherRepository { + return &PublisherRepository{eventStore, eventBus} +} + +func (r *PublisherRepository) Load(id string, streamName StreamName) (*EventStream, error) { + log.Debugf("Loading events from %s stream for aggregate %s", streamName, id) + stream, err := r.EventStore.GetEventsFor(streamName, id) + if nil != err { + return nil, err + } + + return stream, nil +} + +func (r *PublisherRepository) Save(aggregateRoot AggregateRoot, streamName StreamName) error { + events := aggregateRoot.GetUncommittedEvents() + eventStream := NewEventStream(streamName, events) + log.Debugf("Saving %d events to %s stream", len(events), streamName) + err := r.EventStore.Append(eventStream) + if nil != err { + return err + } + + if nil == r.EventBus { + log.Debug("Event bus not detected, skiping publishing events") + return nil + } + + if err = r.EventBus.PublishEvents(events); err != nil { + return err + } + + return nil +} + +func (r *PublisherRepository) Reconstitute(id string, source AggregateRoot, streamName StreamName) error { + log.Debugf("Reconstituting aggregate %s from %s stream", id, streamName) + stream, err := r.Load(id, streamName) + if nil != err { + return err + } + events := stream.Events + + for _, event := range events { + source.Apply(event.Payload) + } + + source.SetVersion(events[len(events)-1].Version) + log.Debugf("Aggregate %s reconstituted", id) + return nil +} diff --git a/eventsourcing/aggregate_root.go b/aggregate_root.go similarity index 66% rename from eventsourcing/aggregate_root.go rename to aggregate_root.go index fe42fc0d..72dbebde 100644 --- a/eventsourcing/aggregate_root.go +++ b/aggregate_root.go @@ -1,10 +1,9 @@ -package eventsourcing +package goengine import ( "fmt" log "github.com/Sirupsen/logrus" - "github.com/hellofresh/goengine/eventstore" "github.com/hellofresh/goengine/reflection" "github.com/pborman/uuid" ) @@ -13,15 +12,15 @@ type AggregateRoot interface { GetID() string GetVersion() int SetVersion(int) - Apply(eventstore.DomainEvent) - GetUncommittedEvents() []*eventstore.DomainMessage + Apply(DomainEvent) + GetUncommittedEvents() []*DomainMessage } type AggregateRootBased struct { ID string version int source interface{} - uncommitedEvents []*eventstore.DomainMessage + uncommitedEvents []*DomainMessage } // NewAggregateRootBased constructor @@ -31,7 +30,7 @@ func NewAggregateRootBased(source interface{}) *AggregateRootBased { // NewEventSourceBasedWithID constructor func NewEventSourceBasedWithID(source interface{}, id string) *AggregateRootBased { - return &AggregateRootBased{id, 0, source, []*eventstore.DomainMessage{}} + return &AggregateRootBased{id, 0, source, []*DomainMessage{}} } func (r *AggregateRootBased) GetID() string { @@ -46,7 +45,7 @@ func (r *AggregateRootBased) SetVersion(version int) { r.version = version } -func (r *AggregateRootBased) GetUncommittedEvents() []*eventstore.DomainMessage { +func (r *AggregateRootBased) GetUncommittedEvents() []*DomainMessage { stream := r.uncommitedEvents r.uncommitedEvents = nil log.Debugf("%d Uncommited events cleaned", len(stream)) @@ -54,20 +53,20 @@ func (r *AggregateRootBased) GetUncommittedEvents() []*eventstore.DomainMessage return stream } -func (r *AggregateRootBased) Apply(event eventstore.DomainEvent) { +func (r *AggregateRootBased) Apply(event DomainEvent) { t := reflection.TypeOf(event) reflection.CallMethod(r.source, fmt.Sprintf("When%s", t.Name()), event) log.Debugf("Event %s applied", t.Name()) } -func (r *AggregateRootBased) RecordThat(event eventstore.DomainEvent) { +func (r *AggregateRootBased) RecordThat(event DomainEvent) { r.version++ r.Apply(event) r.Record(event) } -func (r *AggregateRootBased) Record(event eventstore.DomainEvent) { - message := eventstore.RecordNow(r.ID, r.version, event) +func (r *AggregateRootBased) Record(event DomainEvent) { + message := RecordNow(r.ID, r.version, event) r.uncommitedEvents = append(r.uncommitedEvents, message) log.Debug("Event recorded") } diff --git a/eventsourcing/aggregate_root_test.go b/aggregate_root_test.go similarity index 93% rename from eventsourcing/aggregate_root_test.go rename to aggregate_root_test.go index 8987cb32..e2feb49c 100644 --- a/eventsourcing/aggregate_root_test.go +++ b/aggregate_root_test.go @@ -1,4 +1,4 @@ -package eventsourcing_test +package goengine_test import ( . "github.com/onsi/ginkgo" diff --git a/cmd/goengine/main.go b/cmd/goengine/main.go index 68b10650..327bffa9 100644 --- a/cmd/goengine/main.go +++ b/cmd/goengine/main.go @@ -5,8 +5,7 @@ import ( log "github.com/Sirupsen/logrus" "github.com/hellofresh/goengine" - "github.com/hellofresh/goengine/eventsourcing" - "github.com/hellofresh/goengine/eventstore" + "github.com/hellofresh/goengine/inmemory" "github.com/hellofresh/goengine/mongodb" "gopkg.in/mgo.v2" @@ -14,7 +13,7 @@ import ( func main() { log.SetLevel(log.DebugLevel) - var streamName eventstore.StreamName = "test" + var streamName goengine.StreamName = "test" mongoDSN := os.Getenv("STORAGE_DSN") log.Infof("Connecting to the database %s", mongoDSN) @@ -32,11 +31,24 @@ func main() { registry.RegisterType(&RecipeCreated{}) registry.RegisterType(&RecipeRated{}) + log.Info("Setting up the event bus") + bus := inmemory.NewInMemoryEventBus() + log.Info("Setting up the event store") es := mongodb.NewEventStore(session, registry) log.Info("Creating a recipe") - repository := eventsourcing.NewPublisherRepository(es) + repository := goengine.NewPublisherRepository(es, bus) + + eventDispatcher := goengine.NewVersionedEventDispatchManager(bus, registry) + + eventDispatcher.RegisterEventHandler(&RecipeCreated{}, func(event *goengine.DomainMessage) error { + log.Debug("Event received") + return nil + }) + + stopChannel := make(chan bool) + go eventDispatcher.Listen(stopChannel, false) log.Info("Creating a recipe") aggregateRoot := CreateScenario(streamName) @@ -48,10 +60,13 @@ func main() { log.Panic(err) } + log.Println("Stop channel") + stopChannel <- true + log.Info(history) } -func CreateScenario(streamName eventstore.StreamName) *Recipe { +func CreateScenario(streamName goengine.StreamName) *Recipe { recipe := NewRecipe("Test Recipe") recipe.Rate(4) return recipe diff --git a/cmd/goengine/model.go b/cmd/goengine/model.go index 736a6c37..a03d6465 100644 --- a/cmd/goengine/model.go +++ b/cmd/goengine/model.go @@ -3,8 +3,7 @@ package main import ( "time" - "github.com/hellofresh/goengine/eventsourcing" - "github.com/hellofresh/goengine/eventstore" + "github.com/hellofresh/goengine" ) type RecipeCreated struct { @@ -26,22 +25,22 @@ func (e RecipeRated) OcurredOn() time.Time { } type Recipe struct { - *eventsourcing.AggregateRootBased + *goengine.AggregateRootBased Name string Rating int } func NewRecipe(name string) *Recipe { recipe := new(Recipe) - recipe.AggregateRootBased = eventsourcing.NewAggregateRootBased(recipe) + recipe.AggregateRootBased = goengine.NewAggregateRootBased(recipe) recipe.RecordThat(&RecipeCreated{time.Now(), name}) return recipe } -func NewRecipeFromHisotry(id string, streamName eventstore.StreamName, repo eventsourcing.AggregateRepository) (*Recipe, error) { +func NewRecipeFromHisotry(id string, streamName goengine.StreamName, repo goengine.AggregateRepository) (*Recipe, error) { recipe := new(Recipe) - recipe.AggregateRootBased = eventsourcing.NewEventSourceBasedWithID(recipe, id) + recipe.AggregateRootBased = goengine.NewEventSourceBasedWithID(recipe, id) err := repo.Reconstitute(id, recipe, streamName) return recipe, err diff --git a/eventstore/domain_message.go b/domain_message.go similarity index 88% rename from eventstore/domain_message.go rename to domain_message.go index e8713243..4eb49a9c 100644 --- a/eventstore/domain_message.go +++ b/domain_message.go @@ -1,7 +1,11 @@ -package eventstore +package goengine import "time" +type DomainEvent interface { + OcurredOn() time.Time +} + type DomainMessage struct { ID string `json:"aggregate_id,omitempty"` Version int `json:"version"` diff --git a/event_dispatcher_manager.go b/event_dispatcher_manager.go new file mode 100644 index 00000000..8253ddf9 --- /dev/null +++ b/event_dispatcher_manager.go @@ -0,0 +1,72 @@ +package goengine + +import ( + log "github.com/Sirupsen/logrus" +) + +// VersionedEventDispatchManager is responsible for coordinating receiving messages from event receivers and dispatching them to the event dispatcher. +type VersionedEventDispatchManager struct { + versionedEventDispatcher *MapBasedVersionedEventDispatcher + typeRegistry TypeRegistry + receiver VersionedEventReceiver +} + +// NewVersionedEventDispatchManager is a constructor for the VersionedEventDispatchManager +func NewVersionedEventDispatchManager(receiver VersionedEventReceiver, registry TypeRegistry) *VersionedEventDispatchManager { + return &VersionedEventDispatchManager{NewVersionedEventDispatcher(), registry, receiver} +} + +// RegisterEventHandler allows a caller to register an event handler given an event of the specified type being received +func (m *VersionedEventDispatchManager) RegisterEventHandler(event interface{}, handler VersionedEventHandler) { + m.typeRegistry.RegisterType(event) + m.versionedEventDispatcher.RegisterEventHandler(event, handler) +} + +// RegisterGlobalHandler allows a caller to register a wildcard event handler call on any event received +func (m *VersionedEventDispatchManager) RegisterGlobalHandler(handler VersionedEventHandler) { + m.versionedEventDispatcher.RegisterGlobalHandler(handler) +} + +// Listen starts a listen loop processing channels related to new incoming events, errors and stop listening requests +func (m *VersionedEventDispatchManager) Listen(stop <-chan bool, exclusive bool) error { + // Create communication channels + // + // for closing the queue listener, + closeChannel := make(chan chan error) + // receiving errors from the listener thread (go routine) + errorChannel := make(chan error) + // and receiving events from the queue + receiveEventChannel := make(chan VersionedEventTransactedAccept) + + // Start receiving events by passing these channels to the worker thread (go routine) + options := VersionedEventReceiverOptions{m.typeRegistry, closeChannel, errorChannel, receiveEventChannel, exclusive} + if err := m.receiver.ReceiveEvents(options); err != nil { + return err + } + + for { + // Wait on multiple channels using the select control flow. + select { + // Version event received channel receives a result with a channel to respond to, signifying successful processing of the message. + // This should eventually call an event handler. See cqrs.NewVersionedEventDispatcher() + case event := <-receiveEventChannel: + log.Debugf("EventDispatchManager.DispatchEvent: %s", event.Event) + if err := m.versionedEventDispatcher.DispatchEvent(event.Event); err != nil { + log.Println("Error dispatching event: ", err) + } + + event.ProcessedSuccessfully <- true + log.Debug("EventDispatchManager.DispatchSuccessful") + case <-stop: + log.Debug("EventDispatchManager.Stopping") + closeSignal := make(chan error) + closeChannel <- closeSignal + defer log.Debug("EventDispatchManager.Stopped") + return <-closeSignal + // Receiving on this channel signifys an error has occured worker processor side + case err := <-errorChannel: + log.Debugf("EventDispatchManager.ErrorReceived: %s", err) + return err + } + } +} diff --git a/event_map_dispatcher.go b/event_map_dispatcher.go new file mode 100644 index 00000000..4c8f4cba --- /dev/null +++ b/event_map_dispatcher.go @@ -0,0 +1,53 @@ +package goengine + +import ( + "reflect" +) + +// MapBasedVersionedEventDispatcher is a simple implementation of the versioned event dispatcher. Using a map it registered event handlers to event types +type MapBasedVersionedEventDispatcher struct { + registry map[reflect.Type][]VersionedEventHandler + globalHandlers []VersionedEventHandler +} + +// NewVersionedEventDispatcher is a constructor for the MapBasedVersionedEventDispatcher +func NewVersionedEventDispatcher() *MapBasedVersionedEventDispatcher { + registry := make(map[reflect.Type][]VersionedEventHandler) + return &MapBasedVersionedEventDispatcher{registry, []VersionedEventHandler{}} +} + +// RegisterEventHandler allows a caller to register an event handler given an event of the specified type being received +func (m *MapBasedVersionedEventDispatcher) RegisterEventHandler(event interface{}, handler VersionedEventHandler) { + eventType := reflect.TypeOf(event) + handlers, ok := m.registry[eventType] + if ok { + m.registry[eventType] = append(handlers, handler) + } else { + m.registry[eventType] = []VersionedEventHandler{handler} + } +} + +// RegisterGlobalHandler allows a caller to register a wildcard event handler call on any event received +func (m *MapBasedVersionedEventDispatcher) RegisterGlobalHandler(handler VersionedEventHandler) { + m.globalHandlers = append(m.globalHandlers, handler) +} + +// DispatchEvent executes all event handlers registered for the given event type +func (m *MapBasedVersionedEventDispatcher) DispatchEvent(event *DomainMessage) error { + eventType := reflect.TypeOf(event.Payload) + if handlers, ok := m.registry[eventType]; ok { + for _, handler := range handlers { + if err := handler(event); err != nil { + return err + } + } + } + + for _, handler := range m.globalHandlers { + if err := handler(event); err != nil { + return err + } + } + + return nil +} diff --git a/eventstore/event_store.go b/event_store.go similarity index 93% rename from eventstore/event_store.go rename to event_store.go index 37bdb122..84920026 100644 --- a/eventstore/event_store.go +++ b/event_store.go @@ -1,4 +1,4 @@ -package eventstore +package goengine type EventStore interface { Append(events *EventStream) error diff --git a/eventstore/event_store_test.go b/event_store_test.go similarity index 93% rename from eventstore/event_store_test.go rename to event_store_test.go index 0bc33f0e..4ff0a205 100644 --- a/eventstore/event_store_test.go +++ b/event_store_test.go @@ -1,7 +1,7 @@ -package eventstore_test +package goengine_test import ( - . "github.com/hellofresh/goengine/eventstore" + . "github.com/hellofresh/goengine" "github.com/hellofresh/goengine/inmemory" . "github.com/onsi/ginkgo" @@ -23,7 +23,7 @@ var _ = Describe("A Event Store", func() { }) JustBeforeEach(func() { - var events []*DomainMessage + var events []*goengine.DomainMessage events = append(events, RecordNow(aggregateId, 0, NewSomethingHappened())) events = append(events, RecordNow(aggregateId, 1, NewSomethingHappened())) diff --git a/eventstore/event_stream.go b/event_stream.go similarity index 70% rename from eventstore/event_stream.go rename to event_stream.go index edf61341..1383c10d 100644 --- a/eventstore/event_stream.go +++ b/event_stream.go @@ -1,10 +1,4 @@ -package eventstore - -import "time" - -type DomainEvent interface { - OcurredOn() time.Time -} +package goengine type StreamName string diff --git a/events.go b/events.go new file mode 100644 index 00000000..e154a156 --- /dev/null +++ b/events.go @@ -0,0 +1,37 @@ +package goengine + +// VersionedEventPublisher is responsible for publishing events that have been saved to the event store\repository +type VersionedEventPublisher interface { + PublishEvents([]*DomainMessage) error +} + +// VersionedEventReceiver is responsible for receiving globally published events +type VersionedEventReceiver interface { + ReceiveEvents(VersionedEventReceiverOptions) error +} + +// VersionedEventTransactedAccept is the message routed from an event receiver to the event manager. +// Sometimes event receivers designed with reliable delivery require acknowledgements after a message has been received. The success channel here allows for such acknowledgements +type VersionedEventTransactedAccept struct { + Event *DomainMessage + ProcessedSuccessfully chan bool +} + +// VersionedEventReceiverOptions is an initalization structure to communicate to and from an event receiver go routine +type VersionedEventReceiverOptions struct { + TypeRegistry TypeRegistry + Close chan chan error + Error chan error + ReceiveEvent chan VersionedEventTransactedAccept + Exclusive bool +} + +// VersionedEventHandler is a function that takes a versioned event +type VersionedEventHandler func(*DomainMessage) error + +// VersionedEventDispatcher is responsible for routing events from the event manager to call handlers responsible for processing received events +type VersionedEventDispatcher interface { + DispatchEvent(*DomainMessage) error + RegisterEventHandler(event interface{}, handler VersionedEventHandler) + RegisterGlobalHandler(handler VersionedEventHandler) +} diff --git a/eventsourcing/aggregate_repository.go b/eventsourcing/aggregate_repository.go deleted file mode 100644 index 4cae8d8f..00000000 --- a/eventsourcing/aggregate_repository.go +++ /dev/null @@ -1,54 +0,0 @@ -package eventsourcing - -import ( - log "github.com/Sirupsen/logrus" - "github.com/hellofresh/goengine/eventstore" -) - -type AggregateRepository interface { - Load(string, eventstore.StreamName) (*eventstore.EventStream, error) - Save(AggregateRoot, eventstore.StreamName) - Reconstitute(string, AggregateRoot, eventstore.StreamName) error -} - -type PublisherRepository struct { - eventStore eventstore.EventStore -} - -func NewPublisherRepository(eventStore eventstore.EventStore) *PublisherRepository { - return &PublisherRepository{eventStore} -} - -func (r *PublisherRepository) Load(id string, streamName eventstore.StreamName) (*eventstore.EventStream, error) { - log.Debugf("Loading events from %s stream for aggregate %s", streamName, id) - stream, err := r.eventStore.GetEventsFor(streamName, id) - if nil != err { - return nil, err - } - - return stream, nil -} - -func (r *PublisherRepository) Save(aggregateRoot AggregateRoot, streamName eventstore.StreamName) { - events := aggregateRoot.GetUncommittedEvents() - eventStream := eventstore.NewEventStream(streamName, events) - log.Debugf("Saving %d events to %s stream", len(events), streamName) - r.eventStore.Append(eventStream) -} - -func (r *PublisherRepository) Reconstitute(id string, source AggregateRoot, streamName eventstore.StreamName) error { - log.Debugf("Reconstituting aggregate %s from %s stream", id, streamName) - stream, err := r.Load(id, streamName) - if nil != err { - return err - } - events := stream.Events - - for _, event := range events { - source.Apply(event.Payload) - } - - source.SetVersion(events[len(events)-1].Version) - log.Debugf("Aggregate %s reconstituted", id) - return nil -} diff --git a/eventsourcing/eventsourcing_suite_test.go b/eventsourcing/eventsourcing_suite_test.go deleted file mode 100644 index c4b6882e..00000000 --- a/eventsourcing/eventsourcing_suite_test.go +++ /dev/null @@ -1,13 +0,0 @@ -package eventsourcing_test - -import ( - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - - "testing" -) - -func TestGoengine(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Event Sourcing Suite") -} diff --git a/eventstore/mock_test.go b/eventstore/mock_test.go deleted file mode 100644 index e1aefbdc..00000000 --- a/eventstore/mock_test.go +++ /dev/null @@ -1,17 +0,0 @@ -package eventstore_test - -import ( - "time" -) - -type SomethingHappened struct { - ocurredOn time.Time -} - -func NewSomethingHappened() *SomethingHappened { - return &SomethingHappened{time.Now()} -} - -func (e *SomethingHappened) OcurredOn() time.Time { - return e.ocurredOn -} diff --git a/eventstore/eventstore_suite_test.go b/goengine_suite_test.go similarity index 71% rename from eventstore/eventstore_suite_test.go rename to goengine_suite_test.go index 649d0228..e1155648 100644 --- a/eventstore/eventstore_suite_test.go +++ b/goengine_suite_test.go @@ -1,4 +1,4 @@ -package eventstore_test +package goengine_test import ( . "github.com/onsi/ginkgo" @@ -9,5 +9,5 @@ import ( func TestGoengine(t *testing.T) { RegisterFailHandler(Fail) - RunSpecs(t, "Event Store Suite") + RunSpecs(t, "GO Engine Suite") } diff --git a/inmemory/eventbus.go b/inmemory/eventbus.go new file mode 100644 index 00000000..ac9dae50 --- /dev/null +++ b/inmemory/eventbus.go @@ -0,0 +1,50 @@ +package inmemory + +import ( + "github.com/hellofresh/goengine" +) + +// InMemoryEventBus provides an inmemory implementation of the VersionedEventPublisher VersionedEventReceiver interfaces +type InMemoryEventBus struct { + publishedEventsChannel chan *goengine.DomainMessage + startReceiving bool +} + +// NewInMemoryEventBus constructor +func NewInMemoryEventBus() *InMemoryEventBus { + publishedEventsChannel := make(chan *goengine.DomainMessage, 0) + return &InMemoryEventBus{publishedEventsChannel, false} +} + +// PublishEvents publishes events to the event bus +func (bus *InMemoryEventBus) PublishEvents(events []*goengine.DomainMessage) error { + if !bus.startReceiving { + return nil + } + + for _, event := range events { + bus.publishedEventsChannel <- event + } + + return nil +} + +// ReceiveEvents starts a go routine that monitors incoming events and routes them to a receiver channel specified within the options +func (bus *InMemoryEventBus) ReceiveEvents(options goengine.VersionedEventReceiverOptions) error { + bus.startReceiving = true + + go func() { + for { + select { + case ch := <-options.Close: + ch <- nil + case versionedEvent := <-bus.publishedEventsChannel: + ackCh := make(chan bool) + options.ReceiveEvent <- goengine.VersionedEventTransactedAccept{versionedEvent, ackCh} + <-ackCh + } + } + }() + + return nil +} diff --git a/inmemory/eventstore.go b/inmemory/eventstore.go index b0a85427..a1184a1c 100644 --- a/inmemory/eventstore.go +++ b/inmemory/eventstore.go @@ -1,16 +1,16 @@ package inmemory -import "github.com/hellofresh/goengine/eventstore" +import "github.com/hellofresh/goengine" type InMemoryEventStore struct { - events map[eventstore.StreamName]map[string][]*eventstore.DomainMessage + events map[goengine.StreamName]map[string][]*goengine.DomainMessage } func NewEventStore() *InMemoryEventStore { - return &InMemoryEventStore{make(map[eventstore.StreamName]map[string][]*eventstore.DomainMessage)} + return &InMemoryEventStore{make(map[goengine.StreamName]map[string][]*goengine.DomainMessage)} } -func (s *InMemoryEventStore) Append(events *eventstore.EventStream) error { +func (s *InMemoryEventStore) Append(events *goengine.EventStream) error { name := events.Name for _, event := range events.Events { err := s.save(name, event) @@ -22,13 +22,13 @@ func (s *InMemoryEventStore) Append(events *eventstore.EventStream) error { return nil } -func (s *InMemoryEventStore) GetEventsFor(streamName eventstore.StreamName, id string) (*eventstore.EventStream, error) { - return eventstore.NewEventStream(streamName, s.events[streamName][id]), nil +func (s *InMemoryEventStore) GetEventsFor(streamName goengine.StreamName, id string) (*goengine.EventStream, error) { + return goengine.NewEventStream(streamName, s.events[streamName][id]), nil } -func (s *InMemoryEventStore) FromVersion(streamName eventstore.StreamName, id string, version int) (*eventstore.EventStream, error) { +func (s *InMemoryEventStore) FromVersion(streamName goengine.StreamName, id string, version int) (*goengine.EventStream, error) { events, _ := s.GetEventsFor(streamName, id) - var filtered []*eventstore.DomainMessage + var filtered []*goengine.DomainMessage for _, event := range events.Events { if event.Version >= version { @@ -36,20 +36,20 @@ func (s *InMemoryEventStore) FromVersion(streamName eventstore.StreamName, id st } } - return eventstore.NewEventStream(streamName, filtered), nil + return goengine.NewEventStream(streamName, filtered), nil } -func (s *InMemoryEventStore) CountEventsFor(streamName eventstore.StreamName, id string) (int, error) { +func (s *InMemoryEventStore) CountEventsFor(streamName goengine.StreamName, id string) (int, error) { stream, _ := s.GetEventsFor(streamName, id) return len(stream.Events), nil } -func (s *InMemoryEventStore) save(streamName eventstore.StreamName, event *eventstore.DomainMessage) error { +func (s *InMemoryEventStore) save(streamName goengine.StreamName, event *goengine.DomainMessage) error { id := event.ID events, exists := s.events[streamName][id] if !exists { - s.events[streamName] = make(map[string][]*eventstore.DomainMessage) + s.events[streamName] = make(map[string][]*goengine.DomainMessage) } s.events[streamName][id] = append(events, event) diff --git a/inmemory/eventstore_test.go b/inmemory/eventstore_test.go index 55280b61..07dda2a9 100644 --- a/inmemory/eventstore_test.go +++ b/inmemory/eventstore_test.go @@ -1,7 +1,7 @@ package inmemory_test import ( - . "github.com/hellofresh/goengine/eventstore" + . "github.com/hellofresh/goengine" . "github.com/hellofresh/goengine/inmemory" . "github.com/onsi/ginkgo" diff --git a/eventsourcing/mock_test.go b/mock_test.go similarity index 78% rename from eventsourcing/mock_test.go rename to mock_test.go index 5f68fe55..1d8b3e44 100644 --- a/eventsourcing/mock_test.go +++ b/mock_test.go @@ -1,9 +1,7 @@ -package eventsourcing_test +package goengine_test import ( "time" - - "github.com/hellofresh/goengine/eventsourcing" ) type RecipeCreated struct { @@ -24,14 +22,14 @@ func (e RecipeRated) OcurredOn() time.Time { } type Recipe struct { - *eventsourcing.AggregateRootBased + *AggregateRootBased Name string Rating int } func NewRecipe(name string) *Recipe { recipe := new(Recipe) - recipe.AggregateRootBased = eventsourcing.NewAggregateRootBased(recipe) + recipe.AggregateRootBased = NewAggregateRootBased(recipe) recipe.RecordThat(RecipeCreated{time.Now()}) return recipe diff --git a/mongodb/eventstore.go b/mongodb/eventstore.go index 0057633f..974e28e5 100644 --- a/mongodb/eventstore.go +++ b/mongodb/eventstore.go @@ -5,9 +5,7 @@ import ( "time" "github.com/hellofresh/goengine" - "github.com/hellofresh/goengine/eventstore" "github.com/hellofresh/goengine/reflection" - "gopkg.in/mgo.v2" "gopkg.in/mgo.v2/bson" ) @@ -34,7 +32,7 @@ func NewEventStore(conn *mgo.Session, r goengine.TypeRegistry) *MongoDbEventStor } // Append adds an event to the event store -func (s *MongoDbEventStore) Append(events *eventstore.EventStream) error { +func (s *MongoDbEventStore) Append(events *goengine.EventStream) error { streamName := string(events.Name) for _, event := range events.Events { mongoEvent, err := s.toMongoEvent(event) @@ -55,12 +53,12 @@ func (s *MongoDbEventStore) Append(events *eventstore.EventStream) error { } // GetEventsFor gets events for an id on the specified stream -func (s *MongoDbEventStore) GetEventsFor(streamName eventstore.StreamName, id string) (*eventstore.EventStream, error) { +func (s *MongoDbEventStore) GetEventsFor(streamName goengine.StreamName, id string) (*goengine.EventStream, error) { var mongoEvents []*MongoEvent coll := s.db.C(string(streamName)) err := coll.Find(bson.M{"aggregate_id": id}).All(&mongoEvents) - var results []*eventstore.DomainMessage + var results []*goengine.DomainMessage for _, mongoEvent := range mongoEvents { domainMessage, err := s.fromMongoEvent(mongoEvent) if nil != err { @@ -70,11 +68,11 @@ func (s *MongoDbEventStore) GetEventsFor(streamName eventstore.StreamName, id st results = append(results, domainMessage) } - return eventstore.NewEventStream(streamName, results), err + return goengine.NewEventStream(streamName, results), err } // FromVersion gets events for an id and version on the specified stream -func (s *MongoDbEventStore) FromVersion(streamName eventstore.StreamName, id string, version int) (*eventstore.EventStream, error) { +func (s *MongoDbEventStore) FromVersion(streamName goengine.StreamName, id string, version int) (*goengine.EventStream, error) { var mongoEvents []*MongoEvent coll := s.db.C(string(streamName)) @@ -85,7 +83,7 @@ func (s *MongoDbEventStore) FromVersion(streamName eventstore.StreamName, id str Sort("-version"). All(&mongoEvents) - var results []*eventstore.DomainMessage + var results []*goengine.DomainMessage for _, mongoEvent := range mongoEvents { domainMessage, err := s.fromMongoEvent(mongoEvent) if nil != err { @@ -95,11 +93,11 @@ func (s *MongoDbEventStore) FromVersion(streamName eventstore.StreamName, id str results = append(results, domainMessage) } - return eventstore.NewEventStream(streamName, results), err + return goengine.NewEventStream(streamName, results), err } // CountEventsFor counts events for an id on the specified stream -func (s *MongoDbEventStore) CountEventsFor(streamName eventstore.StreamName, id string) (int, error) { +func (s *MongoDbEventStore) CountEventsFor(streamName goengine.StreamName, id string) (int, error) { return s.db.C(string(streamName)).Find(bson.M{"aggregate_id": string(streamName)}).Count() } @@ -114,7 +112,7 @@ func (s *MongoDbEventStore) createIndexes(c *mgo.Collection) error { return c.EnsureIndex(index) } -func (s *MongoDbEventStore) toMongoEvent(event *eventstore.DomainMessage) (*MongoEvent, error) { +func (s *MongoDbEventStore) toMongoEvent(event *goengine.DomainMessage) (*MongoEvent, error) { serializedPayload, err := json.Marshal(event.Payload) if nil != err { return nil, err @@ -130,7 +128,7 @@ func (s *MongoDbEventStore) toMongoEvent(event *eventstore.DomainMessage) (*Mong }, nil } -func (s *MongoDbEventStore) fromMongoEvent(mongoEvent *MongoEvent) (*eventstore.DomainMessage, error) { +func (s *MongoDbEventStore) fromMongoEvent(mongoEvent *MongoEvent) (*goengine.DomainMessage, error) { event, err := s.registry.Get(mongoEvent.Type) if nil != err { return nil, err @@ -141,10 +139,10 @@ func (s *MongoDbEventStore) fromMongoEvent(mongoEvent *MongoEvent) (*eventstore. return nil, err } - return eventstore.NewDomainMessage( + return goengine.NewDomainMessage( mongoEvent.ID, mongoEvent.Version, - event.(eventstore.DomainEvent), + event.(goengine.DomainEvent), mongoEvent.RecordedOn, ), nil } diff --git a/eventstore/snapshot/snapshot.go b/snapshot/snapshot.go similarity index 100% rename from eventstore/snapshot/snapshot.go rename to snapshot/snapshot.go diff --git a/type_registry.go b/type_registry.go index 023c98c7..18876898 100644 --- a/type_registry.go +++ b/type_registry.go @@ -5,7 +5,6 @@ import ( log "github.com/Sirupsen/logrus" "github.com/hellofresh/goengine/errors" - "github.com/hellofresh/goengine/eventsourcing" "github.com/hellofresh/goengine/reflection" ) @@ -15,7 +14,7 @@ import ( // know how to create a type for that string type TypeRegistry interface { GetTypeByName(string) (reflect.Type, bool) - RegisterAggregate(eventsourcing.AggregateRoot, ...interface{}) + RegisterAggregate(AggregateRoot, ...interface{}) RegisterEvents(...interface{}) RegisterType(interface{}) Get(string) (interface{}, error) @@ -39,7 +38,7 @@ func (r *InMemoryTypeRegistry) RegisterType(i interface{}) { log.Debugf("Type %s was registered", rawType.String()) } -func (r *InMemoryTypeRegistry) RegisterAggregate(aggregate eventsourcing.AggregateRoot, events ...interface{}) { +func (r *InMemoryTypeRegistry) RegisterAggregate(aggregate AggregateRoot, events ...interface{}) { r.RegisterType(aggregate) log.Debugf("Aggregate %s was registered", aggregate.GetID()) From b8c7183d9afd2c636637c52967684dd2c99003dc Mon Sep 17 00:00:00 2001 From: Italo Lelis de Vietro Date: Sun, 30 Oct 2016 14:27:46 +0100 Subject: [PATCH 27/74] Fixed tests --- event_dispatcher_manager.go | 2 +- event_store_test.go | 2 +- mock_test.go | 14 ++++++++++++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/event_dispatcher_manager.go b/event_dispatcher_manager.go index 8253ddf9..e85d7e04 100644 --- a/event_dispatcher_manager.go +++ b/event_dispatcher_manager.go @@ -48,7 +48,7 @@ func (m *VersionedEventDispatchManager) Listen(stop <-chan bool, exclusive bool) // Wait on multiple channels using the select control flow. select { // Version event received channel receives a result with a channel to respond to, signifying successful processing of the message. - // This should eventually call an event handler. See cqrs.NewVersionedEventDispatcher() + // This should eventually call an event handler. See NewVersionedEventDispatcher() case event := <-receiveEventChannel: log.Debugf("EventDispatchManager.DispatchEvent: %s", event.Event) if err := m.versionedEventDispatcher.DispatchEvent(event.Event); err != nil { diff --git a/event_store_test.go b/event_store_test.go index 4ff0a205..decb9366 100644 --- a/event_store_test.go +++ b/event_store_test.go @@ -23,7 +23,7 @@ var _ = Describe("A Event Store", func() { }) JustBeforeEach(func() { - var events []*goengine.DomainMessage + var events []*DomainMessage events = append(events, RecordNow(aggregateId, 0, NewSomethingHappened())) events = append(events, RecordNow(aggregateId, 1, NewSomethingHappened())) diff --git a/mock_test.go b/mock_test.go index 1d8b3e44..c015d226 100644 --- a/mock_test.go +++ b/mock_test.go @@ -2,8 +2,22 @@ package goengine_test import ( "time" + + . "github.com/hellofresh/goengine" ) +type SomethingHappened struct { + ocurredOn time.Time +} + +func NewSomethingHappened() SomethingHappened { + return SomethingHappened{time.Now()} +} + +func (e SomethingHappened) OcurredOn() time.Time { + return e.ocurredOn +} + type RecipeCreated struct { ocurredOn time.Time } From de8b0bdc661bcc7dfcebb5305c2fd3fd0adacf7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Dtalo=20Lelis=20de=20Vietro?= Date: Sat, 31 Dec 2016 16:01:02 +0100 Subject: [PATCH 28/74] Fixed bug when saving events --- mongodb/eventstore.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mongodb/eventstore.go b/mongodb/eventstore.go index 974e28e5..54555396 100644 --- a/mongodb/eventstore.go +++ b/mongodb/eventstore.go @@ -46,7 +46,10 @@ func (s *MongoDbEventStore) Append(events *goengine.EventStream) error { return err } - return coll.Insert(mongoEvent) + err = coll.Insert(mongoEvent) + if nil != err { + return err + } } return nil From dc0acb46730f3e4baf26fab012892237ca414104 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Dtalo=20Lelis=20de=20Vietro?= Date: Sun, 1 Jan 2017 18:03:28 +0100 Subject: [PATCH 29/74] Fixed typo --- domain_message.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain_message.go b/domain_message.go index 4eb49a9c..6eb0e278 100644 --- a/domain_message.go +++ b/domain_message.go @@ -3,7 +3,7 @@ package goengine import "time" type DomainEvent interface { - OcurredOn() time.Time + OccurredOn() time.Time } type DomainMessage struct { From 49ab8b5db33ae1dc918eb15ef32449d1f726a8fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Dtalo=20Lelis=20de=20Vietro?= Date: Sun, 1 Jan 2017 18:07:32 +0100 Subject: [PATCH 30/74] Update mock_test.go --- mock_test.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/mock_test.go b/mock_test.go index c015d226..435c454d 100644 --- a/mock_test.go +++ b/mock_test.go @@ -7,32 +7,32 @@ import ( ) type SomethingHappened struct { - ocurredOn time.Time + occurredOn time.Time } func NewSomethingHappened() SomethingHappened { return SomethingHappened{time.Now()} } -func (e SomethingHappened) OcurredOn() time.Time { - return e.ocurredOn +func (e SomethingHappened) OccurredOn() time.Time { + return e.occurredOn } type RecipeCreated struct { - ocurredOn time.Time + occurredOn time.Time } -func (e RecipeCreated) OcurredOn() time.Time { - return e.ocurredOn +func (e RecipeCreated) OccurredOn() time.Time { + return e.occurredOn } type RecipeRated struct { - ocurredOn time.Time + occurredOn time.Time Rating int } -func (e RecipeRated) OcurredOn() time.Time { - return e.ocurredOn +func (e RecipeRated) OccurredOn() time.Time { + return e.occurredOn } type Recipe struct { From 4e9bc1d8de43b438217fc80ad64751976dd481d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Dtalo=20Lelis=20de=20Vietro?= Date: Sun, 1 Jan 2017 18:34:48 +0100 Subject: [PATCH 31/74] Fi --- inmemory/mock_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/inmemory/mock_test.go b/inmemory/mock_test.go index c3c5f6fe..ede0fe0b 100644 --- a/inmemory/mock_test.go +++ b/inmemory/mock_test.go @@ -5,13 +5,13 @@ import ( ) type SomethingHappened struct { - ocurredOn time.Time + occurredOn time.Time } func NewSomethingHappened() SomethingHappened { return SomethingHappened{time.Now()} } -func (e SomethingHappened) OcurredOn() time.Time { - return e.ocurredOn +func (e SomethingHappened) OccurredOn() time.Time { + return e.occurredOn } From cc12f9c99729c22c629097d4483d1bf7ea253058 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toma=C5=BE=20=C5=BDinko?= Date: Wed, 8 Mar 2017 14:59:47 +0100 Subject: [PATCH 32/74] Adds debug line to aggreagte_root --- aggregate_root.go | 1 + 1 file changed, 1 insertion(+) diff --git a/aggregate_root.go b/aggregate_root.go index 72dbebde..3e65d211 100644 --- a/aggregate_root.go +++ b/aggregate_root.go @@ -55,6 +55,7 @@ func (r *AggregateRootBased) GetUncommittedEvents() []*DomainMessage { func (r *AggregateRootBased) Apply(event DomainEvent) { t := reflection.TypeOf(event) + log.Debugf("source: %v; MethodName: %+v; event: %+v", r.source, fmt.Sprintf("When%s", t.Name()), event) reflection.CallMethod(r.source, fmt.Sprintf("When%s", t.Name()), event) log.Debugf("Event %s applied", t.Name()) } From d3c5700e5ef536c25b29b84926a220f5a2a9859d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toma=C5=BE=20=C5=BDinko?= Date: Wed, 8 Mar 2017 15:01:28 +0100 Subject: [PATCH 33/74] Update aggregate_root.go --- aggregate_root.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aggregate_root.go b/aggregate_root.go index 3e65d211..f6ad907f 100644 --- a/aggregate_root.go +++ b/aggregate_root.go @@ -55,7 +55,7 @@ func (r *AggregateRootBased) GetUncommittedEvents() []*DomainMessage { func (r *AggregateRootBased) Apply(event DomainEvent) { t := reflection.TypeOf(event) - log.Debugf("source: %v; MethodName: %+v; event: %+v", r.source, fmt.Sprintf("When%s", t.Name()), event) + log.Debugf("source: %+v; MethodName: %+v; event: %+v", r.source, fmt.Sprintf("When%s", t.Name()), event) reflection.CallMethod(r.source, fmt.Sprintf("When%s", t.Name()), event) log.Debugf("Event %s applied", t.Name()) } From a5aa37c0e1ddb5d788fa19e7cde777c7b7c9947f Mon Sep 17 00:00:00 2001 From: Kieran Date: Wed, 8 Mar 2017 15:04:55 +0100 Subject: [PATCH 34/74] Added Go 1.8 to Travis --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 5a382f96..fd7d3e43 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,7 @@ services: go: - 1.6 - 1.7 + - 1.8 - master install: From a06f75c27f3c45e997cf172421946af5e6dce8af Mon Sep 17 00:00:00 2001 From: Italo Lelis de Vietro Date: Tue, 14 Mar 2017 12:02:07 +0100 Subject: [PATCH 35/74] Initial rabbit event dispatcher --- cmd/goengine/main.go | 14 +-- docker-compose.yml | 6 + event_dispatcher_manager.go | 6 +- rabbit/eventbus.go | 245 ++++++++++++++++++++++++++++++++++++ rabbit/retry.go | 30 +++++ 5 files changed, 290 insertions(+), 11 deletions(-) create mode 100644 rabbit/eventbus.go create mode 100644 rabbit/retry.go diff --git a/cmd/goengine/main.go b/cmd/goengine/main.go index 327bffa9..51b52b90 100644 --- a/cmd/goengine/main.go +++ b/cmd/goengine/main.go @@ -5,8 +5,8 @@ import ( log "github.com/Sirupsen/logrus" "github.com/hellofresh/goengine" - "github.com/hellofresh/goengine/inmemory" "github.com/hellofresh/goengine/mongodb" + "github.com/hellofresh/goengine/rabbit" "gopkg.in/mgo.v2" ) @@ -32,16 +32,13 @@ func main() { registry.RegisterType(&RecipeRated{}) log.Info("Setting up the event bus") - bus := inmemory.NewInMemoryEventBus() + // bus := inmemory.NewInMemoryEventBus() + bus := rabbit.NewEventBus(os.Getenv("BROKER_DSN"), "events", "events") log.Info("Setting up the event store") es := mongodb.NewEventStore(session, registry) - log.Info("Creating a recipe") - repository := goengine.NewPublisherRepository(es, bus) - eventDispatcher := goengine.NewVersionedEventDispatchManager(bus, registry) - eventDispatcher.RegisterEventHandler(&RecipeCreated{}, func(event *goengine.DomainMessage) error { log.Debug("Event received") return nil @@ -53,17 +50,16 @@ func main() { log.Info("Creating a recipe") aggregateRoot := CreateScenario(streamName) + repository := goengine.NewPublisherRepository(es, bus) repository.Save(aggregateRoot, streamName) - history, err := NewRecipeFromHisotry(aggregateRoot.ID, streamName, repository) + _, err = NewRecipeFromHisotry(aggregateRoot.ID, streamName, repository) if err != nil { log.Panic(err) } log.Println("Stop channel") stopChannel <- true - - log.Info(history) } func CreateScenario(streamName goengine.StreamName) *Recipe { diff --git a/docker-compose.yml b/docker-compose.yml index 077ecdc4..1c847759 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,12 @@ version: '2' services: + rabbitmq: + image: rabbitmq:3.6.1-management + ports: + - "15672:15672" + - "5672:5672" + redis: image: redis diff --git a/event_dispatcher_manager.go b/event_dispatcher_manager.go index e85d7e04..a2b4b6f1 100644 --- a/event_dispatcher_manager.go +++ b/event_dispatcher_manager.go @@ -4,7 +4,8 @@ import ( log "github.com/Sirupsen/logrus" ) -// VersionedEventDispatchManager is responsible for coordinating receiving messages from event receivers and dispatching them to the event dispatcher. +// VersionedEventDispatchManager is responsible for coordinating receiving messages +// from event receivers and dispatching them to the event dispatcher. type VersionedEventDispatchManager struct { versionedEventDispatcher *MapBasedVersionedEventDispatcher typeRegistry TypeRegistry @@ -47,7 +48,8 @@ func (m *VersionedEventDispatchManager) Listen(stop <-chan bool, exclusive bool) for { // Wait on multiple channels using the select control flow. select { - // Version event received channel receives a result with a channel to respond to, signifying successful processing of the message. + // Version event received channel receives a result with a channel to respond to, + // signifying successful processing of the message. // This should eventually call an event handler. See NewVersionedEventDispatcher() case event := <-receiveEventChannel: log.Debugf("EventDispatchManager.DispatchEvent: %s", event.Event) diff --git a/rabbit/eventbus.go b/rabbit/eventbus.go new file mode 100644 index 00000000..3a41cfcd --- /dev/null +++ b/rabbit/eventbus.go @@ -0,0 +1,245 @@ +package rabbit + +import ( + "encoding/json" + "errors" + "fmt" + "time" + + log "github.com/Sirupsen/logrus" + "github.com/hellofresh/goengine" + "github.com/hellofresh/goengine/reflection" + "github.com/streadway/amqp" +) + +// RawVersionedEvent represents the event that goes into rabbitmq +type RawVersionedEvent struct { + ID string `bson:"aggregate_id,omitempty"` + Version int `bson:"version"` + Type string `bson:"type"` + Payload json.RawMessage `bson:"payload"` + RecordedOn time.Time `bson:"recorded_on"` +} + +// EventBus ... +type EventBus struct { + brokerDSN string + name string + exchange string +} + +// NewEventBus ... +func NewEventBus(brokerDSN string, name string, exchange string) *EventBus { + return &EventBus{brokerDSN, name, exchange} +} + +// PublishEvents will publish events +func (bus *EventBus) PublishEvents(events []*goengine.DomainMessage) error { + // Connects opens an AMQP connection from the credentials in the URL. + conn, err := amqp.Dial(bus.brokerDSN) + if err != nil { + return err + } + + // This waits for a server acknowledgment which means the sockets will have + // flushed all outbound publishings prior to returning. It's important to + // block on Close to not lose any publishings. + defer conn.Close() + + c, err := conn.Channel() + if err != nil { + return fmt.Errorf("channel.open: %s", err) + } + + // We declare our topology on both the publisher and consumer to ensure they + // are the same. This is part of AMQP being a programmable messaging model. + // + // See the Channel.Consume example for the complimentary declare. + err = c.ExchangeDeclare(bus.exchange, "fanout", true, false, false, false, nil) + if err != nil { + return fmt.Errorf("exchange.declare: %v", err) + } + + for _, event := range events { + rabbitEvent, err := bus.toRawEvent(event) + if nil != err { + return err + } + + encodedEvent, err := json.Marshal(rabbitEvent) + if nil != err { + return err + } + + // Prepare this message to be persistent. Your publishing requirements may + // be different. + msg := amqp.Publishing{ + DeliveryMode: amqp.Persistent, + Timestamp: time.Now(), + ContentEncoding: "UTF-8", + ContentType: "application/json", + Body: encodedEvent, + } + + err = c.Publish(bus.exchange, "", true, false, msg) + if err != nil { + // Since publish is asynchronous this can happen if the network connection + // is reset or if the server has run out of resources. + return fmt.Errorf("basic.publish: %v", err) + } + } + + return nil +} + +// ReceiveEvents will receive events +func (bus *EventBus) ReceiveEvents(options goengine.VersionedEventReceiverOptions) error { + conn, c, events, err := bus.consumeEventsQueue(options.Exclusive) + if err != nil { + return err + } + + go func() { + for { + select { + case ch := <-options.Close: + defer conn.Close() + ch <- c.Cancel(bus.name, false) + return + + case message, more := <-events: + if more { + var raw RawVersionedEvent + if err := json.Unmarshal(message.Body, &raw); err != nil { + options.Error <- fmt.Errorf("json.Unmarshal received event: %v", err) + } else { + domainEvent, err := bus.fromRawEvent(options.TypeRegistry, &raw) + if nil != err { + log.Debugf("EventBus.Cannot find event type %s", raw.Type) + options.Error <- errors.New("Cannot find event type " + raw.Type) + message.Ack(true) + } else { + ackCh := make(chan bool) + + log.Debug("EventBus.Dispatching Message") + options.ReceiveEvent <- goengine.VersionedEventTransactedAccept{Event: domainEvent, ProcessedSuccessfully: ackCh} + result := <-ackCh + message.Ack(result) + } + } + } else { + log.Debug("RabbitMQ: Could have been disconnected") + for { + retryError := exponential(func() error { + connR, cR, eventsR, errR := bus.consumeEventsQueue(options.Exclusive) + if errR == nil { + conn, c, events, err = connR, cR, eventsR, errR + } + + log.Debug(err) + + return errR + }, 5) + + if retryError == nil { + break + } + } + } + } + } + }() + + return nil +} + +// DeleteQueue will delete a queue +func (bus *EventBus) DeleteQueue(name string) error { + conn, err := amqp.Dial(bus.brokerDSN) + if err != nil { + return err + } + + c, err := conn.Channel() + if err != nil { + return fmt.Errorf("channel.open: %s", err) + } + + _, err = c.QueueDelete(name, false, false, true) + return err +} + +func (bus *EventBus) consumeEventsQueue(exclusive bool) (*amqp.Connection, *amqp.Channel, <-chan amqp.Delivery, error) { + conn, err := amqp.Dial(bus.brokerDSN) + if err != nil { + return nil, nil, nil, err + } + + c, err := conn.Channel() + if err != nil { + return nil, nil, nil, fmt.Errorf("channel.open: %s", err) + } + + // We declare our topology on both the publisher and consumer to ensure they + // are the same. This is part of AMQP being a programmable messaging model. + // + // See the Channel.Consume example for the complimentary declare. + err = c.ExchangeDeclare(bus.exchange, "fanout", true, false, false, false, nil) + if err != nil { + return nil, nil, nil, fmt.Errorf("exchange.declare: %v", err) + } + + if _, err = c.QueueDeclare(bus.name, true, false, false, false, nil); err != nil { + return nil, nil, nil, fmt.Errorf("queue.declare: %v", err) + } + + if err = c.QueueBind(bus.name, bus.name, bus.exchange, false, nil); err != nil { + return nil, nil, nil, fmt.Errorf("queue.bind: %v", err) + } + + events, err := c.Consume(bus.name, bus.name, false, exclusive, false, false, nil) + if err != nil { + return nil, nil, nil, fmt.Errorf("basic.consume: %v", err) + } + + if err := c.Qos(1, 0, false); err != nil { + return nil, nil, nil, fmt.Errorf("Qos: %v", err) + } + + return conn, c, events, nil +} + +func (bus *EventBus) toRawEvent(event *goengine.DomainMessage) (*RawVersionedEvent, error) { + serializedPayload, err := json.Marshal(event.Payload) + if nil != err { + return nil, err + } + + typeName := reflection.TypeOf(event.Payload) + return &RawVersionedEvent{ + ID: event.ID, + Version: event.Version, + Type: typeName.String(), + Payload: serializedPayload, + RecordedOn: event.RecordedOn, + }, nil +} + +func (bus *EventBus) fromRawEvent(typeRegistry goengine.TypeRegistry, rabbitEvent *RawVersionedEvent) (*goengine.DomainMessage, error) { + event, err := typeRegistry.Get(rabbitEvent.Type) + if nil != err { + return nil, err + } + + err = json.Unmarshal(rabbitEvent.Payload, event) + if nil != err { + return nil, err + } + + return goengine.NewDomainMessage( + rabbitEvent.ID, + rabbitEvent.Version, + event.(goengine.DomainEvent), + rabbitEvent.RecordedOn, + ), nil +} diff --git a/rabbit/retry.go b/rabbit/retry.go new file mode 100644 index 00000000..467945d7 --- /dev/null +++ b/rabbit/retry.go @@ -0,0 +1,30 @@ +package rabbit + +import ( + "math" + "time" + + log "github.com/Sirupsen/logrus" +) + +type function func() error + +func exponential(operation function, maxRetries int) error { + var err error + var sleepTime int + for i := 0; i < maxRetries; i++ { + err = operation() + if err == nil { + return nil + } + if i == 0 { + sleepTime = 1 + } else { + sleepTime = int(math.Exp2(float64(i)) * 100) + } + time.Sleep(time.Duration(sleepTime) * time.Millisecond) + log.Debugf("Retry exponential: Attempt %d, sleep %d", i, sleepTime) + } + + return err +} From 7a6acf301e11a6740f1be881e358cad811487251 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toma=C5=BE=20=C5=BDinko?= Date: Thu, 23 Mar 2017 12:20:37 +0100 Subject: [PATCH 36/74] Update aggregate_repository.go --- aggregate_repository.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/aggregate_repository.go b/aggregate_repository.go index f58a2b05..9ac20fcb 100644 --- a/aggregate_repository.go +++ b/aggregate_repository.go @@ -58,6 +58,10 @@ func (r *PublisherRepository) Reconstitute(id string, source AggregateRoot, stre } events := stream.Events + if len(events) == 0 { + return errors.New("No events found for this id") + } + for _, event := range events { source.Apply(event.Payload) } From 59e130246ef881c1902258235a30c1fdfe043c72 Mon Sep 17 00:00:00 2001 From: Robert Kel Date: Thu, 23 Mar 2017 12:30:58 +0100 Subject: [PATCH 37/74] Add more description --- aggregate_repository.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aggregate_repository.go b/aggregate_repository.go index 9ac20fcb..7892951d 100644 --- a/aggregate_repository.go +++ b/aggregate_repository.go @@ -59,7 +59,7 @@ func (r *PublisherRepository) Reconstitute(id string, source AggregateRoot, stre events := stream.Events if len(events) == 0 { - return errors.New("No events found for this id") + return fmt.Errorf("No events found for id: %s", id) } for _, event := range events { From 2f29f169f7a2817636b831e5c5e6d24d86e14621 Mon Sep 17 00:00:00 2001 From: Robert Kel Date: Thu, 23 Mar 2017 12:32:14 +0100 Subject: [PATCH 38/74] Add fmt --- aggregate_repository.go | 1 + 1 file changed, 1 insertion(+) diff --git a/aggregate_repository.go b/aggregate_repository.go index 7892951d..e84400f4 100644 --- a/aggregate_repository.go +++ b/aggregate_repository.go @@ -1,6 +1,7 @@ package goengine import ( + "fmt" log "github.com/Sirupsen/logrus" ) From 5ab82fa9a69921b2592bb9d3e5cce48b2055bea6 Mon Sep 17 00:00:00 2001 From: Vladimir Garvardt Date: Fri, 23 Jun 2017 12:19:45 +0200 Subject: [PATCH 39/74] Updated logrus to 1.0, simplified log messages --- .travis.yml | 6 +++--- aggregate_repository.go | 13 +++++++------ aggregate_root.go | 27 +++++++++++++++------------ cmd/goengine/main.go | 5 ++--- domain_message.go | 9 ++++++++- event_dispatcher_manager.go | 17 ++++++++++------- rabbit/eventbus.go | 4 ++-- rabbit/retry.go | 15 +++++++++------ type_registry.go | 11 ++++++----- 9 files changed, 62 insertions(+), 45 deletions(-) diff --git a/.travis.yml b/.travis.yml index fd7d3e43..f6534407 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,7 @@ go: install: - go get -v -d - - go get github.com/onsi/ginkgo/ginkgo - - go get github.com/onsi/gomega - + - go get -u github.com/onsi/ginkgo/ginkgo + - go get -u github.com/onsi/gomega + script: ginkgo -r diff --git a/aggregate_repository.go b/aggregate_repository.go index e84400f4..c2007cf9 100644 --- a/aggregate_repository.go +++ b/aggregate_repository.go @@ -2,7 +2,8 @@ package goengine import ( "fmt" - log "github.com/Sirupsen/logrus" + + log "github.com/sirupsen/logrus" ) type AggregateRepository interface { @@ -21,7 +22,7 @@ func NewPublisherRepository(eventStore EventStore, eventBus VersionedEventPublis } func (r *PublisherRepository) Load(id string, streamName StreamName) (*EventStream, error) { - log.Debugf("Loading events from %s stream for aggregate %s", streamName, id) + log.WithFields(log.Fields{"stream": streamName, "id": id}).Debug("Loading events from stream for aggregate") stream, err := r.EventStore.GetEventsFor(streamName, id) if nil != err { return nil, err @@ -33,14 +34,14 @@ func (r *PublisherRepository) Load(id string, streamName StreamName) (*EventStre func (r *PublisherRepository) Save(aggregateRoot AggregateRoot, streamName StreamName) error { events := aggregateRoot.GetUncommittedEvents() eventStream := NewEventStream(streamName, events) - log.Debugf("Saving %d events to %s stream", len(events), streamName) + log.WithFields(log.Fields{"count": len(events), "stream": streamName}).Debug("Saving events to stream") err := r.EventStore.Append(eventStream) if nil != err { return err } if nil == r.EventBus { - log.Debug("Event bus not detected, skiping publishing events") + log.Debug("Event bus not detected, skipping publishing events") return nil } @@ -52,7 +53,7 @@ func (r *PublisherRepository) Save(aggregateRoot AggregateRoot, streamName Strea } func (r *PublisherRepository) Reconstitute(id string, source AggregateRoot, streamName StreamName) error { - log.Debugf("Reconstituting aggregate %s from %s stream", id, streamName) + log.WithFields(log.Fields{"stream": streamName, "id": id}).Debug("Reconstituting aggregate from stream") stream, err := r.Load(id, streamName) if nil != err { return err @@ -68,6 +69,6 @@ func (r *PublisherRepository) Reconstitute(id string, source AggregateRoot, stre } source.SetVersion(events[len(events)-1].Version) - log.Debugf("Aggregate %s reconstituted", id) + log.WithField("id", id).Debug("Aggregate reconstituted") return nil } diff --git a/aggregate_root.go b/aggregate_root.go index f6ad907f..63de692d 100644 --- a/aggregate_root.go +++ b/aggregate_root.go @@ -3,9 +3,9 @@ package goengine import ( "fmt" - log "github.com/Sirupsen/logrus" "github.com/hellofresh/goengine/reflection" "github.com/pborman/uuid" + log "github.com/sirupsen/logrus" ) type AggregateRoot interface { @@ -17,10 +17,10 @@ type AggregateRoot interface { } type AggregateRootBased struct { - ID string - version int - source interface{} - uncommitedEvents []*DomainMessage + ID string + version int + source interface{} + uncommittedEvents []*DomainMessage } // NewAggregateRootBased constructor @@ -46,18 +46,21 @@ func (r *AggregateRootBased) SetVersion(version int) { } func (r *AggregateRootBased) GetUncommittedEvents() []*DomainMessage { - stream := r.uncommitedEvents - r.uncommitedEvents = nil - log.Debugf("%d Uncommited events cleaned", len(stream)) + stream := r.uncommittedEvents + r.uncommittedEvents = nil + log.WithField("count", len(stream)).Debug("Uncommitted events cleaned") return stream } func (r *AggregateRootBased) Apply(event DomainEvent) { t := reflection.TypeOf(event) - log.Debugf("source: %+v; MethodName: %+v; event: %+v", r.source, fmt.Sprintf("When%s", t.Name()), event) - reflection.CallMethod(r.source, fmt.Sprintf("When%s", t.Name()), event) - log.Debugf("Event %s applied", t.Name()) + methodName := fmt.Sprintf("When%s", t.Name()) + + entry := log.WithFields(log.Fields{"source": fmt.Sprintf("%+v", r.source), "method": methodName, "event": fmt.Sprintf("%+v", event)}) + entry.Debug("Applying event") + reflection.CallMethod(r.source, methodName, event) + entry.Debug("Event applied") } func (r *AggregateRootBased) RecordThat(event DomainEvent) { @@ -68,6 +71,6 @@ func (r *AggregateRootBased) RecordThat(event DomainEvent) { func (r *AggregateRootBased) Record(event DomainEvent) { message := RecordNow(r.ID, r.version, event) - r.uncommitedEvents = append(r.uncommitedEvents, message) + r.uncommittedEvents = append(r.uncommittedEvents, message) log.Debug("Event recorded") } diff --git a/cmd/goengine/main.go b/cmd/goengine/main.go index 51b52b90..c9f54928 100644 --- a/cmd/goengine/main.go +++ b/cmd/goengine/main.go @@ -3,11 +3,10 @@ package main import ( "os" - log "github.com/Sirupsen/logrus" "github.com/hellofresh/goengine" "github.com/hellofresh/goengine/mongodb" "github.com/hellofresh/goengine/rabbit" - + log "github.com/sirupsen/logrus" "gopkg.in/mgo.v2" ) @@ -16,7 +15,7 @@ func main() { var streamName goengine.StreamName = "test" mongoDSN := os.Getenv("STORAGE_DSN") - log.Infof("Connecting to the database %s", mongoDSN) + log.WithField("dsn", mongoDSN).Debug("Connecting to the database") session, err := mgo.Dial(mongoDSN) if err != nil { log.Panic(err) diff --git a/domain_message.go b/domain_message.go index 6eb0e278..3c11d51c 100644 --- a/domain_message.go +++ b/domain_message.go @@ -1,6 +1,9 @@ package goengine -import "time" +import ( + "fmt" + "time" +) type DomainEvent interface { OccurredOn() time.Time @@ -13,6 +16,10 @@ type DomainMessage struct { RecordedOn time.Time `json:"recorded_on"` } +func (dm *DomainMessage) String() string { + return fmt.Sprintf("DomainMessage{ ID: %s, Version: %d }", dm.ID, dm.Version) +} + func NewDomainMessage(id string, version int, payload DomainEvent, recordedOn time.Time) *DomainMessage { return &DomainMessage{id, version, payload, recordedOn} } diff --git a/event_dispatcher_manager.go b/event_dispatcher_manager.go index a2b4b6f1..12d7cda4 100644 --- a/event_dispatcher_manager.go +++ b/event_dispatcher_manager.go @@ -1,7 +1,7 @@ package goengine import ( - log "github.com/Sirupsen/logrus" + log "github.com/sirupsen/logrus" ) // VersionedEventDispatchManager is responsible for coordinating receiving messages @@ -52,22 +52,25 @@ func (m *VersionedEventDispatchManager) Listen(stop <-chan bool, exclusive bool) // signifying successful processing of the message. // This should eventually call an event handler. See NewVersionedEventDispatcher() case event := <-receiveEventChannel: - log.Debugf("EventDispatchManager.DispatchEvent: %s", event.Event) + entry := log.WithField("event", event.Event) + entry.Debugf("EventDispatchManager.DispatchEvent") if err := m.versionedEventDispatcher.DispatchEvent(event.Event); err != nil { - log.Println("Error dispatching event: ", err) + entry.WithError(err).Error("Error dispatching event") } event.ProcessedSuccessfully <- true - log.Debug("EventDispatchManager.DispatchSuccessful") + entry.Debug("EventDispatchManager.DispatchSuccessful") + case <-stop: log.Debug("EventDispatchManager.Stopping") closeSignal := make(chan error) closeChannel <- closeSignal - defer log.Debug("EventDispatchManager.Stopped") + log.Debug("EventDispatchManager.Stopped") return <-closeSignal - // Receiving on this channel signifys an error has occured worker processor side + + // Receiving on this channel signifys an error has occurred worker processor side case err := <-errorChannel: - log.Debugf("EventDispatchManager.ErrorReceived: %s", err) + log.WithError(err).Debugf("EventDispatchManager.ErrorReceived") return err } } diff --git a/rabbit/eventbus.go b/rabbit/eventbus.go index 3a41cfcd..dd0d1b9a 100644 --- a/rabbit/eventbus.go +++ b/rabbit/eventbus.go @@ -6,9 +6,9 @@ import ( "fmt" "time" - log "github.com/Sirupsen/logrus" "github.com/hellofresh/goengine" "github.com/hellofresh/goengine/reflection" + log "github.com/sirupsen/logrus" "github.com/streadway/amqp" ) @@ -136,7 +136,7 @@ func (bus *EventBus) ReceiveEvents(options goengine.VersionedEventReceiverOption conn, c, events, err = connR, cR, eventsR, errR } - log.Debug(err) + log.WithError(err).Debug("Failed to reconnect to RabbitMQ") return errR }, 5) diff --git a/rabbit/retry.go b/rabbit/retry.go index 467945d7..0cc470b4 100644 --- a/rabbit/retry.go +++ b/rabbit/retry.go @@ -4,26 +4,29 @@ import ( "math" "time" - log "github.com/Sirupsen/logrus" + log "github.com/sirupsen/logrus" ) type function func() error func exponential(operation function, maxRetries int) error { var err error - var sleepTime int + var sleepMs int for i := 0; i < maxRetries; i++ { err = operation() if err == nil { return nil } + if i == 0 { - sleepTime = 1 + sleepMs = 1 } else { - sleepTime = int(math.Exp2(float64(i)) * 100) + sleepMs = int(math.Exp2(float64(i)) * 100) } - time.Sleep(time.Duration(sleepTime) * time.Millisecond) - log.Debugf("Retry exponential: Attempt %d, sleep %d", i, sleepTime) + + sleepTime := time.Duration(sleepMs) * time.Millisecond + time.Sleep(sleepTime) + log.WithFields(log.Fields{"attempt": i, "sleep": sleepTime.String()}).Debug("Retry exponential") } return err diff --git a/type_registry.go b/type_registry.go index 18876898..f0e6bc5e 100644 --- a/type_registry.go +++ b/type_registry.go @@ -3,9 +3,9 @@ package goengine import ( "reflect" - log "github.com/Sirupsen/logrus" "github.com/hellofresh/goengine/errors" "github.com/hellofresh/goengine/reflection" + log "github.com/sirupsen/logrus" ) // TypeRegistry is a registry for go types @@ -35,15 +35,16 @@ func NewInMemmoryTypeRegistry() *InMemoryTypeRegistry { func (r *InMemoryTypeRegistry) RegisterType(i interface{}) { rawType := reflection.TypeOf(i) r.types[rawType.String()] = rawType - log.Debugf("Type %s was registered", rawType.String()) + log.WithField("type", rawType.String()).Debug("Type was registered") } func (r *InMemoryTypeRegistry) RegisterAggregate(aggregate AggregateRoot, events ...interface{}) { r.RegisterType(aggregate) - log.Debugf("Aggregate %s was registered", aggregate.GetID()) + entry := log.WithField("aggregate", aggregate.GetID()) + entry.Debug("Aggregate was registered") r.RegisterEvents(events) - log.Debugf("%s events were registered for aggregate %s", len(events), aggregate.GetID()) + entry.WithField("count", len(events)).Debug("Events were registered for aggregate") } func (r *InMemoryTypeRegistry) RegisterEvents(events ...interface{}) { @@ -66,6 +67,6 @@ func (r *InMemoryTypeRegistry) Get(name string) (interface{}, error) { return reflect.New(typ).Interface(), nil } - log.Debugf("Type %s not found", name) + log.WithField("type", name).Debug("Type not found") return nil, errors.ErrorTypeNotFound } From 9b060888e377907b6427cccf46341a3de41173df Mon Sep 17 00:00:00 2001 From: Kieran Date: Tue, 30 May 2017 10:56:58 +0200 Subject: [PATCH 40/74] Fix 'inmemmory' typo (breaking change) --- cmd/goengine/main.go | 2 +- type_registry.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/goengine/main.go b/cmd/goengine/main.go index c9f54928..cf8e55d4 100644 --- a/cmd/goengine/main.go +++ b/cmd/goengine/main.go @@ -26,7 +26,7 @@ func main() { session.SetMode(mgo.Monotonic, true) log.Info("Setting up the registry") - registry := goengine.NewInMemmoryTypeRegistry() + registry := goengine.NewInMemoryTypeRegistry() registry.RegisterType(&RecipeCreated{}) registry.RegisterType(&RecipeRated{}) diff --git a/type_registry.go b/type_registry.go index f0e6bc5e..148c2a44 100644 --- a/type_registry.go +++ b/type_registry.go @@ -26,8 +26,8 @@ type InMemoryTypeRegistry struct { types map[string]reflect.Type } -// NewInMemmoryTypeRegistry creates a new in memory registry -func NewInMemmoryTypeRegistry() *InMemoryTypeRegistry { +// NewInMemoryTypeRegistry creates a new in memory registry +func NewInMemoryTypeRegistry() *InMemoryTypeRegistry { return &InMemoryTypeRegistry{make(map[string]reflect.Type)} } From 1ad8972ce23cfa437baf1ae3d3ad64ee44794b9c Mon Sep 17 00:00:00 2001 From: Kieran Date: Tue, 30 May 2017 11:51:22 +0200 Subject: [PATCH 41/74] Also fix readme link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d6fee65f..a3534099 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ go get github.com/hellofresh/goengine Here you can check a small tutorial of how to use this component in an orders scenario. -[Tutorial] (docs/how_to.md) +[Tutorial](docs/how_to.md) ## Contributing From 6ece76dc84d4498c8f424f411ab881f5ee16f5c2 Mon Sep 17 00:00:00 2001 From: Vladimir Garvardt Date: Mon, 26 Jun 2017 16:01:23 +0200 Subject: [PATCH 42/74] Removed logrus dependency from the project --- README.md | 2 +- aggregate_repository.go | 14 ++++++------ aggregate_root.go | 11 +++++----- cmd/goengine/main.go | 25 +++++++++++---------- event_dispatcher_manager.go | 18 ++++++--------- logging.go | 44 +++++++++++++++++++++++++++++++++++++ rabbit/eventbus.go | 10 ++++----- rabbit/retry.go | 4 ++-- type_registry.go | 13 ++++++----- 9 files changed, 90 insertions(+), 51 deletions(-) create mode 100644 logging.go diff --git a/README.md b/README.md index a3534099..44124643 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ Engine is divided in a few small independent components. ## Install ```sh -go get github.com/hellofresh/goengine +go get -u github.com/hellofresh/goengine ``` ## Usage diff --git a/aggregate_repository.go b/aggregate_repository.go index c2007cf9..25ee4566 100644 --- a/aggregate_repository.go +++ b/aggregate_repository.go @@ -2,8 +2,6 @@ package goengine import ( "fmt" - - log "github.com/sirupsen/logrus" ) type AggregateRepository interface { @@ -22,7 +20,7 @@ func NewPublisherRepository(eventStore EventStore, eventBus VersionedEventPublis } func (r *PublisherRepository) Load(id string, streamName StreamName) (*EventStream, error) { - log.WithFields(log.Fields{"stream": streamName, "id": id}).Debug("Loading events from stream for aggregate") + Log("Loading events from stream for aggregate", map[string]interface{}{"stream": streamName, "id": id}, nil) stream, err := r.EventStore.GetEventsFor(streamName, id) if nil != err { return nil, err @@ -34,14 +32,15 @@ func (r *PublisherRepository) Load(id string, streamName StreamName) (*EventStre func (r *PublisherRepository) Save(aggregateRoot AggregateRoot, streamName StreamName) error { events := aggregateRoot.GetUncommittedEvents() eventStream := NewEventStream(streamName, events) - log.WithFields(log.Fields{"count": len(events), "stream": streamName}).Debug("Saving events to stream") + Log("Saving events to stream", map[string]interface{}{"count": len(events), "stream": streamName}, nil) + err := r.EventStore.Append(eventStream) if nil != err { return err } if nil == r.EventBus { - log.Debug("Event bus not detected, skipping publishing events") + Log("Event bus not detected, skipping publishing events", nil, nil) return nil } @@ -53,7 +52,8 @@ func (r *PublisherRepository) Save(aggregateRoot AggregateRoot, streamName Strea } func (r *PublisherRepository) Reconstitute(id string, source AggregateRoot, streamName StreamName) error { - log.WithFields(log.Fields{"stream": streamName, "id": id}).Debug("Reconstituting aggregate from stream") + Log("Reconstituting aggregate from stream", map[string]interface{}{"stream": streamName, "id": id}, nil) + stream, err := r.Load(id, streamName) if nil != err { return err @@ -69,6 +69,6 @@ func (r *PublisherRepository) Reconstitute(id string, source AggregateRoot, stre } source.SetVersion(events[len(events)-1].Version) - log.WithField("id", id).Debug("Aggregate reconstituted") + Log("Aggregate reconstituted", map[string]interface{}{"id": id}, nil) return nil } diff --git a/aggregate_root.go b/aggregate_root.go index 63de692d..e07aa7f4 100644 --- a/aggregate_root.go +++ b/aggregate_root.go @@ -5,7 +5,6 @@ import ( "github.com/hellofresh/goengine/reflection" "github.com/pborman/uuid" - log "github.com/sirupsen/logrus" ) type AggregateRoot interface { @@ -48,7 +47,7 @@ func (r *AggregateRootBased) SetVersion(version int) { func (r *AggregateRootBased) GetUncommittedEvents() []*DomainMessage { stream := r.uncommittedEvents r.uncommittedEvents = nil - log.WithField("count", len(stream)).Debug("Uncommitted events cleaned") + Log("Uncommitted events cleaned", map[string]interface{}{"count": len(stream)}, nil) return stream } @@ -57,10 +56,10 @@ func (r *AggregateRootBased) Apply(event DomainEvent) { t := reflection.TypeOf(event) methodName := fmt.Sprintf("When%s", t.Name()) - entry := log.WithFields(log.Fields{"source": fmt.Sprintf("%+v", r.source), "method": methodName, "event": fmt.Sprintf("%+v", event)}) - entry.Debug("Applying event") + fields := map[string]interface{}{"source": fmt.Sprintf("%+v", r.source), "method": methodName, "event": fmt.Sprintf("%+v", event)} + Log("Applying event", fields, nil) reflection.CallMethod(r.source, methodName, event) - entry.Debug("Event applied") + Log("Event applied", fields, nil) } func (r *AggregateRootBased) RecordThat(event DomainEvent) { @@ -72,5 +71,5 @@ func (r *AggregateRootBased) RecordThat(event DomainEvent) { func (r *AggregateRootBased) Record(event DomainEvent) { message := RecordNow(r.ID, r.version, event) r.uncommittedEvents = append(r.uncommittedEvents, message) - log.Debug("Event recorded") + Log("Event recorded", nil, nil) } diff --git a/cmd/goengine/main.go b/cmd/goengine/main.go index cf8e55d4..2f9e1192 100644 --- a/cmd/goengine/main.go +++ b/cmd/goengine/main.go @@ -6,47 +6,47 @@ import ( "github.com/hellofresh/goengine" "github.com/hellofresh/goengine/mongodb" "github.com/hellofresh/goengine/rabbit" - log "github.com/sirupsen/logrus" "gopkg.in/mgo.v2" ) func main() { - log.SetLevel(log.DebugLevel) var streamName goengine.StreamName = "test" mongoDSN := os.Getenv("STORAGE_DSN") - log.WithField("dsn", mongoDSN).Debug("Connecting to the database") + goengine.Log("Connecting to the database", map[string]interface{}{"dsn": mongoDSN}, nil) session, err := mgo.Dial(mongoDSN) if err != nil { - log.Panic(err) + goengine.Log("Failed to connect to Mongo", nil, err) + panic(err) } defer session.Close() // Optional. Switch the session to a monotonic behavior. session.SetMode(mgo.Monotonic, true) - log.Info("Setting up the registry") + goengine.Log("Setting up the registry", nil, nil) registry := goengine.NewInMemoryTypeRegistry() registry.RegisterType(&RecipeCreated{}) registry.RegisterType(&RecipeRated{}) - log.Info("Setting up the event bus") // bus := inmemory.NewInMemoryEventBus() - bus := rabbit.NewEventBus(os.Getenv("BROKER_DSN"), "events", "events") + brokerDSN := os.Getenv("BROKER_DSN") + goengine.Log("Setting up the event bus", map[string]interface{}{"dsn": brokerDSN}, nil) + bus := rabbit.NewEventBus(brokerDSN, "events", "events") - log.Info("Setting up the event store") + goengine.Log("Setting up the event store", nil, nil) es := mongodb.NewEventStore(session, registry) eventDispatcher := goengine.NewVersionedEventDispatchManager(bus, registry) eventDispatcher.RegisterEventHandler(&RecipeCreated{}, func(event *goengine.DomainMessage) error { - log.Debug("Event received") + goengine.Log("Event received", nil, nil) return nil }) stopChannel := make(chan bool) go eventDispatcher.Listen(stopChannel, false) - log.Info("Creating a recipe") + goengine.Log("Creating a recipe", nil, nil) aggregateRoot := CreateScenario(streamName) repository := goengine.NewPublisherRepository(es, bus) @@ -54,10 +54,11 @@ func main() { _, err = NewRecipeFromHisotry(aggregateRoot.ID, streamName, repository) if err != nil { - log.Panic(err) + goengine.Log("Failed to connect to Mongo", nil, err) + panic(err) } - log.Println("Stop channel") + goengine.Log("Stopping channel", nil, err) stopChannel <- true } diff --git a/event_dispatcher_manager.go b/event_dispatcher_manager.go index 12d7cda4..5a4cee9d 100644 --- a/event_dispatcher_manager.go +++ b/event_dispatcher_manager.go @@ -1,9 +1,5 @@ package goengine -import ( - log "github.com/sirupsen/logrus" -) - // VersionedEventDispatchManager is responsible for coordinating receiving messages // from event receivers and dispatching them to the event dispatcher. type VersionedEventDispatchManager struct { @@ -52,25 +48,25 @@ func (m *VersionedEventDispatchManager) Listen(stop <-chan bool, exclusive bool) // signifying successful processing of the message. // This should eventually call an event handler. See NewVersionedEventDispatcher() case event := <-receiveEventChannel: - entry := log.WithField("event", event.Event) - entry.Debugf("EventDispatchManager.DispatchEvent") + fields := map[string]interface{}{"event": event.Event} + Log("EventDispatchManager.DispatchEvent", fields, nil) if err := m.versionedEventDispatcher.DispatchEvent(event.Event); err != nil { - entry.WithError(err).Error("Error dispatching event") + Log("Error dispatching event", fields, err) } event.ProcessedSuccessfully <- true - entry.Debug("EventDispatchManager.DispatchSuccessful") + Log("EventDispatchManager.DispatchSuccessful", fields, nil) case <-stop: - log.Debug("EventDispatchManager.Stopping") + Log("EventDispatchManager.Stopping", nil, nil) closeSignal := make(chan error) closeChannel <- closeSignal - log.Debug("EventDispatchManager.Stopped") + Log("EventDispatchManager.Stopped", nil, nil) return <-closeSignal // Receiving on this channel signifys an error has occurred worker processor side case err := <-errorChannel: - log.WithError(err).Debugf("EventDispatchManager.ErrorReceived") + Log("EventDispatchManager.ErrorReceived", nil, err) return err } } diff --git a/logging.go b/logging.go new file mode 100644 index 00000000..01baea74 --- /dev/null +++ b/logging.go @@ -0,0 +1,44 @@ +package goengine + +import ( + "fmt" + "log" + "os" + "strings" +) + +type LogHandler func(msg string, fields map[string]interface{}, err error) + +var logHandler LogHandler + +func init() { + l := log.New(os.Stderr, "[GoEngine] ", log.LstdFlags) + + SetLogHandler(func(msg string, fields map[string]interface{}, err error) { + if nil != err { + if nil == fields { + fields = make(map[string]interface{}) + } + fields["error"] = err.Error() + } + + msgParts := make([]string, len(fields)+1) + + msgParts[0] = msg + idx := 1 + for k, v := range fields { + msgParts[idx] = fmt.Sprintf("%s=%v", k, v) + idx++ + } + + l.Println(strings.Join(msgParts, "\t")) + }) +} + +func SetLogHandler(handler LogHandler) { + logHandler = handler +} + +func Log(msg string, fields map[string]interface{}, err error) { + logHandler(msg, fields, err) +} diff --git a/rabbit/eventbus.go b/rabbit/eventbus.go index dd0d1b9a..2ee236c0 100644 --- a/rabbit/eventbus.go +++ b/rabbit/eventbus.go @@ -8,7 +8,6 @@ import ( "github.com/hellofresh/goengine" "github.com/hellofresh/goengine/reflection" - log "github.com/sirupsen/logrus" "github.com/streadway/amqp" ) @@ -115,20 +114,20 @@ func (bus *EventBus) ReceiveEvents(options goengine.VersionedEventReceiverOption } else { domainEvent, err := bus.fromRawEvent(options.TypeRegistry, &raw) if nil != err { - log.Debugf("EventBus.Cannot find event type %s", raw.Type) + goengine.Log("EventBus.Cannot find event type", map[string]interface{}{"type": raw.Type}, nil) options.Error <- errors.New("Cannot find event type " + raw.Type) message.Ack(true) } else { ackCh := make(chan bool) - log.Debug("EventBus.Dispatching Message") + goengine.Log("EventBus.Dispatching Message", nil, nil) options.ReceiveEvent <- goengine.VersionedEventTransactedAccept{Event: domainEvent, ProcessedSuccessfully: ackCh} result := <-ackCh message.Ack(result) } } } else { - log.Debug("RabbitMQ: Could have been disconnected") + goengine.Log("RabbitMQ: Could have been disconnected", nil, nil) for { retryError := exponential(func() error { connR, cR, eventsR, errR := bus.consumeEventsQueue(options.Exclusive) @@ -136,8 +135,7 @@ func (bus *EventBus) ReceiveEvents(options goengine.VersionedEventReceiverOption conn, c, events, err = connR, cR, eventsR, errR } - log.WithError(err).Debug("Failed to reconnect to RabbitMQ") - + goengine.Log("Failed to reconnect to RabbitMQ", nil, err) return errR }, 5) diff --git a/rabbit/retry.go b/rabbit/retry.go index 0cc470b4..d82edb6c 100644 --- a/rabbit/retry.go +++ b/rabbit/retry.go @@ -4,7 +4,7 @@ import ( "math" "time" - log "github.com/sirupsen/logrus" + "github.com/hellofresh/goengine" ) type function func() error @@ -26,7 +26,7 @@ func exponential(operation function, maxRetries int) error { sleepTime := time.Duration(sleepMs) * time.Millisecond time.Sleep(sleepTime) - log.WithFields(log.Fields{"attempt": i, "sleep": sleepTime.String()}).Debug("Retry exponential") + goengine.Log("Retry exponential", map[string]interface{}{"attempt": i, "sleep": sleepTime.String()}, err) } return err diff --git a/type_registry.go b/type_registry.go index 148c2a44..0beda950 100644 --- a/type_registry.go +++ b/type_registry.go @@ -5,7 +5,6 @@ import ( "github.com/hellofresh/goengine/errors" "github.com/hellofresh/goengine/reflection" - log "github.com/sirupsen/logrus" ) // TypeRegistry is a registry for go types @@ -35,16 +34,18 @@ func NewInMemoryTypeRegistry() *InMemoryTypeRegistry { func (r *InMemoryTypeRegistry) RegisterType(i interface{}) { rawType := reflection.TypeOf(i) r.types[rawType.String()] = rawType - log.WithField("type", rawType.String()).Debug("Type was registered") + Log("Type was registered", map[string]interface{}{"type": rawType.String()}, nil) } func (r *InMemoryTypeRegistry) RegisterAggregate(aggregate AggregateRoot, events ...interface{}) { r.RegisterType(aggregate) - entry := log.WithField("aggregate", aggregate.GetID()) - entry.Debug("Aggregate was registered") + + fields := map[string]interface{}{"aggregate": aggregate.GetID()} + Log("Aggregate was registered", fields, nil) r.RegisterEvents(events) - entry.WithField("count", len(events)).Debug("Events were registered for aggregate") + fields["count"] = len(events) + Log("Events were registered for aggregate", fields, nil) } func (r *InMemoryTypeRegistry) RegisterEvents(events ...interface{}) { @@ -67,6 +68,6 @@ func (r *InMemoryTypeRegistry) Get(name string) (interface{}, error) { return reflect.New(typ).Interface(), nil } - log.WithField("type", name).Debug("Type not found") + Log("Type not found", map[string]interface{}{"type": name}, nil) return nil, errors.ErrorTypeNotFound } From 80d83a7eef7aeec5d7a6deb6dd5d4e483da59881 Mon Sep 17 00:00:00 2001 From: Vladimir Garvardt Date: Mon, 26 Jun 2017 16:11:04 +0200 Subject: [PATCH 43/74] Added logging info to readme --- README.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/README.md b/README.md index 44124643..d8ed24d2 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,42 @@ Here you can check a small tutorial of how to use this component in an orders sc [Tutorial](docs/how_to.md) +## Logging + +GoEngine uses default `log` package for debug logging. If you want to use your own logger - `goengine.SetLogHandler()` +is available. Here is how you can use, e.g. `github.com/sirupsen/logrus` for logging: + +```go +package main + +import ( + "github.com/hellofresh/goengine" + log "github.com/sirupsen/logrus" +) + +func main() { + goengine.SetLogHandler(func(msg string, fields map[string]interface{}, err error) { + if nil == fields && nil == err { + log.Debug(msg) + } else { + var entry *log.Entry + if fields != nil { + entry = log.WithFields(log.Fields(fields)) + if nil != err { + entry = entry.WithError(err) + } + } else { + entry = log.WithError(err) + } + + entry.Debug(msg) + } + }) + + // do your application stuff +} +``` + ## Contributing Please see [CONTRIBUTING](CONTRIBUTING.md) for details. From 47fd6171f532966cb1a648e4de5f6f9bf8093854 Mon Sep 17 00:00:00 2001 From: Vladimir Garvardt Date: Wed, 30 Jan 2019 17:57:35 +0100 Subject: [PATCH 44/74] Use gofrs uuid lib instead of pborman --- aggregate_root.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aggregate_root.go b/aggregate_root.go index e07aa7f4..0adb22b9 100644 --- a/aggregate_root.go +++ b/aggregate_root.go @@ -3,8 +3,8 @@ package goengine import ( "fmt" + "github.com/gofrs/uuid" "github.com/hellofresh/goengine/reflection" - "github.com/pborman/uuid" ) type AggregateRoot interface { @@ -24,7 +24,7 @@ type AggregateRootBased struct { // NewAggregateRootBased constructor func NewAggregateRootBased(source interface{}) *AggregateRootBased { - return NewEventSourceBasedWithID(source, uuid.New()) + return NewEventSourceBasedWithID(source, uuid.Must(uuid.NewV4()).String()) } // NewEventSourceBasedWithID constructor From 470e2699ee7906cebba0159dc732ee4eab73f885 Mon Sep 17 00:00:00 2001 From: Vladimir Garvardt Date: Wed, 30 Jan 2019 17:59:33 +0100 Subject: [PATCH 45/74] Use modern version of go for testing --- .travis.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index f6534407..ae3c66e6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,10 +4,10 @@ services: - docker go: - - 1.6 - - 1.7 - - 1.8 - - master + - "1.9" + - "1.10" + - "1.11" + - "stable" install: - go get -v -d From a97aa7d21163f9735fa7f670801cc6624a221025 Mon Sep 17 00:00:00 2001 From: Vladimir Garvardt Date: Thu, 31 Jan 2019 19:18:05 +0100 Subject: [PATCH 46/74] Switched to official mongo driver --- Gopkg.lock | 257 +++++++++++++++++++++++++++++++++++++++++ Gopkg.toml | 50 ++++++++ cmd/goengine/main.go | 43 +++++-- event_store.go | 2 +- event_store_test.go | 2 +- inmemory/eventstore.go | 4 +- mongodb/eventstore.go | 124 ++++++++++++++------ 7 files changed, 435 insertions(+), 47 deletions(-) create mode 100644 Gopkg.lock create mode 100644 Gopkg.toml diff --git a/Gopkg.lock b/Gopkg.lock new file mode 100644 index 00000000..bd140089 --- /dev/null +++ b/Gopkg.lock @@ -0,0 +1,257 @@ +# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. + + +[[projects]] + digest = "1:586ea76dbd0374d6fb649a91d70d652b7fe0ccffb8910a77468e7702e7901f3d" + name = "github.com/go-stack/stack" + packages = ["."] + pruneopts = "UT" + revision = "2fee6af1a9795aafbe0253a0cfbdf668e1fb8a9a" + version = "v1.8.0" + +[[projects]] + digest = "1:bed9d72d596f94e65fff37f4d6c01398074a6bb1c3f3ceff963516bd01db6ff5" + name = "github.com/gofrs/uuid" + packages = ["."] + pruneopts = "UT" + revision = "6b08a5c5172ba18946672b49749cde22873dd7c2" + version = "v3.2.0" + +[[projects]] + branch = "master" + digest = "1:4a0c6bb4805508a6287675fac876be2ac1182539ca8a32468d8128882e9d5009" + name = "github.com/golang/snappy" + packages = ["."] + pruneopts = "UT" + revision = "2e65f85255dbc3072edf28d6b5b8efc472979f5a" + +[[projects]] + branch = "master" + digest = "1:59392ed8afb901aab4287d4894df8191722e34f3957716f4350c8c133ce99046" + name = "github.com/hpcloud/tail" + packages = [ + ".", + "ratelimiter", + "util", + "watch", + "winfile", + ] + pruneopts = "UT" + revision = "a1dbeea552b7c8df4b542c66073e393de198a800" + +[[projects]] + digest = "1:27fa1b385644151ee1fc0c8b04f1f86963d9701335491b94488fd3912e370354" + name = "github.com/mongodb/mongo-go-driver" + packages = [ + "bson", + "bson/bsoncodec", + "bson/bsonrw", + "bson/bsontype", + "bson/primitive", + "event", + "internal", + "mongo", + "mongo/options", + "mongo/readconcern", + "mongo/readpref", + "mongo/writeconcern", + "tag", + "version", + "x/bsonx", + "x/bsonx/bsoncore", + "x/mongo/driver", + "x/mongo/driver/auth", + "x/mongo/driver/auth/internal/gssapi", + "x/mongo/driver/session", + "x/mongo/driver/topology", + "x/mongo/driver/uuid", + "x/network/address", + "x/network/command", + "x/network/compressor", + "x/network/connection", + "x/network/connstring", + "x/network/description", + "x/network/result", + "x/network/wiremessage", + ] + pruneopts = "UT" + revision = "3cfdc9ffcf780eede57d27ec26a3edad4c9ab6a9" + version = "v0.2.0" + +[[projects]] + digest = "1:5f4b78246f0bcb105b1e3b2b9e22b52a57cd02f57a8078572fe27c62f4a75ff7" + name = "github.com/onsi/ginkgo" + packages = [ + ".", + "config", + "internal/codelocation", + "internal/containernode", + "internal/failer", + "internal/leafnodes", + "internal/remote", + "internal/spec", + "internal/spec_iterator", + "internal/specrunner", + "internal/suite", + "internal/testingtproxy", + "internal/writer", + "reporters", + "reporters/stenographer", + "reporters/stenographer/support/go-colorable", + "reporters/stenographer/support/go-isatty", + "types", + ] + pruneopts = "UT" + revision = "2e1be8f7d90e9d3e3e58b0ce470f2f14d075406f" + version = "v1.7.0" + +[[projects]] + digest = "1:7a137fb7718928e473b7d805434ae563ec41790d3d227cdc64e8b14d1cab8a1f" + name = "github.com/onsi/gomega" + packages = [ + ".", + "format", + "internal/assertion", + "internal/asyncassertion", + "internal/oraclematcher", + "internal/testingtsupport", + "matchers", + "matchers/support/goraph/bipartitegraph", + "matchers/support/goraph/edge", + "matchers/support/goraph/node", + "matchers/support/goraph/util", + "types", + ] + pruneopts = "UT" + revision = "65fb64232476ad9046e57c26cd0bff3d3a8dc6cd" + version = "v1.4.3" + +[[projects]] + branch = "master" + digest = "1:525ac3364813b4688df380594e562133e07830dfce0722effda64b37634c13d0" + name = "github.com/streadway/amqp" + packages = ["."] + pruneopts = "UT" + revision = "a314942b2fd9dde7a3f70ba3f1062848ce6eb392" + +[[projects]] + branch = "master" + digest = "1:40fdfd6ab85ca32b6935853bbba35935dcb1d796c8135efd85947566c76e662e" + name = "github.com/xdg/scram" + packages = ["."] + pruneopts = "UT" + revision = "7eeb5667e42c09cb51bf7b7c28aea8c56767da90" + +[[projects]] + branch = "master" + digest = "1:f5c1d04bc09c644c592b45b9f0bad4030521b1a7d11c7dadbb272d9439fa6e8e" + name = "github.com/xdg/stringprep" + packages = ["."] + pruneopts = "UT" + revision = "73f8eece6fdcd902c185bf651de50f3828bed5ed" + +[[projects]] + branch = "master" + digest = "1:f92f6956e4059f6a3efc14924d2dd58ba90da25cc57fe07ae3779ef2f5e0c5f2" + name = "golang.org/x/crypto" + packages = ["pbkdf2"] + pruneopts = "UT" + revision = "b01c7a72566457eb1420261cdafef86638fc3861" + +[[projects]] + branch = "master" + digest = "1:4939e20b972c22cd512abff0bf6ed8fc0e3e86aeb836d016be3323c6a901d99d" + name = "golang.org/x/net" + packages = [ + "html", + "html/atom", + "html/charset", + ] + pruneopts = "UT" + revision = "d26f9f9a57f3fab6a695bec0d84433c2c50f8bbf" + +[[projects]] + branch = "master" + digest = "1:75515eedc0dc2cb0b40372008b616fa2841d831c63eedd403285ff286c593295" + name = "golang.org/x/sync" + packages = ["semaphore"] + pruneopts = "UT" + revision = "37e7f081c4d4c64e13b10787722085407fe5d15f" + +[[projects]] + branch = "master" + digest = "1:aba2486bbebaadd1f62bde3c363ddbd984efade895833d86ed069f586fd9e899" + name = "golang.org/x/sys" + packages = ["unix"] + pruneopts = "UT" + revision = "aca44879d5644da7c5b8ec6a1115e9b6ea6c40d9" + +[[projects]] + digest = "1:4392fcf42d5cf0e3ff78c96b2acf8223d49e4fdc53eb77c99d2f8dfe4680e006" + name = "golang.org/x/text" + packages = [ + "encoding", + "encoding/charmap", + "encoding/htmlindex", + "encoding/internal", + "encoding/internal/identifier", + "encoding/japanese", + "encoding/korean", + "encoding/simplifiedchinese", + "encoding/traditionalchinese", + "encoding/unicode", + "internal/gen", + "internal/tag", + "internal/triegen", + "internal/ucd", + "internal/utf8internal", + "language", + "runes", + "transform", + "unicode/cldr", + "unicode/norm", + ] + pruneopts = "UT" + revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" + version = "v0.3.0" + +[[projects]] + digest = "1:abeb38ade3f32a92943e5be54f55ed6d6e3b6602761d74b4aab4c9dd45c18abd" + name = "gopkg.in/fsnotify/fsnotify.v1" + packages = ["."] + pruneopts = "UT" + revision = "c2828203cd70a50dcccfb2761f8b1f8ceef9a8e9" + version = "v1.4.7" + +[[projects]] + digest = "1:3c839a777de0e6da035c9de900b60cbec463b0a89351192c1ea083eaf9e0fce0" + name = "gopkg.in/tomb.v1" + packages = ["."] + pruneopts = "UT" + revision = "c131134a1947e9afd9cecfe11f4c6dff0732ae58" + +[[projects]] + digest = "1:4d2e5a73dc1500038e504a8d78b986630e3626dc027bc030ba5c75da257cdb96" + name = "gopkg.in/yaml.v2" + packages = ["."] + pruneopts = "UT" + revision = "51d6538a90f86fe93ac480b35f37b2be17fef232" + version = "v2.2.2" + +[solve-meta] + analyzer-name = "dep" + analyzer-version = 1 + input-imports = [ + "github.com/gofrs/uuid", + "github.com/mongodb/mongo-go-driver/bson", + "github.com/mongodb/mongo-go-driver/mongo", + "github.com/mongodb/mongo-go-driver/mongo/options", + "github.com/mongodb/mongo-go-driver/mongo/readconcern", + "github.com/mongodb/mongo-go-driver/mongo/readpref", + "github.com/mongodb/mongo-go-driver/mongo/writeconcern", + "github.com/onsi/ginkgo", + "github.com/onsi/gomega", + "github.com/streadway/amqp", + ] + solver-name = "gps-cdcl" + solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml new file mode 100644 index 00000000..77a73284 --- /dev/null +++ b/Gopkg.toml @@ -0,0 +1,50 @@ +# Gopkg.toml example +# +# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html +# for detailed Gopkg.toml documentation. +# +# required = ["github.com/user/thing/cmd/thing"] +# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] +# +# [[constraint]] +# name = "github.com/user/project" +# version = "1.0.0" +# +# [[constraint]] +# name = "github.com/user/project2" +# branch = "dev" +# source = "github.com/myfork/project2" +# +# [[override]] +# name = "github.com/x/y" +# version = "2.4.0" +# +# [prune] +# non-go = false +# go-tests = true +# unused-packages = true + + +[[constraint]] + name = "github.com/onsi/ginkgo" + version = "1.7.0" + +[[constraint]] + name = "github.com/onsi/gomega" + version = "1.4.3" + +[[constraint]] + branch = "master" + name = "github.com/streadway/amqp" + +[prune] + go-tests = true + unused-packages = true + +[[constraint]] + name = "github.com/gofrs/uuid" + version = "3.2.0" + +[[constraint]] + name = "github.com/mongodb/mongo-go-driver" + version = "0.2.0" diff --git a/cmd/goengine/main.go b/cmd/goengine/main.go index 2f9e1192..0b5aa310 100644 --- a/cmd/goengine/main.go +++ b/cmd/goengine/main.go @@ -1,28 +1,55 @@ package main import ( + "context" "os" + "time" "github.com/hellofresh/goengine" "github.com/hellofresh/goengine/mongodb" "github.com/hellofresh/goengine/rabbit" - "gopkg.in/mgo.v2" + "github.com/mongodb/mongo-go-driver/mongo" + "github.com/mongodb/mongo-go-driver/mongo/options" + "github.com/mongodb/mongo-go-driver/mongo/readconcern" + "github.com/mongodb/mongo-go-driver/mongo/readpref" + "github.com/mongodb/mongo-go-driver/mongo/writeconcern" ) func main() { var streamName goengine.StreamName = "test" mongoDSN := os.Getenv("STORAGE_DSN") + goengine.Log("Connecting to the database", map[string]interface{}{"dsn": mongoDSN}, nil) - session, err := mgo.Dial(mongoDSN) + mongoClient, err := mongo.NewClientWithOptions( + mongoDSN, + options.Client(). + SetAppName("goengine"). + SetReadConcern(readconcern.Linearizable()). + SetReadPreference(readpref.Nearest()). + SetWriteConcern(writeconcern.New(writeconcern.WMajority())), + ) + if err != nil { + goengine.Log("Failed to create new Mongo mongoClient", nil, err) + panic(err) + } + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + err = mongoClient.Connect(ctx) if err != nil { goengine.Log("Failed to connect to Mongo", nil, err) panic(err) } - defer session.Close() - // Optional. Switch the session to a monotonic behavior. - session.SetMode(mgo.Monotonic, true) + defer func() { + ctx, cancel = context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + if err := mongoClient.Disconnect(ctx); err != nil { + goengine.Log("Failed to close connection to Mongo", nil, err) + panic(err) + } + }() goengine.Log("Setting up the registry", nil, nil) registry := goengine.NewInMemoryTypeRegistry() @@ -35,7 +62,7 @@ func main() { bus := rabbit.NewEventBus(brokerDSN, "events", "events") goengine.Log("Setting up the event store", nil, nil) - es := mongodb.NewEventStore(session, registry) + es := mongodb.NewEventStore(mongoClient.Database("event_store"), registry) eventDispatcher := goengine.NewVersionedEventDispatchManager(bus, registry) eventDispatcher.RegisterEventHandler(&RecipeCreated{}, func(event *goengine.DomainMessage) error { @@ -47,7 +74,7 @@ func main() { go eventDispatcher.Listen(stopChannel, false) goengine.Log("Creating a recipe", nil, nil) - aggregateRoot := CreateScenario(streamName) + aggregateRoot := CreateScenario() repository := goengine.NewPublisherRepository(es, bus) repository.Save(aggregateRoot, streamName) @@ -62,7 +89,7 @@ func main() { stopChannel <- true } -func CreateScenario(streamName goengine.StreamName) *Recipe { +func CreateScenario() *Recipe { recipe := NewRecipe("Test Recipe") recipe.Rate(4) return recipe diff --git a/event_store.go b/event_store.go index 84920026..81f43b11 100644 --- a/event_store.go +++ b/event_store.go @@ -4,5 +4,5 @@ type EventStore interface { Append(events *EventStream) error GetEventsFor(streamName StreamName, id string) (*EventStream, error) FromVersion(streamName StreamName, id string, version int) (*EventStream, error) - CountEventsFor(streamName StreamName, id string) (int, error) + CountEventsFor(streamName StreamName, id string) (int64, error) } diff --git a/event_store_test.go b/event_store_test.go index decb9366..e50473f1 100644 --- a/event_store_test.go +++ b/event_store_test.go @@ -46,7 +46,7 @@ var _ = Describe("A Event Store", func() { }) It("should count the events that happened", func() { - Expect(store.CountEventsFor(streamName, aggregateId)).Should(Equal(3)) + Expect(store.CountEventsFor(streamName, aggregateId)).Should(Equal(int64(3))) }) It("should retrieve events for version bigger then 1", func() { diff --git a/inmemory/eventstore.go b/inmemory/eventstore.go index a1184a1c..ab7b6804 100644 --- a/inmemory/eventstore.go +++ b/inmemory/eventstore.go @@ -39,9 +39,9 @@ func (s *InMemoryEventStore) FromVersion(streamName goengine.StreamName, id stri return goengine.NewEventStream(streamName, filtered), nil } -func (s *InMemoryEventStore) CountEventsFor(streamName goengine.StreamName, id string) (int, error) { +func (s *InMemoryEventStore) CountEventsFor(streamName goengine.StreamName, id string) (int64, error) { stream, _ := s.GetEventsFor(streamName, id) - return len(stream.Events), nil + return int64(len(stream.Events)), nil } func (s *InMemoryEventStore) save(streamName goengine.StreamName, event *goengine.DomainMessage) error { diff --git a/mongodb/eventstore.go b/mongodb/eventstore.go index 54555396..5bc47f56 100644 --- a/mongodb/eventstore.go +++ b/mongodb/eventstore.go @@ -1,13 +1,15 @@ package mongodb import ( + "context" "encoding/json" "time" "github.com/hellofresh/goengine" "github.com/hellofresh/goengine/reflection" - "gopkg.in/mgo.v2" - "gopkg.in/mgo.v2/bson" + "github.com/mongodb/mongo-go-driver/bson" + "github.com/mongodb/mongo-go-driver/mongo" + "github.com/mongodb/mongo-go-driver/mongo/options" ) // MongoEvent represents an event on mongodb @@ -19,20 +21,20 @@ type MongoEvent struct { RecordedOn time.Time `bson:"recorded_on"` } -// MongoDbEventStore The mongodb event store -type MongoDbEventStore struct { - conn *mgo.Session - db *mgo.Database +// MongoDBEventStore The mongodb event store +type MongoDBEventStore struct { + mongoDB *mongo.Database + registry goengine.TypeRegistry } // NewEventStore creates new MongoDB based event store -func NewEventStore(conn *mgo.Session, r goengine.TypeRegistry) *MongoDbEventStore { - return &MongoDbEventStore{conn, conn.DB(""), r} +func NewEventStore(mongoDB *mongo.Database, r goengine.TypeRegistry) *MongoDBEventStore { + return &MongoDBEventStore{mongoDB, r} } // Append adds an event to the event store -func (s *MongoDbEventStore) Append(events *goengine.EventStream) error { +func (s *MongoDBEventStore) Append(events *goengine.EventStream) error { streamName := string(events.Name) for _, event := range events.Events { mongoEvent, err := s.toMongoEvent(event) @@ -40,13 +42,16 @@ func (s *MongoDbEventStore) Append(events *goengine.EventStream) error { return err } - coll := s.db.C(streamName) + coll := s.mongoDB.Collection(streamName) err = s.createIndexes(coll) if nil != err { return err } - err = coll.Insert(mongoEvent) + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + _, err = coll.InsertOne(ctx, mongoEvent) + cancel() + if nil != err { return err } @@ -56,10 +61,31 @@ func (s *MongoDbEventStore) Append(events *goengine.EventStream) error { } // GetEventsFor gets events for an id on the specified stream -func (s *MongoDbEventStore) GetEventsFor(streamName goengine.StreamName, id string) (*goengine.EventStream, error) { +func (s *MongoDBEventStore) GetEventsFor(streamName goengine.StreamName, id string) (*goengine.EventStream, error) { var mongoEvents []*MongoEvent - coll := s.db.C(string(streamName)) - err := coll.Find(bson.M{"aggregate_id": id}).All(&mongoEvents) + coll := s.mongoDB.Collection(string(streamName)) + + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + cur, err := coll.Find(ctx, bson.M{"aggregate_id": id}) + if err != nil { + return nil, err + } + + for cur.Next(ctx) { + var mongoEvent *MongoEvent + err := cur.Decode(mongoEvent) + if err != nil { + return nil, err + } + + mongoEvents = append(mongoEvents, mongoEvent) + } + + if err := cur.Err(); err != nil { + return nil, err + } var results []*goengine.DomainMessage for _, mongoEvent := range mongoEvents { @@ -75,16 +101,38 @@ func (s *MongoDbEventStore) GetEventsFor(streamName goengine.StreamName, id stri } // FromVersion gets events for an id and version on the specified stream -func (s *MongoDbEventStore) FromVersion(streamName goengine.StreamName, id string, version int) (*goengine.EventStream, error) { +func (s *MongoDBEventStore) FromVersion(streamName goengine.StreamName, id string, version int) (*goengine.EventStream, error) { var mongoEvents []*MongoEvent - coll := s.db.C(string(streamName)) + coll := s.mongoDB.Collection(string(streamName)) + + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + cur, err := coll.Find( + ctx, + bson.M{ + "aggregate_id": id, + "version": bson.M{"$gte": version}, + }, + options.Find().SetSort("-version"), + ) + if err != nil { + return nil, err + } - err := coll.Find(bson.M{ - "aggregate_id": id, - "version": bson.M{"$gte": version}, - }). - Sort("-version"). - All(&mongoEvents) + for cur.Next(ctx) { + var mongoEvent *MongoEvent + err := cur.Decode(mongoEvent) + if err != nil { + return nil, err + } + + mongoEvents = append(mongoEvents, mongoEvent) + } + + if err := cur.Err(); err != nil { + return nil, err + } var results []*goengine.DomainMessage for _, mongoEvent := range mongoEvents { @@ -100,22 +148,28 @@ func (s *MongoDbEventStore) FromVersion(streamName goengine.StreamName, id strin } // CountEventsFor counts events for an id on the specified stream -func (s *MongoDbEventStore) CountEventsFor(streamName goengine.StreamName, id string) (int, error) { - return s.db.C(string(streamName)).Find(bson.M{"aggregate_id": string(streamName)}).Count() -} +func (s *MongoDBEventStore) CountEventsFor(streamName goengine.StreamName, id string) (int64, error) { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() -func (s *MongoDbEventStore) createIndexes(c *mgo.Collection) error { - index := mgo.Index{ - Key: []string{"aggregate_id", "version"}, - Unique: true, - DropDups: true, - Background: true, - } + return s.mongoDB.Collection(string(streamName)).Count(ctx, bson.M{"aggregate_id": string(streamName)}) +} - return c.EnsureIndex(index) +func (s *MongoDBEventStore) createIndexes(c *mongo.Collection) error { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + _, err := c.Indexes().CreateOne( + ctx, + mongo.IndexModel{ + Keys: []string{"aggregate_id", "version"}, + Options: options.Index().SetUnique(true).SetBackground(true), + }, + ) + return err } -func (s *MongoDbEventStore) toMongoEvent(event *goengine.DomainMessage) (*MongoEvent, error) { +func (s *MongoDBEventStore) toMongoEvent(event *goengine.DomainMessage) (*MongoEvent, error) { serializedPayload, err := json.Marshal(event.Payload) if nil != err { return nil, err @@ -131,7 +185,7 @@ func (s *MongoDbEventStore) toMongoEvent(event *goengine.DomainMessage) (*MongoE }, nil } -func (s *MongoDbEventStore) fromMongoEvent(mongoEvent *MongoEvent) (*goengine.DomainMessage, error) { +func (s *MongoDBEventStore) fromMongoEvent(mongoEvent *MongoEvent) (*goengine.DomainMessage, error) { event, err := s.registry.Get(mongoEvent.Type) if nil != err { return nil, err From aceeab099477fbc9b07cfd55d9bfed38041a2fef Mon Sep 17 00:00:00 2001 From: Vladimir Garvardt Date: Thu, 31 Jan 2019 19:24:46 +0100 Subject: [PATCH 47/74] Fixed tests --- cmd/goengine/main.go | 10 ++++++++-- docker-compose.yml | 11 ++++------- inmemory/eventstore_test.go | 2 +- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/cmd/goengine/main.go b/cmd/goengine/main.go index 0b5aa310..8c9d25d3 100644 --- a/cmd/goengine/main.go +++ b/cmd/goengine/main.go @@ -2,6 +2,7 @@ package main import ( "context" + "errors" "os" "time" @@ -19,6 +20,13 @@ func main() { var streamName goengine.StreamName = "test" mongoDSN := os.Getenv("STORAGE_DSN") + if len(mongoDSN) == 0 { + panic(errors.New("missing STORAGE_DSN environment variable")) + } + brokerDSN := os.Getenv("BROKER_DSN") + if len(mongoDSN) == 0 { + panic(errors.New("missing BROKER_DSN environment variable")) + } goengine.Log("Connecting to the database", map[string]interface{}{"dsn": mongoDSN}, nil) mongoClient, err := mongo.NewClientWithOptions( @@ -56,8 +64,6 @@ func main() { registry.RegisterType(&RecipeCreated{}) registry.RegisterType(&RecipeRated{}) - // bus := inmemory.NewInMemoryEventBus() - brokerDSN := os.Getenv("BROKER_DSN") goengine.Log("Setting up the event bus", map[string]interface{}{"dsn": brokerDSN}, nil) bus := rabbit.NewEventBus(brokerDSN, "events", "events") diff --git a/docker-compose.yml b/docker-compose.yml index 1c847759..1e2bca6b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,15 +2,12 @@ version: '2' services: rabbitmq: - image: rabbitmq:3.6.1-management + image: rabbitmq:3-management-alpine ports: - "15672:15672" - "5672:5672" - - redis: - image: redis mongo: - image: mongo - ports: - - "27017:27017" + image: mongo + ports: + - "27017:27017" diff --git a/inmemory/eventstore_test.go b/inmemory/eventstore_test.go index 07dda2a9..6f45e592 100644 --- a/inmemory/eventstore_test.go +++ b/inmemory/eventstore_test.go @@ -41,7 +41,7 @@ var _ = Describe("In Memory Event Store", func() { }) It("should count the events that happened", func() { - Expect(inMemory.CountEventsFor(streamName, aggregateId)).Should(Equal(4)) + Expect(inMemory.CountEventsFor(streamName, aggregateId)).Should(Equal(int64(4))) }) It("should retrieve events for version bigger then 1", func() { From 77734a9fdbaacc6355b77cedf8192e3ea889daa7 Mon Sep 17 00:00:00 2001 From: Vladimir Garvardt Date: Thu, 31 Jan 2019 21:29:16 +0100 Subject: [PATCH 48/74] Fixed mongo usage --- cmd/goengine/main.go | 24 ++++++++++-------------- cmd/goengine/model.go | 18 +++++++++--------- mongodb/eventstore.go | 15 ++++++++------- 3 files changed, 27 insertions(+), 30 deletions(-) diff --git a/cmd/goengine/main.go b/cmd/goengine/main.go index 8c9d25d3..e54c87a9 100644 --- a/cmd/goengine/main.go +++ b/cmd/goengine/main.go @@ -11,9 +11,6 @@ import ( "github.com/hellofresh/goengine/rabbit" "github.com/mongodb/mongo-go-driver/mongo" "github.com/mongodb/mongo-go-driver/mongo/options" - "github.com/mongodb/mongo-go-driver/mongo/readconcern" - "github.com/mongodb/mongo-go-driver/mongo/readpref" - "github.com/mongodb/mongo-go-driver/mongo/writeconcern" ) func main() { @@ -31,11 +28,7 @@ func main() { goengine.Log("Connecting to the database", map[string]interface{}{"dsn": mongoDSN}, nil) mongoClient, err := mongo.NewClientWithOptions( mongoDSN, - options.Client(). - SetAppName("goengine"). - SetReadConcern(readconcern.Linearizable()). - SetReadPreference(readpref.Nearest()). - SetWriteConcern(writeconcern.New(writeconcern.WMajority())), + options.Client().SetAppName("goengine"), ) if err != nil { goengine.Log("Failed to create new Mongo mongoClient", nil, err) @@ -68,11 +61,11 @@ func main() { bus := rabbit.NewEventBus(brokerDSN, "events", "events") goengine.Log("Setting up the event store", nil, nil) - es := mongodb.NewEventStore(mongoClient.Database("event_store"), registry) + eventStore := mongodb.NewEventStore(mongoClient.Database("event_store"), registry) eventDispatcher := goengine.NewVersionedEventDispatchManager(bus, registry) eventDispatcher.RegisterEventHandler(&RecipeCreated{}, func(event *goengine.DomainMessage) error { - goengine.Log("Event received", nil, nil) + goengine.Log("Event received", map[string]interface{}{"event": event}, nil) return nil }) @@ -82,12 +75,15 @@ func main() { goengine.Log("Creating a recipe", nil, nil) aggregateRoot := CreateScenario() - repository := goengine.NewPublisherRepository(es, bus) - repository.Save(aggregateRoot, streamName) + repository := goengine.NewPublisherRepository(eventStore, bus) + if err := repository.Save(aggregateRoot, streamName); err != nil { + goengine.Log("Failed to save aggregate to stream", nil, err) + panic(err) + } - _, err = NewRecipeFromHisotry(aggregateRoot.ID, streamName, repository) + _, err = NewRecipeFromHistory(aggregateRoot.ID, streamName, repository) if err != nil { - goengine.Log("Failed to connect to Mongo", nil, err) + goengine.Log("Failed get a recipe from history", nil, err) panic(err) } diff --git a/cmd/goengine/model.go b/cmd/goengine/model.go index a03d6465..e3f4e2e6 100644 --- a/cmd/goengine/model.go +++ b/cmd/goengine/model.go @@ -7,21 +7,21 @@ import ( ) type RecipeCreated struct { - ocurredOn time.Time - Name string + occurredOn time.Time + Name string } -func (e RecipeCreated) OcurredOn() time.Time { - return e.ocurredOn +func (e RecipeCreated) OccurredOn() time.Time { + return e.occurredOn } type RecipeRated struct { - ocurredOn time.Time - Rating int + occurredOn time.Time + Rating int } -func (e RecipeRated) OcurredOn() time.Time { - return e.ocurredOn +func (e RecipeRated) OccurredOn() time.Time { + return e.occurredOn } type Recipe struct { @@ -38,7 +38,7 @@ func NewRecipe(name string) *Recipe { return recipe } -func NewRecipeFromHisotry(id string, streamName goengine.StreamName, repo goengine.AggregateRepository) (*Recipe, error) { +func NewRecipeFromHistory(id string, streamName goengine.StreamName, repo goengine.AggregateRepository) (*Recipe, error) { recipe := new(Recipe) recipe.AggregateRootBased = goengine.NewEventSourceBasedWithID(recipe, id) err := repo.Reconstitute(id, recipe, streamName) diff --git a/mongodb/eventstore.go b/mongodb/eventstore.go index 5bc47f56..12d6cb97 100644 --- a/mongodb/eventstore.go +++ b/mongodb/eventstore.go @@ -10,6 +10,7 @@ import ( "github.com/mongodb/mongo-go-driver/bson" "github.com/mongodb/mongo-go-driver/mongo" "github.com/mongodb/mongo-go-driver/mongo/options" + "github.com/mongodb/mongo-go-driver/x/bsonx" ) // MongoEvent represents an event on mongodb @@ -62,7 +63,7 @@ func (s *MongoDBEventStore) Append(events *goengine.EventStream) error { // GetEventsFor gets events for an id on the specified stream func (s *MongoDBEventStore) GetEventsFor(streamName goengine.StreamName, id string) (*goengine.EventStream, error) { - var mongoEvents []*MongoEvent + var mongoEvents []MongoEvent coll := s.mongoDB.Collection(string(streamName)) ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) @@ -74,8 +75,8 @@ func (s *MongoDBEventStore) GetEventsFor(streamName goengine.StreamName, id stri } for cur.Next(ctx) { - var mongoEvent *MongoEvent - err := cur.Decode(mongoEvent) + var mongoEvent MongoEvent + err := cur.Decode(&mongoEvent) if err != nil { return nil, err } @@ -102,7 +103,7 @@ func (s *MongoDBEventStore) GetEventsFor(streamName goengine.StreamName, id stri // FromVersion gets events for an id and version on the specified stream func (s *MongoDBEventStore) FromVersion(streamName goengine.StreamName, id string, version int) (*goengine.EventStream, error) { - var mongoEvents []*MongoEvent + var mongoEvents []MongoEvent coll := s.mongoDB.Collection(string(streamName)) ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) @@ -121,7 +122,7 @@ func (s *MongoDBEventStore) FromVersion(streamName goengine.StreamName, id strin } for cur.Next(ctx) { - var mongoEvent *MongoEvent + var mongoEvent MongoEvent err := cur.Decode(mongoEvent) if err != nil { return nil, err @@ -162,7 +163,7 @@ func (s *MongoDBEventStore) createIndexes(c *mongo.Collection) error { _, err := c.Indexes().CreateOne( ctx, mongo.IndexModel{ - Keys: []string{"aggregate_id", "version"}, + Keys: bsonx.Doc{{"aggregate_id", bsonx.Int32(1)}, {"version", bsonx.Int32(-1)}}, Options: options.Index().SetUnique(true).SetBackground(true), }, ) @@ -185,7 +186,7 @@ func (s *MongoDBEventStore) toMongoEvent(event *goengine.DomainMessage) (*MongoE }, nil } -func (s *MongoDBEventStore) fromMongoEvent(mongoEvent *MongoEvent) (*goengine.DomainMessage, error) { +func (s *MongoDBEventStore) fromMongoEvent(mongoEvent MongoEvent) (*goengine.DomainMessage, error) { event, err := s.registry.Get(mongoEvent.Type) if nil != err { return nil, err From 7eb4de2deeb8bc82fdb80a6531b74f84b5b2c0aa Mon Sep 17 00:00:00 2001 From: Vladimir Garvardt Date: Thu, 31 Jan 2019 21:36:12 +0100 Subject: [PATCH 49/74] Run all tests in CI --- .travis.yml | 13 ++++++++++++- Gopkg.lock | 4 +--- Makefile | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 4 deletions(-) create mode 100644 Makefile diff --git a/.travis.yml b/.travis.yml index ae3c66e6..f8fd6d10 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,9 +9,20 @@ go: - "1.11" - "stable" +env: + - MAKE_TASK=test-unit + - MAKE_TASK=test-integration + +before_install: + - docker-compose up -d + install: - go get -v -d - go get -u github.com/onsi/ginkgo/ginkgo - go get -u github.com/onsi/gomega -script: ginkgo -r +script: + - make $MAKE_TASK + +after_script: + - docker-compose down -v diff --git a/Gopkg.lock b/Gopkg.lock index bd140089..434a2585 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -246,9 +246,7 @@ "github.com/mongodb/mongo-go-driver/bson", "github.com/mongodb/mongo-go-driver/mongo", "github.com/mongodb/mongo-go-driver/mongo/options", - "github.com/mongodb/mongo-go-driver/mongo/readconcern", - "github.com/mongodb/mongo-go-driver/mongo/readpref", - "github.com/mongodb/mongo-go-driver/mongo/writeconcern", + "github.com/mongodb/mongo-go-driver/x/bsonx", "github.com/onsi/ginkgo", "github.com/onsi/gomega", "github.com/streadway/amqp", diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..a68d6cda --- /dev/null +++ b/Makefile @@ -0,0 +1,34 @@ +NO_COLOR=\033[0m +OK_COLOR=\033[32;01m + +format: + @echo "$(OK_COLOR)==> checking code formating with 'gofmt' tool$(NO_COLOR)" + @gofmt -l -s cmd pkg | grep ".*\.go"; if [ "$$?" = "0" ]; then exit 1; fi + +vet: + @echo "$(OK_COLOR)==> checking code correctness with 'go vet' tool$(NO_COLOR)" + @go vet ./... + +lint: tools.golint + @echo "$(OK_COLOR)==> checking code style with 'golint' tool$(NO_COLOR)" + @go list ./... | xargs -n 1 golint -set_exit_status + +test-integration: lint format vet + @echo "$(OK_COLOR)==> Running integration tests$(NO_COLOR)" + @STORAGE_DSN=mongodb://localhost:27017/ BROKER_DSN=amqp://guest:guest@localhost:5672/ go run ./cmd/goengine/... + +test-unit: lint format vet + @echo "$(OK_COLOR)==> Running unit tests$(NO_COLOR)" + @ginkgo -r + +#--------------- +#-- tools +#--------------- + +tools: tools.golint + +tools.golint: + @command -v golint >/dev/null ; if [ $$? -ne 0 ]; then \ + echo "--> installing golint"; \ + go get github.com/golang/lint/golint; \ + fi From b9b08483a9e073640b65f93ad868562d52594b1e Mon Sep 17 00:00:00 2001 From: Vladimir Garvardt Date: Thu, 31 Jan 2019 21:55:59 +0100 Subject: [PATCH 50/74] Adde comment stubs, made nicer naming --- aggregate_repository.go | 12 ++++++++---- aggregate_root.go | 13 +++++++++++-- cmd/goengine/main.go | 4 ++-- cmd/goengine/model.go | 10 ++++++++++ domain_message.go | 5 +++++ errors/type.go | 9 ++++++--- event_store.go | 1 + event_stream.go | 3 +++ inmemory/eventbus.go | 18 ++++++++---------- inmemory/eventstore.go | 22 ++++++++++++++-------- inmemory/eventstore_test.go | 2 +- logging.go | 3 +++ mongodb/eventstore.go | 22 +++++++++++----------- reflection/caller.go | 1 + snapshot/snapshot.go | 1 + type_registry.go | 3 +++ 16 files changed, 88 insertions(+), 41 deletions(-) diff --git a/aggregate_repository.go b/aggregate_repository.go index 25ee4566..59e1bc3f 100644 --- a/aggregate_repository.go +++ b/aggregate_repository.go @@ -1,24 +1,26 @@ package goengine -import ( - "fmt" -) +import "fmt" +// AggregateRepository ... type AggregateRepository interface { Load(string, StreamName) (*EventStream, error) Save(AggregateRoot, StreamName) error Reconstitute(string, AggregateRoot, StreamName) error } +// PublisherRepository ... type PublisherRepository struct { EventStore EventStore EventBus VersionedEventPublisher } +// NewPublisherRepository ... func NewPublisherRepository(eventStore EventStore, eventBus VersionedEventPublisher) *PublisherRepository { return &PublisherRepository{eventStore, eventBus} } +// Load ... func (r *PublisherRepository) Load(id string, streamName StreamName) (*EventStream, error) { Log("Loading events from stream for aggregate", map[string]interface{}{"stream": streamName, "id": id}, nil) stream, err := r.EventStore.GetEventsFor(streamName, id) @@ -29,6 +31,7 @@ func (r *PublisherRepository) Load(id string, streamName StreamName) (*EventStre return stream, nil } +// Save ... func (r *PublisherRepository) Save(aggregateRoot AggregateRoot, streamName StreamName) error { events := aggregateRoot.GetUncommittedEvents() eventStream := NewEventStream(streamName, events) @@ -51,6 +54,7 @@ func (r *PublisherRepository) Save(aggregateRoot AggregateRoot, streamName Strea return nil } +// Reconstitute ... func (r *PublisherRepository) Reconstitute(id string, source AggregateRoot, streamName StreamName) error { Log("Reconstituting aggregate from stream", map[string]interface{}{"stream": streamName, "id": id}, nil) @@ -61,7 +65,7 @@ func (r *PublisherRepository) Reconstitute(id string, source AggregateRoot, stre events := stream.Events if len(events) == 0 { - return fmt.Errorf("No events found for id: %s", id) + return fmt.Errorf("no events found for id: %s", id) } for _, event := range events { diff --git a/aggregate_root.go b/aggregate_root.go index 0adb22b9..edcd3f9b 100644 --- a/aggregate_root.go +++ b/aggregate_root.go @@ -7,6 +7,7 @@ import ( "github.com/hellofresh/goengine/reflection" ) +// AggregateRoot ... type AggregateRoot interface { GetID() string GetVersion() int @@ -15,6 +16,7 @@ type AggregateRoot interface { GetUncommittedEvents() []*DomainMessage } +// AggregateRootBased ... type AggregateRootBased struct { ID string version int @@ -22,28 +24,32 @@ type AggregateRootBased struct { uncommittedEvents []*DomainMessage } -// NewAggregateRootBased constructor +// NewAggregateRootBased ... func NewAggregateRootBased(source interface{}) *AggregateRootBased { return NewEventSourceBasedWithID(source, uuid.Must(uuid.NewV4()).String()) } -// NewEventSourceBasedWithID constructor +// NewEventSourceBasedWithID ... func NewEventSourceBasedWithID(source interface{}, id string) *AggregateRootBased { return &AggregateRootBased{id, 0, source, []*DomainMessage{}} } +// GetID ... func (r *AggregateRootBased) GetID() string { return r.ID } +// GetVersion ... func (r *AggregateRootBased) GetVersion() int { return r.version } +// SetVersion ... func (r *AggregateRootBased) SetVersion(version int) { r.version = version } +// GetUncommittedEvents ... func (r *AggregateRootBased) GetUncommittedEvents() []*DomainMessage { stream := r.uncommittedEvents r.uncommittedEvents = nil @@ -52,6 +58,7 @@ func (r *AggregateRootBased) GetUncommittedEvents() []*DomainMessage { return stream } +// Apply ... func (r *AggregateRootBased) Apply(event DomainEvent) { t := reflection.TypeOf(event) methodName := fmt.Sprintf("When%s", t.Name()) @@ -62,12 +69,14 @@ func (r *AggregateRootBased) Apply(event DomainEvent) { Log("Event applied", fields, nil) } +// RecordThat ... func (r *AggregateRootBased) RecordThat(event DomainEvent) { r.version++ r.Apply(event) r.Record(event) } +// Record ... func (r *AggregateRootBased) Record(event DomainEvent) { message := RecordNow(r.ID, r.version, event) r.uncommittedEvents = append(r.uncommittedEvents, message) diff --git a/cmd/goengine/main.go b/cmd/goengine/main.go index e54c87a9..cc212569 100644 --- a/cmd/goengine/main.go +++ b/cmd/goengine/main.go @@ -73,7 +73,7 @@ func main() { go eventDispatcher.Listen(stopChannel, false) goengine.Log("Creating a recipe", nil, nil) - aggregateRoot := CreateScenario() + aggregateRoot := createScenario() repository := goengine.NewPublisherRepository(eventStore, bus) if err := repository.Save(aggregateRoot, streamName); err != nil { @@ -91,7 +91,7 @@ func main() { stopChannel <- true } -func CreateScenario() *Recipe { +func createScenario() *Recipe { recipe := NewRecipe("Test Recipe") recipe.Rate(4) return recipe diff --git a/cmd/goengine/model.go b/cmd/goengine/model.go index e3f4e2e6..5dbedd42 100644 --- a/cmd/goengine/model.go +++ b/cmd/goengine/model.go @@ -6,30 +6,36 @@ import ( "github.com/hellofresh/goengine" ) +// RecipeCreated ... type RecipeCreated struct { occurredOn time.Time Name string } +// OccurredOn ... func (e RecipeCreated) OccurredOn() time.Time { return e.occurredOn } +// RecipeRated ... type RecipeRated struct { occurredOn time.Time Rating int } +// OccurredOn ... func (e RecipeRated) OccurredOn() time.Time { return e.occurredOn } +// Recipe ... type Recipe struct { *goengine.AggregateRootBased Name string Rating int } +// NewRecipe ... func NewRecipe(name string) *Recipe { recipe := new(Recipe) recipe.AggregateRootBased = goengine.NewAggregateRootBased(recipe) @@ -38,6 +44,7 @@ func NewRecipe(name string) *Recipe { return recipe } +// NewRecipeFromHistory ... func NewRecipeFromHistory(id string, streamName goengine.StreamName, repo goengine.AggregateRepository) (*Recipe, error) { recipe := new(Recipe) recipe.AggregateRootBased = goengine.NewEventSourceBasedWithID(recipe, id) @@ -46,14 +53,17 @@ func NewRecipeFromHistory(id string, streamName goengine.StreamName, repo goengi return recipe, err } +// Rate ... func (r *Recipe) Rate(rate int) { r.RecordThat(&RecipeRated{time.Now(), rate}) } +// WhenRecipeCreated ... func (r *Recipe) WhenRecipeCreated(event *RecipeCreated) { r.Name = event.Name } +// WhenRecipeRated ... func (r *Recipe) WhenRecipeRated(event *RecipeRated) { r.Rating = event.Rating } diff --git a/domain_message.go b/domain_message.go index 3c11d51c..40189c8e 100644 --- a/domain_message.go +++ b/domain_message.go @@ -5,10 +5,12 @@ import ( "time" ) +// DomainEvent ... type DomainEvent interface { OccurredOn() time.Time } +// DomainMessage ... type DomainMessage struct { ID string `json:"aggregate_id,omitempty"` Version int `json:"version"` @@ -16,14 +18,17 @@ type DomainMessage struct { RecordedOn time.Time `json:"recorded_on"` } +// String ... func (dm *DomainMessage) String() string { return fmt.Sprintf("DomainMessage{ ID: %s, Version: %d }", dm.ID, dm.Version) } +// NewDomainMessage ... func NewDomainMessage(id string, version int, payload DomainEvent, recordedOn time.Time) *DomainMessage { return &DomainMessage{id, version, payload, recordedOn} } +// RecordNow ... func RecordNow(id string, version int, payload DomainEvent) *DomainMessage { recordedTime := time.Now() return NewDomainMessage(id, version, payload, recordedTime) diff --git a/errors/type.go b/errors/type.go index 8cf17d52..20b69080 100644 --- a/errors/type.go +++ b/errors/type.go @@ -3,7 +3,10 @@ package errors import "errors" var ( - ErrorTypeNotRegistred = errors.New("The type is not registereds") - ErrorTypeNotStruct = errors.New("Input param is not a struct") - ErrorTypeNotFound = errors.New("The type was not found") + // ErrorTypeNotRegistered ... + ErrorTypeNotRegistered = errors.New("the type is not registered") + // ErrorTypeNotStruct ... + ErrorTypeNotStruct = errors.New("input param is not a struct") + // ErrorTypeNotFound ... + ErrorTypeNotFound = errors.New("the type was not found") ) diff --git a/event_store.go b/event_store.go index 81f43b11..b5570eca 100644 --- a/event_store.go +++ b/event_store.go @@ -1,5 +1,6 @@ package goengine +// EventStore ... type EventStore interface { Append(events *EventStream) error GetEventsFor(streamName StreamName, id string) (*EventStream, error) diff --git a/event_stream.go b/event_stream.go index 1383c10d..de2e8f77 100644 --- a/event_stream.go +++ b/event_stream.go @@ -1,12 +1,15 @@ package goengine +// StreamName ... type StreamName string +// EventStream ... type EventStream struct { Name StreamName Events []*DomainMessage } +// NewEventStream ... func NewEventStream(name StreamName, events []*DomainMessage) *EventStream { return &EventStream{name, events} } diff --git a/inmemory/eventbus.go b/inmemory/eventbus.go index ac9dae50..7349cc17 100644 --- a/inmemory/eventbus.go +++ b/inmemory/eventbus.go @@ -1,23 +1,21 @@ package inmemory -import ( - "github.com/hellofresh/goengine" -) +import "github.com/hellofresh/goengine" -// InMemoryEventBus provides an inmemory implementation of the VersionedEventPublisher VersionedEventReceiver interfaces -type InMemoryEventBus struct { +// EventBus provides an in memory implementation of the VersionedEventPublisher VersionedEventReceiver interfaces +type EventBus struct { publishedEventsChannel chan *goengine.DomainMessage startReceiving bool } -// NewInMemoryEventBus constructor -func NewInMemoryEventBus() *InMemoryEventBus { +// NewEventBus ... +func NewEventBus() *EventBus { publishedEventsChannel := make(chan *goengine.DomainMessage, 0) - return &InMemoryEventBus{publishedEventsChannel, false} + return &EventBus{publishedEventsChannel, false} } // PublishEvents publishes events to the event bus -func (bus *InMemoryEventBus) PublishEvents(events []*goengine.DomainMessage) error { +func (bus *EventBus) PublishEvents(events []*goengine.DomainMessage) error { if !bus.startReceiving { return nil } @@ -30,7 +28,7 @@ func (bus *InMemoryEventBus) PublishEvents(events []*goengine.DomainMessage) err } // ReceiveEvents starts a go routine that monitors incoming events and routes them to a receiver channel specified within the options -func (bus *InMemoryEventBus) ReceiveEvents(options goengine.VersionedEventReceiverOptions) error { +func (bus *EventBus) ReceiveEvents(options goengine.VersionedEventReceiverOptions) error { bus.startReceiving = true go func() { diff --git a/inmemory/eventstore.go b/inmemory/eventstore.go index ab7b6804..c8c26b74 100644 --- a/inmemory/eventstore.go +++ b/inmemory/eventstore.go @@ -2,15 +2,18 @@ package inmemory import "github.com/hellofresh/goengine" -type InMemoryEventStore struct { +// EventStore ... +type EventStore struct { events map[goengine.StreamName]map[string][]*goengine.DomainMessage } -func NewEventStore() *InMemoryEventStore { - return &InMemoryEventStore{make(map[goengine.StreamName]map[string][]*goengine.DomainMessage)} +// NewEventStore ... +func NewEventStore() *EventStore { + return &EventStore{make(map[goengine.StreamName]map[string][]*goengine.DomainMessage)} } -func (s *InMemoryEventStore) Append(events *goengine.EventStream) error { +// Append ... +func (s *EventStore) Append(events *goengine.EventStream) error { name := events.Name for _, event := range events.Events { err := s.save(name, event) @@ -22,11 +25,13 @@ func (s *InMemoryEventStore) Append(events *goengine.EventStream) error { return nil } -func (s *InMemoryEventStore) GetEventsFor(streamName goengine.StreamName, id string) (*goengine.EventStream, error) { +// GetEventsFor ... +func (s *EventStore) GetEventsFor(streamName goengine.StreamName, id string) (*goengine.EventStream, error) { return goengine.NewEventStream(streamName, s.events[streamName][id]), nil } -func (s *InMemoryEventStore) FromVersion(streamName goengine.StreamName, id string, version int) (*goengine.EventStream, error) { +// FromVersion ... +func (s *EventStore) FromVersion(streamName goengine.StreamName, id string, version int) (*goengine.EventStream, error) { events, _ := s.GetEventsFor(streamName, id) var filtered []*goengine.DomainMessage @@ -39,12 +44,13 @@ func (s *InMemoryEventStore) FromVersion(streamName goengine.StreamName, id stri return goengine.NewEventStream(streamName, filtered), nil } -func (s *InMemoryEventStore) CountEventsFor(streamName goengine.StreamName, id string) (int64, error) { +// CountEventsFor ... +func (s *EventStore) CountEventsFor(streamName goengine.StreamName, id string) (int64, error) { stream, _ := s.GetEventsFor(streamName, id) return int64(len(stream.Events)), nil } -func (s *InMemoryEventStore) save(streamName goengine.StreamName, event *goengine.DomainMessage) error { +func (s *EventStore) save(streamName goengine.StreamName, event *goengine.DomainMessage) error { id := event.ID events, exists := s.events[streamName][id] diff --git a/inmemory/eventstore_test.go b/inmemory/eventstore_test.go index 6f45e592..2b568870 100644 --- a/inmemory/eventstore_test.go +++ b/inmemory/eventstore_test.go @@ -10,7 +10,7 @@ import ( var _ = Describe("In Memory Event Store", func() { var events []*DomainMessage - var inMemory *InMemoryEventStore = NewEventStore() + var inMemory *EventStore = NewEventStore() var aggregateId string var streamName StreamName diff --git a/logging.go b/logging.go index 01baea74..3c2231dd 100644 --- a/logging.go +++ b/logging.go @@ -7,6 +7,7 @@ import ( "strings" ) +// LogHandler ... type LogHandler func(msg string, fields map[string]interface{}, err error) var logHandler LogHandler @@ -35,10 +36,12 @@ func init() { }) } +// SetLogHandler ... func SetLogHandler(handler LogHandler) { logHandler = handler } +// Log ... func Log(msg string, fields map[string]interface{}, err error) { logHandler(msg, fields, err) } diff --git a/mongodb/eventstore.go b/mongodb/eventstore.go index 12d6cb97..c69c4c15 100644 --- a/mongodb/eventstore.go +++ b/mongodb/eventstore.go @@ -22,20 +22,20 @@ type MongoEvent struct { RecordedOn time.Time `bson:"recorded_on"` } -// MongoDBEventStore The mongodb event store -type MongoDBEventStore struct { +// EventStore The mongodb event store +type EventStore struct { mongoDB *mongo.Database registry goengine.TypeRegistry } // NewEventStore creates new MongoDB based event store -func NewEventStore(mongoDB *mongo.Database, r goengine.TypeRegistry) *MongoDBEventStore { - return &MongoDBEventStore{mongoDB, r} +func NewEventStore(mongoDB *mongo.Database, r goengine.TypeRegistry) *EventStore { + return &EventStore{mongoDB, r} } // Append adds an event to the event store -func (s *MongoDBEventStore) Append(events *goengine.EventStream) error { +func (s *EventStore) Append(events *goengine.EventStream) error { streamName := string(events.Name) for _, event := range events.Events { mongoEvent, err := s.toMongoEvent(event) @@ -62,7 +62,7 @@ func (s *MongoDBEventStore) Append(events *goengine.EventStream) error { } // GetEventsFor gets events for an id on the specified stream -func (s *MongoDBEventStore) GetEventsFor(streamName goengine.StreamName, id string) (*goengine.EventStream, error) { +func (s *EventStore) GetEventsFor(streamName goengine.StreamName, id string) (*goengine.EventStream, error) { var mongoEvents []MongoEvent coll := s.mongoDB.Collection(string(streamName)) @@ -102,7 +102,7 @@ func (s *MongoDBEventStore) GetEventsFor(streamName goengine.StreamName, id stri } // FromVersion gets events for an id and version on the specified stream -func (s *MongoDBEventStore) FromVersion(streamName goengine.StreamName, id string, version int) (*goengine.EventStream, error) { +func (s *EventStore) FromVersion(streamName goengine.StreamName, id string, version int) (*goengine.EventStream, error) { var mongoEvents []MongoEvent coll := s.mongoDB.Collection(string(streamName)) @@ -149,14 +149,14 @@ func (s *MongoDBEventStore) FromVersion(streamName goengine.StreamName, id strin } // CountEventsFor counts events for an id on the specified stream -func (s *MongoDBEventStore) CountEventsFor(streamName goengine.StreamName, id string) (int64, error) { +func (s *EventStore) CountEventsFor(streamName goengine.StreamName, id string) (int64, error) { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() return s.mongoDB.Collection(string(streamName)).Count(ctx, bson.M{"aggregate_id": string(streamName)}) } -func (s *MongoDBEventStore) createIndexes(c *mongo.Collection) error { +func (s *EventStore) createIndexes(c *mongo.Collection) error { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() @@ -170,7 +170,7 @@ func (s *MongoDBEventStore) createIndexes(c *mongo.Collection) error { return err } -func (s *MongoDBEventStore) toMongoEvent(event *goengine.DomainMessage) (*MongoEvent, error) { +func (s *EventStore) toMongoEvent(event *goengine.DomainMessage) (*MongoEvent, error) { serializedPayload, err := json.Marshal(event.Payload) if nil != err { return nil, err @@ -186,7 +186,7 @@ func (s *MongoDBEventStore) toMongoEvent(event *goengine.DomainMessage) (*MongoE }, nil } -func (s *MongoDBEventStore) fromMongoEvent(mongoEvent MongoEvent) (*goengine.DomainMessage, error) { +func (s *EventStore) fromMongoEvent(mongoEvent MongoEvent) (*goengine.DomainMessage, error) { event, err := s.registry.Get(mongoEvent.Type) if nil != err { return nil, err diff --git a/reflection/caller.go b/reflection/caller.go index 303118d3..adefcb0d 100644 --- a/reflection/caller.go +++ b/reflection/caller.go @@ -2,6 +2,7 @@ package reflection import "reflect" +// CallMethod ... func CallMethod(i interface{}, methodName string, args ...interface{}) interface{} { // check for method on pointer method := reflect.ValueOf(i).MethodByName(methodName) diff --git a/snapshot/snapshot.go b/snapshot/snapshot.go index 282ae403..dfdbda95 100644 --- a/snapshot/snapshot.go +++ b/snapshot/snapshot.go @@ -2,6 +2,7 @@ package snapshot import "time" +// Snapshot ... type Snapshot struct { version int aggregateID string diff --git a/type_registry.go b/type_registry.go index 0beda950..4a82889d 100644 --- a/type_registry.go +++ b/type_registry.go @@ -37,6 +37,7 @@ func (r *InMemoryTypeRegistry) RegisterType(i interface{}) { Log("Type was registered", map[string]interface{}{"type": rawType.String()}, nil) } +// RegisterAggregate ... func (r *InMemoryTypeRegistry) RegisterAggregate(aggregate AggregateRoot, events ...interface{}) { r.RegisterType(aggregate) @@ -48,12 +49,14 @@ func (r *InMemoryTypeRegistry) RegisterAggregate(aggregate AggregateRoot, events Log("Events were registered for aggregate", fields, nil) } +// RegisterEvents ... func (r *InMemoryTypeRegistry) RegisterEvents(events ...interface{}) { for _, event := range events { r.RegisterType(event) } } +// GetTypeByName ... func (r *InMemoryTypeRegistry) GetTypeByName(typeName string) (reflect.Type, bool) { if typeValue, ok := r.types[typeName]; ok { return typeValue, ok From b4c10febf7caa86afa35a47ff471bd7fc287dc57 Mon Sep 17 00:00:00 2001 From: Vladimir Garvardt Date: Thu, 31 Jan 2019 22:45:06 +0100 Subject: [PATCH 51/74] WIll fix format later --- Makefile | 8 ++------ mock_test.go | 2 +- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index a68d6cda..e59b2d40 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,6 @@ NO_COLOR=\033[0m OK_COLOR=\033[32;01m -format: - @echo "$(OK_COLOR)==> checking code formating with 'gofmt' tool$(NO_COLOR)" - @gofmt -l -s cmd pkg | grep ".*\.go"; if [ "$$?" = "0" ]; then exit 1; fi - vet: @echo "$(OK_COLOR)==> checking code correctness with 'go vet' tool$(NO_COLOR)" @go vet ./... @@ -13,11 +9,11 @@ lint: tools.golint @echo "$(OK_COLOR)==> checking code style with 'golint' tool$(NO_COLOR)" @go list ./... | xargs -n 1 golint -set_exit_status -test-integration: lint format vet +test-integration: lint vet @echo "$(OK_COLOR)==> Running integration tests$(NO_COLOR)" @STORAGE_DSN=mongodb://localhost:27017/ BROKER_DSN=amqp://guest:guest@localhost:5672/ go run ./cmd/goengine/... -test-unit: lint format vet +test-unit: lint vet @echo "$(OK_COLOR)==> Running unit tests$(NO_COLOR)" @ginkgo -r diff --git a/mock_test.go b/mock_test.go index 435c454d..bf6685e3 100644 --- a/mock_test.go +++ b/mock_test.go @@ -28,7 +28,7 @@ func (e RecipeCreated) OccurredOn() time.Time { type RecipeRated struct { occurredOn time.Time - Rating int + Rating int } func (e RecipeRated) OccurredOn() time.Time { From 94962463e3c14dc0e9369583709d682d83623fde Mon Sep 17 00:00:00 2001 From: Vladimir Garvardt Date: Thu, 31 Jan 2019 23:10:54 +0100 Subject: [PATCH 52/74] Unit tests are finally working --- aggregate_root_test.go | 2 +- event_store_test.go | 59 --------------------------------- goengine_suite_test.go | 6 ++-- inmemory/eventbus.go | 5 ++- inmemory/eventstore_test.go | 33 +++++++++--------- inmemory/inmemory_suite_test.go | 6 ++-- inmemory/mock_test.go | 6 ++-- mock_test.go | 20 ++--------- mongodb/eventstore.go | 5 ++- 9 files changed, 35 insertions(+), 107 deletions(-) delete mode 100644 event_store_test.go diff --git a/aggregate_root_test.go b/aggregate_root_test.go index e2feb49c..a9fcc221 100644 --- a/aggregate_root_test.go +++ b/aggregate_root_test.go @@ -1,4 +1,4 @@ -package goengine_test +package goengine import ( . "github.com/onsi/ginkgo" diff --git a/event_store_test.go b/event_store_test.go deleted file mode 100644 index e50473f1..00000000 --- a/event_store_test.go +++ /dev/null @@ -1,59 +0,0 @@ -package goengine_test - -import ( - . "github.com/hellofresh/goengine" - "github.com/hellofresh/goengine/inmemory" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" -) - -var _ = Describe("A Event Store", func() { - var eventStream *EventStream - var store EventStore - var aggregateId string - var streamName StreamName - - store = inmemory.NewEventStore() - - BeforeEach(func() { - eventStream = nil - aggregateId = "594fb936-d646-44b5-a152-84eb4f709f20" - streamName = "test" - }) - - JustBeforeEach(func() { - var events []*DomainMessage - - events = append(events, RecordNow(aggregateId, 0, NewSomethingHappened())) - events = append(events, RecordNow(aggregateId, 1, NewSomethingHappened())) - events = append(events, RecordNow(aggregateId, 2, NewSomethingHappened())) - - eventStream = NewEventStream(streamName, events) - }) - - Describe("when something happens", func() { - It("should save an event", func() { - err := store.Append(eventStream) - Expect(err).To(BeNil()) - }) - - It("should retrive the things that happened", func() { - expectedEvents, err := store.GetEventsFor(streamName, aggregateId) - - Expect(err).To(BeNil()) - Expect(expectedEvents.Events).To(HaveLen(3)) - }) - - It("should count the events that happened", func() { - Expect(store.CountEventsFor(streamName, aggregateId)).Should(Equal(int64(3))) - }) - - It("should retrieve events for version bigger then 1", func() { - expectedEvents, err := store.FromVersion(streamName, aggregateId, 1) - - Expect(err).To(BeNil()) - Expect(expectedEvents.Events).To(HaveLen(2)) - }) - }) -}) diff --git a/goengine_suite_test.go b/goengine_suite_test.go index e1155648..d5154e4e 100644 --- a/goengine_suite_test.go +++ b/goengine_suite_test.go @@ -1,10 +1,10 @@ -package goengine_test +package goengine import ( + "testing" + . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - - "testing" ) func TestGoengine(t *testing.T) { diff --git a/inmemory/eventbus.go b/inmemory/eventbus.go index 7349cc17..4aac8126 100644 --- a/inmemory/eventbus.go +++ b/inmemory/eventbus.go @@ -38,7 +38,10 @@ func (bus *EventBus) ReceiveEvents(options goengine.VersionedEventReceiverOption ch <- nil case versionedEvent := <-bus.publishedEventsChannel: ackCh := make(chan bool) - options.ReceiveEvent <- goengine.VersionedEventTransactedAccept{versionedEvent, ackCh} + options.ReceiveEvent <- goengine.VersionedEventTransactedAccept{ + Event: versionedEvent, + ProcessedSuccessfully: ackCh, + } <-ackCh } } diff --git a/inmemory/eventstore_test.go b/inmemory/eventstore_test.go index 2b568870..06bcb84c 100644 --- a/inmemory/eventstore_test.go +++ b/inmemory/eventstore_test.go @@ -1,51 +1,50 @@ -package inmemory_test +package inmemory import ( - . "github.com/hellofresh/goengine" - . "github.com/hellofresh/goengine/inmemory" + "github.com/hellofresh/goengine" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) var _ = Describe("In Memory Event Store", func() { - var events []*DomainMessage - var inMemory *EventStore = NewEventStore() - var aggregateId string - var streamName StreamName + var events []*goengine.DomainMessage + var inMemory goengine.EventStore = NewEventStore() + var aggregateID string + var streamName goengine.StreamName BeforeEach(func() { events = nil // clear the slice before each execution - aggregateId = "eca7741f-b4c2-4fec-bfc7-be438a794be9" //uuid.New() + aggregateID = "eca7741f-b4c2-4fec-bfc7-be438a794be9" //uuid.New() streamName = "test" }) JustBeforeEach(func() { - events = append(events, RecordNow(aggregateId, 0, NewSomethingHappened())) - events = append(events, RecordNow(aggregateId, 1, NewSomethingHappened())) - events = append(events, RecordNow(aggregateId, 2, NewSomethingHappened())) - events = append(events, RecordNow(aggregateId, 3, NewSomethingHappened())) + events = append(events, goengine.RecordNow(aggregateID, 0, NewSomethingHappened())) + events = append(events, goengine.RecordNow(aggregateID, 1, NewSomethingHappened())) + events = append(events, goengine.RecordNow(aggregateID, 2, NewSomethingHappened())) + events = append(events, goengine.RecordNow(aggregateID, 3, NewSomethingHappened())) }) Describe("when something happens", func() { It("should save an event", func() { - err := inMemory.Append(NewEventStream(streamName, events)) + err := inMemory.Append(goengine.NewEventStream(streamName, events)) Expect(err).To(BeNil()) }) - It("should retrive the things that happened", func() { - stream, err := inMemory.GetEventsFor(streamName, aggregateId) + It("should retrieve the things that happened", func() { + stream, err := inMemory.GetEventsFor(streamName, aggregateID) Expect(err).To(BeNil()) Expect(stream.Events).To(HaveLen(4)) }) It("should count the events that happened", func() { - Expect(inMemory.CountEventsFor(streamName, aggregateId)).Should(Equal(int64(4))) + Expect(inMemory.CountEventsFor(streamName, aggregateID)).Should(Equal(int64(4))) }) It("should retrieve events for version bigger then 1", func() { - stream, err := inMemory.FromVersion(streamName, aggregateId, 1) + stream, err := inMemory.FromVersion(streamName, aggregateID, 1) Expect(err).To(BeNil()) Expect(stream.Events).To(HaveLen(3)) diff --git a/inmemory/inmemory_suite_test.go b/inmemory/inmemory_suite_test.go index 7fc228ea..a939e048 100644 --- a/inmemory/inmemory_suite_test.go +++ b/inmemory/inmemory_suite_test.go @@ -1,10 +1,10 @@ -package inmemory_test +package inmemory import ( + "testing" + . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - - "testing" ) func TestGoengine(t *testing.T) { diff --git a/inmemory/mock_test.go b/inmemory/mock_test.go index ede0fe0b..a7e4306c 100644 --- a/inmemory/mock_test.go +++ b/inmemory/mock_test.go @@ -1,8 +1,6 @@ -package inmemory_test +package inmemory -import ( - "time" -) +import "time" type SomethingHappened struct { occurredOn time.Time diff --git a/mock_test.go b/mock_test.go index bf6685e3..f5b8e373 100644 --- a/mock_test.go +++ b/mock_test.go @@ -1,22 +1,6 @@ -package goengine_test +package goengine -import ( - "time" - - . "github.com/hellofresh/goengine" -) - -type SomethingHappened struct { - occurredOn time.Time -} - -func NewSomethingHappened() SomethingHappened { - return SomethingHappened{time.Now()} -} - -func (e SomethingHappened) OccurredOn() time.Time { - return e.occurredOn -} +import "time" type RecipeCreated struct { occurredOn time.Time diff --git a/mongodb/eventstore.go b/mongodb/eventstore.go index c69c4c15..dc54bf13 100644 --- a/mongodb/eventstore.go +++ b/mongodb/eventstore.go @@ -163,7 +163,10 @@ func (s *EventStore) createIndexes(c *mongo.Collection) error { _, err := c.Indexes().CreateOne( ctx, mongo.IndexModel{ - Keys: bsonx.Doc{{"aggregate_id", bsonx.Int32(1)}, {"version", bsonx.Int32(-1)}}, + Keys: bsonx.Doc{ + {Key: "aggregate_id", Value: bsonx.Int32(1)}, + {Key: "version", Value: bsonx.Int32(-1)}, + }, Options: options.Index().SetUnique(true).SetBackground(true), }, ) From 10e2468851404c61a1c4a909142e651a4b35e67a Mon Sep 17 00:00:00 2001 From: Vladimir Garvardt Date: Thu, 31 Jan 2019 23:15:22 +0100 Subject: [PATCH 53/74] Trying to fix integration tests runner in Travis --- Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e59b2d40..267377a8 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,8 @@ NO_COLOR=\033[0m OK_COLOR=\033[32;01m +PKG_SRC := github.com/hellofresh/goengine + vet: @echo "$(OK_COLOR)==> checking code correctness with 'go vet' tool$(NO_COLOR)" @go vet ./... @@ -11,7 +13,7 @@ lint: tools.golint test-integration: lint vet @echo "$(OK_COLOR)==> Running integration tests$(NO_COLOR)" - @STORAGE_DSN=mongodb://localhost:27017/ BROKER_DSN=amqp://guest:guest@localhost:5672/ go run ./cmd/goengine/... + @STORAGE_DSN=mongodb://localhost:27017/ BROKER_DSN=amqp://guest:guest@localhost:5672/ go run $(PKG_SRC)/cmd/goengine/... test-unit: lint vet @echo "$(OK_COLOR)==> Running unit tests$(NO_COLOR)" From 7f7e13a5bf19ae280bbd02d4f04501634f28fbe7 Mon Sep 17 00:00:00 2001 From: Vladimir Garvardt Date: Thu, 31 Jan 2019 23:23:35 +0100 Subject: [PATCH 54/74] Install dependencies with godep --- .travis.yml | 4 +--- Makefile | 6 ++++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index f8fd6d10..972b92d5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,9 +17,7 @@ before_install: - docker-compose up -d install: - - go get -v -d - - go get -u github.com/onsi/ginkgo/ginkgo - - go get -u github.com/onsi/gomega + - make deps script: - make $MAKE_TASK diff --git a/Makefile b/Makefile index 267377a8..b6a49c5f 100644 --- a/Makefile +++ b/Makefile @@ -3,6 +3,12 @@ OK_COLOR=\033[32;01m PKG_SRC := github.com/hellofresh/goengine +deps: + @echo "$(OK_COLOR)==> Installing dependencies$(NO_COLOR)" + @go get -u github.com/onsi/ginkgo/ginkgo + @go get -u github.com/onsi/gomega + @dep ensure -v -vendor-only + vet: @echo "$(OK_COLOR)==> checking code correctness with 'go vet' tool$(NO_COLOR)" @go vet ./... From c18c3bcb83db83cb0b8568001fc98d5035e9ccbe Mon Sep 17 00:00:00 2001 From: Vladimir Garvardt Date: Thu, 31 Jan 2019 23:27:00 +0100 Subject: [PATCH 55/74] No more go 1.9 --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 972b92d5..618b3f87 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,6 @@ services: - docker go: - - "1.9" - "1.10" - "1.11" - "stable" From 9e6db36843cf33a2b7c709cd9a10c6dc25aad960 Mon Sep 17 00:00:00 2001 From: Vladimir Garvardt Date: Thu, 31 Jan 2019 23:39:14 +0100 Subject: [PATCH 56/74] Forgotten godep dependency to install dependencies while installing dependencies with godep --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index b6a49c5f..4138ad5b 100644 --- a/Makefile +++ b/Makefile @@ -5,6 +5,7 @@ PKG_SRC := github.com/hellofresh/goengine deps: @echo "$(OK_COLOR)==> Installing dependencies$(NO_COLOR)" + @go get -u github.com/golang/dep/cmd/dep @go get -u github.com/onsi/ginkgo/ginkgo @go get -u github.com/onsi/gomega @dep ensure -v -vendor-only From d60bc905b521971f5cc1039cf1a5f225aed40e3b Mon Sep 17 00:00:00 2001 From: Vladimir Garvardt Date: Thu, 31 Jan 2019 23:44:33 +0100 Subject: [PATCH 57/74] Screw go1.10 as well --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 618b3f87..952cda92 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,6 @@ services: - docker go: - - "1.10" - "1.11" - "stable" From 6aa1ebe2ec8c770b14d207f40f2d50964e088e09 Mon Sep 17 00:00:00 2001 From: Vladimir Garvardt Date: Fri, 1 Feb 2019 14:56:15 +0100 Subject: [PATCH 58/74] Added configurable context --- goengine_suite_test.go | 2 + mongodb/context_strategy.go | 144 ++++++++++++++++++++++++++++++++++ mongodb/eventstore.go | 34 +++++--- mongodb/mongodb_suite_test.go | 13 +++ mongodb/options.go | 18 +++++ mongodb/options_test.go | 63 +++++++++++++++ 6 files changed, 262 insertions(+), 12 deletions(-) create mode 100644 mongodb/context_strategy.go create mode 100644 mongodb/mongodb_suite_test.go create mode 100644 mongodb/options.go create mode 100644 mongodb/options_test.go diff --git a/goengine_suite_test.go b/goengine_suite_test.go index d5154e4e..2dc43e6e 100644 --- a/goengine_suite_test.go +++ b/goengine_suite_test.go @@ -8,6 +8,8 @@ import ( ) func TestGoengine(t *testing.T) { + SetLogHandler(func(msg string, fields map[string]interface{}, err error) {}) + RegisterFailHandler(Fail) RunSpecs(t, "GO Engine Suite") } diff --git a/mongodb/context_strategy.go b/mongodb/context_strategy.go new file mode 100644 index 00000000..abf7f565 --- /dev/null +++ b/mongodb/context_strategy.go @@ -0,0 +1,144 @@ +package mongodb + +import ( + "context" + "time" +) + +// ContextStrategy is an interface that represents strategy for providing contexts for running MongoDB requests +type ContextStrategy interface { + // Append is the context used for EventStore.Append() calls + Append() (context.Context, context.CancelFunc) + // GetEventsFor is the context used for EventStore.GetEventsFor() calls + GetEventsFor() (context.Context, context.CancelFunc) + // FromVersion is the context used for EventStore.FromVersion() calls + FromVersion() (context.Context, context.CancelFunc) + // CountEventsFor is the context used for EventStore.CountEventsFor() calls + CountEventsFor() (context.Context, context.CancelFunc) + // CreateIndices is the context used for MongoDB EventStore implementation indices creation + CreateIndices() (context.Context, context.CancelFunc) +} + +// BackgroundContextStrategy is the ContextStrategy implementation that always returns Background context and noop cancel +type BackgroundContextStrategy struct { + ctx context.Context +} + +// NewBackgroundContextStrategy instantiates new BackgroundContextStrategy +func NewBackgroundContextStrategy() *BackgroundContextStrategy { + return &BackgroundContextStrategy{ctx: context.Background()} +} + +// Append is the context used for EventStore.Append() calls +func (s *BackgroundContextStrategy) Append() (context.Context, context.CancelFunc) { + return s.ctx, func() {} +} + +// GetEventsFor is the context used for EventStore.GetEventsFor() calls +func (s *BackgroundContextStrategy) GetEventsFor() (context.Context, context.CancelFunc) { + return s.ctx, func() {} +} + +// FromVersion is the context used for EventStore.FromVersion() calls +func (s *BackgroundContextStrategy) FromVersion() (context.Context, context.CancelFunc) { + return s.ctx, func() {} +} + +// CountEventsFor is the context used for EventStore.CountEventsFor() calls +func (s *BackgroundContextStrategy) CountEventsFor() (context.Context, context.CancelFunc) { + return s.ctx, func() {} +} + +// CreateIndices is the context used for MongoDB EventStore implementation indices creation +func (s *BackgroundContextStrategy) CreateIndices() (context.Context, context.CancelFunc) { + return s.ctx, func() {} +} + +// TimeoutContextStrategy is the ContextStrategy implementation that returns configurable WithTimeout context and its cancel +type TimeoutContextStrategy struct { + append time.Duration + getEventsFor time.Duration + fromVersion time.Duration + countEventsFor time.Duration + createIndices time.Duration +} + +// TimeoutContextStrategyOption is the options type to configure TimeoutContextStrategy creation +type TimeoutContextStrategyOption func(s *TimeoutContextStrategy) + +// NewTimeoutContextStrategy instantiates new TimeoutContextStrategy +func NewTimeoutContextStrategy(options ...TimeoutContextStrategyOption) *TimeoutContextStrategy { + s := &TimeoutContextStrategy{ + append: 5 * time.Second, + getEventsFor: 30 * time.Second, + fromVersion: 30 * time.Second, + countEventsFor: 5 * time.Second, + createIndices: 5 * time.Second, + } + + for _, o := range options { + o(s) + } + + return s +} + +// Append is the context used for EventStore.Append() calls +func (s *TimeoutContextStrategy) Append() (context.Context, context.CancelFunc) { + return context.WithTimeout(context.Background(), s.append) +} + +// GetEventsFor is the context used for EventStore.GetEventsFor() calls +func (s *TimeoutContextStrategy) GetEventsFor() (context.Context, context.CancelFunc) { + return context.WithTimeout(context.Background(), s.getEventsFor) +} + +// FromVersion is the context used for EventStore.FromVersion() calls +func (s *TimeoutContextStrategy) FromVersion() (context.Context, context.CancelFunc) { + return context.WithTimeout(context.Background(), s.fromVersion) +} + +// CountEventsFor is the context used for EventStore.CountEventsFor() calls +func (s *TimeoutContextStrategy) CountEventsFor() (context.Context, context.CancelFunc) { + return context.WithTimeout(context.Background(), s.countEventsFor) +} + +// CreateIndices is the context used for MongoDB EventStore implementation indices creation +func (s *TimeoutContextStrategy) CreateIndices() (context.Context, context.CancelFunc) { + return context.WithTimeout(context.Background(), s.createIndices) +} + +// NewAppendTimeout is the TimeoutContextStrategy configuration option to set a timeout for Append call +func NewAppendTimeout(timeout time.Duration) TimeoutContextStrategyOption { + return func(s *TimeoutContextStrategy) { + s.append = timeout + } +} + +// NewGetEventsForTimeout is the TimeoutContextStrategy configuration option to set a timeout for GetEventsFor call +func NewGetEventsForTimeout(timeout time.Duration) TimeoutContextStrategyOption { + return func(s *TimeoutContextStrategy) { + s.getEventsFor = timeout + } +} + +// NewFromVersionTimeout is the TimeoutContextStrategy configuration option to set a timeout for FromVersion call +func NewFromVersionTimeout(timeout time.Duration) TimeoutContextStrategyOption { + return func(s *TimeoutContextStrategy) { + s.fromVersion = timeout + } +} + +// NewCountEventsForTimeout is the TimeoutContextStrategy configuration option to set a timeout for CountEventsFor call +func NewCountEventsForTimeout(timeout time.Duration) TimeoutContextStrategyOption { + return func(s *TimeoutContextStrategy) { + s.countEventsFor = timeout + } +} + +// NewCreateIndicesTimeout is the TimeoutContextStrategy configuration option to set a timeout for CreateIndices call +func NewCreateIndicesTimeout(timeout time.Duration) TimeoutContextStrategyOption { + return func(s *TimeoutContextStrategy) { + s.createIndices = timeout + } +} diff --git a/mongodb/eventstore.go b/mongodb/eventstore.go index dc54bf13..2b260b32 100644 --- a/mongodb/eventstore.go +++ b/mongodb/eventstore.go @@ -1,7 +1,6 @@ package mongodb import ( - "context" "encoding/json" "time" @@ -24,14 +23,25 @@ type MongoEvent struct { // EventStore The mongodb event store type EventStore struct { - mongoDB *mongo.Database - + mongoDB *mongo.Database registry goengine.TypeRegistry + + cs ContextStrategy } // NewEventStore creates new MongoDB based event store -func NewEventStore(mongoDB *mongo.Database, r goengine.TypeRegistry) *EventStore { - return &EventStore{mongoDB, r} +func NewEventStore(mongoDB *mongo.Database, registry goengine.TypeRegistry, options ...Option) *EventStore { + es := &EventStore{ + mongoDB: mongoDB, + registry: registry, + cs: NewBackgroundContextStrategy(), + } + + for _, o := range options { + o(es) + } + + return es } // Append adds an event to the event store @@ -44,12 +54,12 @@ func (s *EventStore) Append(events *goengine.EventStream) error { } coll := s.mongoDB.Collection(streamName) - err = s.createIndexes(coll) + err = s.createIndices(coll) if nil != err { return err } - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + ctx, cancel := s.cs.Append() _, err = coll.InsertOne(ctx, mongoEvent) cancel() @@ -66,7 +76,7 @@ func (s *EventStore) GetEventsFor(streamName goengine.StreamName, id string) (*g var mongoEvents []MongoEvent coll := s.mongoDB.Collection(string(streamName)) - ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + ctx, cancel := s.cs.GetEventsFor() defer cancel() cur, err := coll.Find(ctx, bson.M{"aggregate_id": id}) @@ -106,7 +116,7 @@ func (s *EventStore) FromVersion(streamName goengine.StreamName, id string, vers var mongoEvents []MongoEvent coll := s.mongoDB.Collection(string(streamName)) - ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + ctx, cancel := s.cs.FromVersion() defer cancel() cur, err := coll.Find( @@ -150,14 +160,14 @@ func (s *EventStore) FromVersion(streamName goengine.StreamName, id string, vers // CountEventsFor counts events for an id on the specified stream func (s *EventStore) CountEventsFor(streamName goengine.StreamName, id string) (int64, error) { - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + ctx, cancel := s.cs.CountEventsFor() defer cancel() return s.mongoDB.Collection(string(streamName)).Count(ctx, bson.M{"aggregate_id": string(streamName)}) } -func (s *EventStore) createIndexes(c *mongo.Collection) error { - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) +func (s *EventStore) createIndices(c *mongo.Collection) error { + ctx, cancel := s.cs.CreateIndices() defer cancel() _, err := c.Indexes().CreateOne( diff --git a/mongodb/mongodb_suite_test.go b/mongodb/mongodb_suite_test.go new file mode 100644 index 00000000..92510df7 --- /dev/null +++ b/mongodb/mongodb_suite_test.go @@ -0,0 +1,13 @@ +package mongodb + +import ( + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +func TestGoengine(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "MongoDB EventStore Suite") +} diff --git a/mongodb/options.go b/mongodb/options.go new file mode 100644 index 00000000..0679e516 --- /dev/null +++ b/mongodb/options.go @@ -0,0 +1,18 @@ +package mongodb + +// Option is the options type to configure MongoDB EventStore implementation creation +type Option func(eventStore *EventStore) + +// ContextBackground sets Context Strategy for EventStore to BackgroundContextStrategy +func ContextBackground() Option { + return func(eventStore *EventStore) { + eventStore.cs = NewBackgroundContextStrategy() + } +} + +// ContextTimeout sets Context Strategy for EventStore to TimeoutContextStrategy +func ContextTimeout(options ...TimeoutContextStrategyOption) Option { + return func(eventStore *EventStore) { + eventStore.cs = NewTimeoutContextStrategy(options...) + } +} diff --git a/mongodb/options_test.go b/mongodb/options_test.go new file mode 100644 index 00000000..d0c01b96 --- /dev/null +++ b/mongodb/options_test.go @@ -0,0 +1,63 @@ +package mongodb + +import ( + "math/rand" + "time" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("MongoDB Event Store Context Background", func() { + Describe("when I use ContextBackground option", func() { + es := NewEventStore(nil, nil, ContextBackground()) + + It("should have BackgroundContextStrategy context strategy", func() { + Expect(es.cs).Should(BeAssignableToTypeOf(NewBackgroundContextStrategy())) + }) + }) +}) + +var _ = Describe("MongoDB Event Store Context Timeout", func() { + Describe("when I use ContextTimeout option", func() { + es := NewEventStore(nil, nil, ContextTimeout()) + + It("should have TimeoutContextStrategy context strategy with some predefined values", func() { + Expect(es.cs).Should(BeAssignableToTypeOf(NewTimeoutContextStrategy())) + + csTimeout, _ := es.cs.(*TimeoutContextStrategy) + Expect(csTimeout.append).Should(BeNumerically(">", 0)) + Expect(csTimeout.getEventsFor).Should(BeNumerically(">", 0)) + Expect(csTimeout.fromVersion).Should(BeNumerically(">", 0)) + Expect(csTimeout.countEventsFor).Should(BeNumerically(">", 0)) + Expect(csTimeout.createIndices).Should(BeNumerically(">", 0)) + }) + }) + + Describe("when I use ContextTimeout option with creation options", func() { + appendTimeout := rand.Uint64() + getEventsFor := rand.Uint64() + fromVersion := rand.Uint64() + countEventsFor := rand.Uint64() + createIndices := rand.Uint64() + + es := NewEventStore(nil, nil, ContextTimeout( + NewAppendTimeout(time.Duration(appendTimeout)), + NewGetEventsForTimeout(time.Duration(getEventsFor)), + NewFromVersionTimeout(time.Duration(fromVersion)), + NewCountEventsForTimeout(time.Duration(countEventsFor)), + NewCreateIndicesTimeout(time.Duration(createIndices)), + )) + + It("should have all the timeouts set respectively", func() { + Expect(es.cs).Should(BeAssignableToTypeOf(NewTimeoutContextStrategy())) + + csTimeout, _ := es.cs.(*TimeoutContextStrategy) + Expect(csTimeout.append).Should(BeEquivalentTo(appendTimeout)) + Expect(csTimeout.getEventsFor).Should(BeEquivalentTo(getEventsFor)) + Expect(csTimeout.fromVersion).Should(BeEquivalentTo(fromVersion)) + Expect(csTimeout.countEventsFor).Should(BeEquivalentTo(countEventsFor)) + Expect(csTimeout.createIndices).Should(BeEquivalentTo(createIndices)) + }) + }) +}) From 72495b0e66afb93a1b4fec69c2281646936561ac Mon Sep 17 00:00:00 2001 From: Vladimir Garvardt Date: Tue, 12 Feb 2019 11:23:48 +0100 Subject: [PATCH 59/74] Improved interface comments --- mongodb/context_strategy.go | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/mongodb/context_strategy.go b/mongodb/context_strategy.go index abf7f565..7c65248c 100644 --- a/mongodb/context_strategy.go +++ b/mongodb/context_strategy.go @@ -5,17 +5,13 @@ import ( "time" ) -// ContextStrategy is an interface that represents strategy for providing contexts for running MongoDB requests +// ContextStrategy is an interface that represents strategy for providing contexts for corresponding MongoDB EventStore +// instance queries to MongoDB type ContextStrategy interface { - // Append is the context used for EventStore.Append() calls Append() (context.Context, context.CancelFunc) - // GetEventsFor is the context used for EventStore.GetEventsFor() calls GetEventsFor() (context.Context, context.CancelFunc) - // FromVersion is the context used for EventStore.FromVersion() calls FromVersion() (context.Context, context.CancelFunc) - // CountEventsFor is the context used for EventStore.CountEventsFor() calls CountEventsFor() (context.Context, context.CancelFunc) - // CreateIndices is the context used for MongoDB EventStore implementation indices creation CreateIndices() (context.Context, context.CancelFunc) } @@ -29,27 +25,27 @@ func NewBackgroundContextStrategy() *BackgroundContextStrategy { return &BackgroundContextStrategy{ctx: context.Background()} } -// Append is the context used for EventStore.Append() calls +// Append is the ContextStrategy.Append() implementation func (s *BackgroundContextStrategy) Append() (context.Context, context.CancelFunc) { return s.ctx, func() {} } -// GetEventsFor is the context used for EventStore.GetEventsFor() calls +// GetEventsFor is the ContextStrategy.GetEventsFor() implementation func (s *BackgroundContextStrategy) GetEventsFor() (context.Context, context.CancelFunc) { return s.ctx, func() {} } -// FromVersion is the context used for EventStore.FromVersion() calls +// FromVersion is the ContextStrategy.FromVersion() implementation func (s *BackgroundContextStrategy) FromVersion() (context.Context, context.CancelFunc) { return s.ctx, func() {} } -// CountEventsFor is the context used for EventStore.CountEventsFor() calls +// CountEventsFor is the ContextStrategy.CountEventsFor() implementation func (s *BackgroundContextStrategy) CountEventsFor() (context.Context, context.CancelFunc) { return s.ctx, func() {} } -// CreateIndices is the context used for MongoDB EventStore implementation indices creation +// CreateIndices is the ContextStrategy.CreateIndices() implementation func (s *BackgroundContextStrategy) CreateIndices() (context.Context, context.CancelFunc) { return s.ctx, func() {} } @@ -83,27 +79,27 @@ func NewTimeoutContextStrategy(options ...TimeoutContextStrategyOption) *Timeout return s } -// Append is the context used for EventStore.Append() calls +// Append is the ContextStrategy.Append() implementation func (s *TimeoutContextStrategy) Append() (context.Context, context.CancelFunc) { return context.WithTimeout(context.Background(), s.append) } -// GetEventsFor is the context used for EventStore.GetEventsFor() calls +// GetEventsFor is the ContextStrategy.GetEventsFor() implementation func (s *TimeoutContextStrategy) GetEventsFor() (context.Context, context.CancelFunc) { return context.WithTimeout(context.Background(), s.getEventsFor) } -// FromVersion is the context used for EventStore.FromVersion() calls +// FromVersion is the ContextStrategy.FromVersion() implementation func (s *TimeoutContextStrategy) FromVersion() (context.Context, context.CancelFunc) { return context.WithTimeout(context.Background(), s.fromVersion) } -// CountEventsFor is the context used for EventStore.CountEventsFor() calls +// CountEventsFor is the ContextStrategy.CountEventsFor() implementation func (s *TimeoutContextStrategy) CountEventsFor() (context.Context, context.CancelFunc) { return context.WithTimeout(context.Background(), s.countEventsFor) } -// CreateIndices is the context used for MongoDB EventStore implementation indices creation +// CreateIndices is the ContextStrategy.CreateIndices() implementation func (s *TimeoutContextStrategy) CreateIndices() (context.Context, context.CancelFunc) { return context.WithTimeout(context.Background(), s.createIndices) } From 543a24c5a197843b4bf35d9c8c85c298099309d3 Mon Sep 17 00:00:00 2001 From: Vladimir Garvardt Date: Tue, 19 Feb 2019 17:36:46 +0100 Subject: [PATCH 60/74] Use the current latest mongo driver --- Gopkg.lock | 6 +++--- Gopkg.toml | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 434a2585..c014e0a7 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -40,7 +40,7 @@ revision = "a1dbeea552b7c8df4b542c66073e393de198a800" [[projects]] - digest = "1:27fa1b385644151ee1fc0c8b04f1f86963d9701335491b94488fd3912e370354" + digest = "1:9be9701967c831fb40a4b8b35c474b0a6e3af1f68ac35ad5fde6c44d71cbf4d1" name = "github.com/mongodb/mongo-go-driver" packages = [ "bson", @@ -75,8 +75,8 @@ "x/network/wiremessage", ] pruneopts = "UT" - revision = "3cfdc9ffcf780eede57d27ec26a3edad4c9ab6a9" - version = "v0.2.0" + revision = "e1f3d104525e687eda76125707c9852e429f2730" + version = "v0.3.0" [[projects]] digest = "1:5f4b78246f0bcb105b1e3b2b9e22b52a57cd02f57a8078572fe27c62f4a75ff7" diff --git a/Gopkg.toml b/Gopkg.toml index 77a73284..aee17ed8 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -37,14 +37,14 @@ branch = "master" name = "github.com/streadway/amqp" -[prune] - go-tests = true - unused-packages = true - [[constraint]] name = "github.com/gofrs/uuid" version = "3.2.0" [[constraint]] name = "github.com/mongodb/mongo-go-driver" - version = "0.2.0" + version = "0.3.0" + +[prune] + go-tests = true + unused-packages = true From b912bacce969071e8b56df69cc69877024067aa5 Mon Sep 17 00:00:00 2001 From: Vladimir Garvardt Date: Fri, 22 Feb 2019 15:54:57 +0100 Subject: [PATCH 61/74] Fixed aggregate versions ordering --- aggregate_repository.go | 2 +- mongodb/eventstore.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aggregate_repository.go b/aggregate_repository.go index 59e1bc3f..97e263ad 100644 --- a/aggregate_repository.go +++ b/aggregate_repository.go @@ -73,6 +73,6 @@ func (r *PublisherRepository) Reconstitute(id string, source AggregateRoot, stre } source.SetVersion(events[len(events)-1].Version) - Log("Aggregate reconstituted", map[string]interface{}{"id": id}, nil) + Log("Aggregate reconstituted", map[string]interface{}{"id": id, "stream": streamName}, nil) return nil } diff --git a/mongodb/eventstore.go b/mongodb/eventstore.go index 2b260b32..3f5f5264 100644 --- a/mongodb/eventstore.go +++ b/mongodb/eventstore.go @@ -175,7 +175,7 @@ func (s *EventStore) createIndices(c *mongo.Collection) error { mongo.IndexModel{ Keys: bsonx.Doc{ {Key: "aggregate_id", Value: bsonx.Int32(1)}, - {Key: "version", Value: bsonx.Int32(-1)}, + {Key: "version", Value: bsonx.Int32(1)}, }, Options: options.Index().SetUnique(true).SetBackground(true), }, From 6b152445ff6c76be82117f150dddcfb576d61f1a Mon Sep 17 00:00:00 2001 From: Vladimir Garvardt Date: Mon, 25 Feb 2019 12:34:36 +0100 Subject: [PATCH 62/74] Bumped mongo driver to 1.0-rc1 to use new package structure --- Gopkg.lock | 86 +++++++++++++++++++++---------------------- Gopkg.toml | 8 ++-- cmd/goengine/main.go | 11 +++--- mongodb/eventstore.go | 8 ++-- 4 files changed, 57 insertions(+), 56 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index c014e0a7..888bccb1 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -39,45 +39,6 @@ pruneopts = "UT" revision = "a1dbeea552b7c8df4b542c66073e393de198a800" -[[projects]] - digest = "1:9be9701967c831fb40a4b8b35c474b0a6e3af1f68ac35ad5fde6c44d71cbf4d1" - name = "github.com/mongodb/mongo-go-driver" - packages = [ - "bson", - "bson/bsoncodec", - "bson/bsonrw", - "bson/bsontype", - "bson/primitive", - "event", - "internal", - "mongo", - "mongo/options", - "mongo/readconcern", - "mongo/readpref", - "mongo/writeconcern", - "tag", - "version", - "x/bsonx", - "x/bsonx/bsoncore", - "x/mongo/driver", - "x/mongo/driver/auth", - "x/mongo/driver/auth/internal/gssapi", - "x/mongo/driver/session", - "x/mongo/driver/topology", - "x/mongo/driver/uuid", - "x/network/address", - "x/network/command", - "x/network/compressor", - "x/network/connection", - "x/network/connstring", - "x/network/description", - "x/network/result", - "x/network/wiremessage", - ] - pruneopts = "UT" - revision = "e1f3d104525e687eda76125707c9852e429f2730" - version = "v0.3.0" - [[projects]] digest = "1:5f4b78246f0bcb105b1e3b2b9e22b52a57cd02f57a8078572fe27c62f4a75ff7" name = "github.com/onsi/ginkgo" @@ -150,6 +111,45 @@ pruneopts = "UT" revision = "73f8eece6fdcd902c185bf651de50f3828bed5ed" +[[projects]] + digest = "1:7280a69811fe89d769f5cbbee7ec10cc33488d1e0d573c6d65e35a8887ab3420" + name = "go.mongodb.org/mongo-driver" + packages = [ + "bson", + "bson/bsoncodec", + "bson/bsonrw", + "bson/bsontype", + "bson/primitive", + "event", + "internal", + "mongo", + "mongo/options", + "mongo/readconcern", + "mongo/readpref", + "mongo/writeconcern", + "tag", + "version", + "x/bsonx", + "x/bsonx/bsoncore", + "x/mongo/driver", + "x/mongo/driver/auth", + "x/mongo/driver/auth/internal/gssapi", + "x/mongo/driver/session", + "x/mongo/driver/topology", + "x/mongo/driver/uuid", + "x/network/address", + "x/network/command", + "x/network/compressor", + "x/network/connection", + "x/network/connstring", + "x/network/description", + "x/network/result", + "x/network/wiremessage", + ] + pruneopts = "UT" + revision = "ccf36d0607fa2f6f4ae9645e625a7f33b26cf6d1" + version = "v1.0.0-rc1" + [[projects]] branch = "master" digest = "1:f92f6956e4059f6a3efc14924d2dd58ba90da25cc57fe07ae3779ef2f5e0c5f2" @@ -243,13 +243,13 @@ analyzer-version = 1 input-imports = [ "github.com/gofrs/uuid", - "github.com/mongodb/mongo-go-driver/bson", - "github.com/mongodb/mongo-go-driver/mongo", - "github.com/mongodb/mongo-go-driver/mongo/options", - "github.com/mongodb/mongo-go-driver/x/bsonx", "github.com/onsi/ginkgo", "github.com/onsi/gomega", "github.com/streadway/amqp", + "go.mongodb.org/mongo-driver/bson", + "go.mongodb.org/mongo-driver/mongo", + "go.mongodb.org/mongo-driver/mongo/options", + "go.mongodb.org/mongo-driver/x/bsonx", ] solver-name = "gps-cdcl" solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml index aee17ed8..1b5aaee1 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -41,10 +41,10 @@ name = "github.com/gofrs/uuid" version = "3.2.0" -[[constraint]] - name = "github.com/mongodb/mongo-go-driver" - version = "0.3.0" - [prune] go-tests = true unused-packages = true + +[[constraint]] + name = "go.mongodb.org/mongo-driver" + version = "v1.0.0-rc1" diff --git a/cmd/goengine/main.go b/cmd/goengine/main.go index cc212569..cd546142 100644 --- a/cmd/goengine/main.go +++ b/cmd/goengine/main.go @@ -9,8 +9,8 @@ import ( "github.com/hellofresh/goengine" "github.com/hellofresh/goengine/mongodb" "github.com/hellofresh/goengine/rabbit" - "github.com/mongodb/mongo-go-driver/mongo" - "github.com/mongodb/mongo-go-driver/mongo/options" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" ) func main() { @@ -26,9 +26,10 @@ func main() { } goengine.Log("Connecting to the database", map[string]interface{}{"dsn": mongoDSN}, nil) - mongoClient, err := mongo.NewClientWithOptions( - mongoDSN, - options.Client().SetAppName("goengine"), + mongoClient, err := mongo.NewClient( + options.Client(). + ApplyURI(mongoDSN). + SetAppName("goengine"), ) if err != nil { goengine.Log("Failed to create new Mongo mongoClient", nil, err) diff --git a/mongodb/eventstore.go b/mongodb/eventstore.go index 3f5f5264..e8f119bd 100644 --- a/mongodb/eventstore.go +++ b/mongodb/eventstore.go @@ -6,10 +6,10 @@ import ( "github.com/hellofresh/goengine" "github.com/hellofresh/goengine/reflection" - "github.com/mongodb/mongo-go-driver/bson" - "github.com/mongodb/mongo-go-driver/mongo" - "github.com/mongodb/mongo-go-driver/mongo/options" - "github.com/mongodb/mongo-go-driver/x/bsonx" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + "go.mongodb.org/mongo-driver/x/bsonx" ) // MongoEvent represents an event on mongodb From 9e8734d7cf4d666db1457ca63c594b067f35a837 Mon Sep 17 00:00:00 2001 From: Vladimir Garvardt Date: Mon, 25 Feb 2019 12:43:34 +0100 Subject: [PATCH 63/74] Fixed Count command --- mongodb/eventstore.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mongodb/eventstore.go b/mongodb/eventstore.go index e8f119bd..ebc522e7 100644 --- a/mongodb/eventstore.go +++ b/mongodb/eventstore.go @@ -163,7 +163,7 @@ func (s *EventStore) CountEventsFor(streamName goengine.StreamName, id string) ( ctx, cancel := s.cs.CountEventsFor() defer cancel() - return s.mongoDB.Collection(string(streamName)).Count(ctx, bson.M{"aggregate_id": string(streamName)}) + return s.mongoDB.Collection(string(streamName)).CountDocuments(ctx, bson.M{"aggregate_id": string(streamName)}) } func (s *EventStore) createIndices(c *mongo.Collection) error { From 43811d3b368cd8d2b8037b9411c6cbfc0b5ae0a7 Mon Sep 17 00:00:00 2001 From: Vladimir Garvardt Date: Mon, 18 Mar 2019 10:31:21 +0100 Subject: [PATCH 64/74] Bumped mongo driver version to 1.0 --- Gopkg.lock | 6 +++--- Gopkg.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 888bccb1..983366d1 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -112,7 +112,7 @@ revision = "73f8eece6fdcd902c185bf651de50f3828bed5ed" [[projects]] - digest = "1:7280a69811fe89d769f5cbbee7ec10cc33488d1e0d573c6d65e35a8887ab3420" + digest = "1:21f9cb6f1337c4776ed1d2d7b7ed6ffba3269ca12274c065364a5c0edee1f28b" name = "go.mongodb.org/mongo-driver" packages = [ "bson", @@ -147,8 +147,8 @@ "x/network/wiremessage", ] pruneopts = "UT" - revision = "ccf36d0607fa2f6f4ae9645e625a7f33b26cf6d1" - version = "v1.0.0-rc1" + revision = "1c3b9b9a41eecdf056560e07b68e6407b8d598c3" + version = "v1.0.0" [[projects]] branch = "master" diff --git a/Gopkg.toml b/Gopkg.toml index 1b5aaee1..3d312ada 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -47,4 +47,4 @@ [[constraint]] name = "go.mongodb.org/mongo-driver" - version = "v1.0.0-rc1" + version = "v1.0.0" From c7003bbad98fe58ec5f5d2f0a960522d378a262d Mon Sep 17 00:00:00 2001 From: Vladimir Garvardt Date: Mon, 18 Mar 2019 10:39:34 +0100 Subject: [PATCH 65/74] Use golang version of golint --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 4138ad5b..fb3273b4 100644 --- a/Makefile +++ b/Makefile @@ -35,5 +35,5 @@ tools: tools.golint tools.golint: @command -v golint >/dev/null ; if [ $$? -ne 0 ]; then \ echo "--> installing golint"; \ - go get github.com/golang/lint/golint; \ + go get golang.org/x/lint/golint; \ fi From de8b49d30c762d03f449265101a4248e16990e57 Mon Sep 17 00:00:00 2001 From: Vladimir Garvardt Date: Wed, 25 Sep 2019 16:02:46 +0200 Subject: [PATCH 66/74] Added connection name parameter --- .travis.yml | 6 +- Gopkg.lock | 255 ------------------------------------------- Gopkg.toml | 50 --------- Makefile | 2 - cmd/goengine/main.go | 2 +- go.mod | 21 ++++ go.sum | 47 ++++++++ rabbit/eventbus.go | 52 ++++++--- 8 files changed, 108 insertions(+), 327 deletions(-) delete mode 100644 Gopkg.lock delete mode 100644 Gopkg.toml create mode 100644 go.mod create mode 100644 go.sum diff --git a/.travis.yml b/.travis.yml index 952cda92..78d51390 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,7 @@ services: go: - "1.11" + - "1.12" - "stable" env: @@ -14,11 +15,8 @@ env: before_install: - docker-compose up -d -install: - - make deps - script: - - make $MAKE_TASK + - env GO111MODULE=on make $MAKE_TASK after_script: - docker-compose down -v diff --git a/Gopkg.lock b/Gopkg.lock deleted file mode 100644 index 983366d1..00000000 --- a/Gopkg.lock +++ /dev/null @@ -1,255 +0,0 @@ -# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. - - -[[projects]] - digest = "1:586ea76dbd0374d6fb649a91d70d652b7fe0ccffb8910a77468e7702e7901f3d" - name = "github.com/go-stack/stack" - packages = ["."] - pruneopts = "UT" - revision = "2fee6af1a9795aafbe0253a0cfbdf668e1fb8a9a" - version = "v1.8.0" - -[[projects]] - digest = "1:bed9d72d596f94e65fff37f4d6c01398074a6bb1c3f3ceff963516bd01db6ff5" - name = "github.com/gofrs/uuid" - packages = ["."] - pruneopts = "UT" - revision = "6b08a5c5172ba18946672b49749cde22873dd7c2" - version = "v3.2.0" - -[[projects]] - branch = "master" - digest = "1:4a0c6bb4805508a6287675fac876be2ac1182539ca8a32468d8128882e9d5009" - name = "github.com/golang/snappy" - packages = ["."] - pruneopts = "UT" - revision = "2e65f85255dbc3072edf28d6b5b8efc472979f5a" - -[[projects]] - branch = "master" - digest = "1:59392ed8afb901aab4287d4894df8191722e34f3957716f4350c8c133ce99046" - name = "github.com/hpcloud/tail" - packages = [ - ".", - "ratelimiter", - "util", - "watch", - "winfile", - ] - pruneopts = "UT" - revision = "a1dbeea552b7c8df4b542c66073e393de198a800" - -[[projects]] - digest = "1:5f4b78246f0bcb105b1e3b2b9e22b52a57cd02f57a8078572fe27c62f4a75ff7" - name = "github.com/onsi/ginkgo" - packages = [ - ".", - "config", - "internal/codelocation", - "internal/containernode", - "internal/failer", - "internal/leafnodes", - "internal/remote", - "internal/spec", - "internal/spec_iterator", - "internal/specrunner", - "internal/suite", - "internal/testingtproxy", - "internal/writer", - "reporters", - "reporters/stenographer", - "reporters/stenographer/support/go-colorable", - "reporters/stenographer/support/go-isatty", - "types", - ] - pruneopts = "UT" - revision = "2e1be8f7d90e9d3e3e58b0ce470f2f14d075406f" - version = "v1.7.0" - -[[projects]] - digest = "1:7a137fb7718928e473b7d805434ae563ec41790d3d227cdc64e8b14d1cab8a1f" - name = "github.com/onsi/gomega" - packages = [ - ".", - "format", - "internal/assertion", - "internal/asyncassertion", - "internal/oraclematcher", - "internal/testingtsupport", - "matchers", - "matchers/support/goraph/bipartitegraph", - "matchers/support/goraph/edge", - "matchers/support/goraph/node", - "matchers/support/goraph/util", - "types", - ] - pruneopts = "UT" - revision = "65fb64232476ad9046e57c26cd0bff3d3a8dc6cd" - version = "v1.4.3" - -[[projects]] - branch = "master" - digest = "1:525ac3364813b4688df380594e562133e07830dfce0722effda64b37634c13d0" - name = "github.com/streadway/amqp" - packages = ["."] - pruneopts = "UT" - revision = "a314942b2fd9dde7a3f70ba3f1062848ce6eb392" - -[[projects]] - branch = "master" - digest = "1:40fdfd6ab85ca32b6935853bbba35935dcb1d796c8135efd85947566c76e662e" - name = "github.com/xdg/scram" - packages = ["."] - pruneopts = "UT" - revision = "7eeb5667e42c09cb51bf7b7c28aea8c56767da90" - -[[projects]] - branch = "master" - digest = "1:f5c1d04bc09c644c592b45b9f0bad4030521b1a7d11c7dadbb272d9439fa6e8e" - name = "github.com/xdg/stringprep" - packages = ["."] - pruneopts = "UT" - revision = "73f8eece6fdcd902c185bf651de50f3828bed5ed" - -[[projects]] - digest = "1:21f9cb6f1337c4776ed1d2d7b7ed6ffba3269ca12274c065364a5c0edee1f28b" - name = "go.mongodb.org/mongo-driver" - packages = [ - "bson", - "bson/bsoncodec", - "bson/bsonrw", - "bson/bsontype", - "bson/primitive", - "event", - "internal", - "mongo", - "mongo/options", - "mongo/readconcern", - "mongo/readpref", - "mongo/writeconcern", - "tag", - "version", - "x/bsonx", - "x/bsonx/bsoncore", - "x/mongo/driver", - "x/mongo/driver/auth", - "x/mongo/driver/auth/internal/gssapi", - "x/mongo/driver/session", - "x/mongo/driver/topology", - "x/mongo/driver/uuid", - "x/network/address", - "x/network/command", - "x/network/compressor", - "x/network/connection", - "x/network/connstring", - "x/network/description", - "x/network/result", - "x/network/wiremessage", - ] - pruneopts = "UT" - revision = "1c3b9b9a41eecdf056560e07b68e6407b8d598c3" - version = "v1.0.0" - -[[projects]] - branch = "master" - digest = "1:f92f6956e4059f6a3efc14924d2dd58ba90da25cc57fe07ae3779ef2f5e0c5f2" - name = "golang.org/x/crypto" - packages = ["pbkdf2"] - pruneopts = "UT" - revision = "b01c7a72566457eb1420261cdafef86638fc3861" - -[[projects]] - branch = "master" - digest = "1:4939e20b972c22cd512abff0bf6ed8fc0e3e86aeb836d016be3323c6a901d99d" - name = "golang.org/x/net" - packages = [ - "html", - "html/atom", - "html/charset", - ] - pruneopts = "UT" - revision = "d26f9f9a57f3fab6a695bec0d84433c2c50f8bbf" - -[[projects]] - branch = "master" - digest = "1:75515eedc0dc2cb0b40372008b616fa2841d831c63eedd403285ff286c593295" - name = "golang.org/x/sync" - packages = ["semaphore"] - pruneopts = "UT" - revision = "37e7f081c4d4c64e13b10787722085407fe5d15f" - -[[projects]] - branch = "master" - digest = "1:aba2486bbebaadd1f62bde3c363ddbd984efade895833d86ed069f586fd9e899" - name = "golang.org/x/sys" - packages = ["unix"] - pruneopts = "UT" - revision = "aca44879d5644da7c5b8ec6a1115e9b6ea6c40d9" - -[[projects]] - digest = "1:4392fcf42d5cf0e3ff78c96b2acf8223d49e4fdc53eb77c99d2f8dfe4680e006" - name = "golang.org/x/text" - packages = [ - "encoding", - "encoding/charmap", - "encoding/htmlindex", - "encoding/internal", - "encoding/internal/identifier", - "encoding/japanese", - "encoding/korean", - "encoding/simplifiedchinese", - "encoding/traditionalchinese", - "encoding/unicode", - "internal/gen", - "internal/tag", - "internal/triegen", - "internal/ucd", - "internal/utf8internal", - "language", - "runes", - "transform", - "unicode/cldr", - "unicode/norm", - ] - pruneopts = "UT" - revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" - version = "v0.3.0" - -[[projects]] - digest = "1:abeb38ade3f32a92943e5be54f55ed6d6e3b6602761d74b4aab4c9dd45c18abd" - name = "gopkg.in/fsnotify/fsnotify.v1" - packages = ["."] - pruneopts = "UT" - revision = "c2828203cd70a50dcccfb2761f8b1f8ceef9a8e9" - version = "v1.4.7" - -[[projects]] - digest = "1:3c839a777de0e6da035c9de900b60cbec463b0a89351192c1ea083eaf9e0fce0" - name = "gopkg.in/tomb.v1" - packages = ["."] - pruneopts = "UT" - revision = "c131134a1947e9afd9cecfe11f4c6dff0732ae58" - -[[projects]] - digest = "1:4d2e5a73dc1500038e504a8d78b986630e3626dc027bc030ba5c75da257cdb96" - name = "gopkg.in/yaml.v2" - packages = ["."] - pruneopts = "UT" - revision = "51d6538a90f86fe93ac480b35f37b2be17fef232" - version = "v2.2.2" - -[solve-meta] - analyzer-name = "dep" - analyzer-version = 1 - input-imports = [ - "github.com/gofrs/uuid", - "github.com/onsi/ginkgo", - "github.com/onsi/gomega", - "github.com/streadway/amqp", - "go.mongodb.org/mongo-driver/bson", - "go.mongodb.org/mongo-driver/mongo", - "go.mongodb.org/mongo-driver/mongo/options", - "go.mongodb.org/mongo-driver/x/bsonx", - ] - solver-name = "gps-cdcl" - solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml deleted file mode 100644 index 3d312ada..00000000 --- a/Gopkg.toml +++ /dev/null @@ -1,50 +0,0 @@ -# Gopkg.toml example -# -# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html -# for detailed Gopkg.toml documentation. -# -# required = ["github.com/user/thing/cmd/thing"] -# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] -# -# [[constraint]] -# name = "github.com/user/project" -# version = "1.0.0" -# -# [[constraint]] -# name = "github.com/user/project2" -# branch = "dev" -# source = "github.com/myfork/project2" -# -# [[override]] -# name = "github.com/x/y" -# version = "2.4.0" -# -# [prune] -# non-go = false -# go-tests = true -# unused-packages = true - - -[[constraint]] - name = "github.com/onsi/ginkgo" - version = "1.7.0" - -[[constraint]] - name = "github.com/onsi/gomega" - version = "1.4.3" - -[[constraint]] - branch = "master" - name = "github.com/streadway/amqp" - -[[constraint]] - name = "github.com/gofrs/uuid" - version = "3.2.0" - -[prune] - go-tests = true - unused-packages = true - -[[constraint]] - name = "go.mongodb.org/mongo-driver" - version = "v1.0.0" diff --git a/Makefile b/Makefile index fb3273b4..e9fd7cdc 100644 --- a/Makefile +++ b/Makefile @@ -5,10 +5,8 @@ PKG_SRC := github.com/hellofresh/goengine deps: @echo "$(OK_COLOR)==> Installing dependencies$(NO_COLOR)" - @go get -u github.com/golang/dep/cmd/dep @go get -u github.com/onsi/ginkgo/ginkgo @go get -u github.com/onsi/gomega - @dep ensure -v -vendor-only vet: @echo "$(OK_COLOR)==> checking code correctness with 'go vet' tool$(NO_COLOR)" diff --git a/cmd/goengine/main.go b/cmd/goengine/main.go index cd546142..b1af875b 100644 --- a/cmd/goengine/main.go +++ b/cmd/goengine/main.go @@ -59,7 +59,7 @@ func main() { registry.RegisterType(&RecipeRated{}) goengine.Log("Setting up the event bus", map[string]interface{}{"dsn": brokerDSN}, nil) - bus := rabbit.NewEventBus(brokerDSN, "events", "events") + bus := rabbit.NewEventBus(brokerDSN, "events", "events", "goengine-test") goengine.Log("Setting up the event store", nil, nil) eventStore := mongodb.NewEventStore(mongoClient.Database("event_store"), registry) diff --git a/go.mod b/go.mod new file mode 100644 index 00000000..ee598435 --- /dev/null +++ b/go.mod @@ -0,0 +1,21 @@ +module github.com/hellofresh/goengine + +go 1.12 + +require ( + github.com/go-stack/stack v1.8.0 // indirect + github.com/gofrs/uuid v3.2.0+incompatible + github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db // indirect + github.com/onsi/ginkgo v1.7.0 + github.com/onsi/gomega v1.4.3 + github.com/streadway/amqp v0.0.0-20181205114330-a314942b2fd9 + github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c // indirect + github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc // indirect + go.mongodb.org/mongo-driver v1.0.0 + golang.org/x/crypto v0.0.0-20190130090550-b01c7a725664 // indirect + golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3 // indirect + golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 // indirect + golang.org/x/sys v0.0.0-20190130150945-aca44879d564 // indirect + gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect + gopkg.in/yaml.v2 v2.2.2 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 00000000..076fade5 --- /dev/null +++ b/go.sum @@ -0,0 +1,47 @@ +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE= +github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/hpcloud/tail v0.0.0-20180514194441-a1dbeea552b7/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/streadway/amqp v0.0.0-20181205114330-a314942b2fd9 h1:37QTz/gdHBLQcsmgMTnQDSWCtKzJ7YnfI2M2yTdr4BQ= +github.com/streadway/amqp v0.0.0-20181205114330-a314942b2fd9/go.mod h1:1WNBiOZtZQLpVAyu0iTduoJL9hEsMloAK5XWrtW0xdY= +github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c h1:u40Z8hqBAAQyv+vATcGgV0YCnDjqSL7/q/JyPhhJSPk= +github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= +github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc h1:n+nNi93yXLkJvKwXNP9d55HC7lGK4H/SRcwB5IaUZLo= +github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= +go.mongodb.org/mongo-driver v1.0.0 h1:KxPRDyfB2xXnDE2My8acoOWBQkfv3tz0SaWTRZjJR0c= +go.mongodb.org/mongo-driver v1.0.0/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= +golang.org/x/crypto v0.0.0-20190130090550-b01c7a725664 h1:YbZJ76lQ1BqNhVe7dKTSB67wDrc2VPRR75IyGyyPDX8= +golang.org/x/crypto v0.0.0-20190130090550-b01c7a725664/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3 h1:ulvT7fqt0yHWzpJwI57MezWnYDVpCAYBVuYst/L+fAY= +golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190130150945-aca44879d564 h1:o6ENHFwwr1TZ9CUPQcfo1HGvLP1OPsPOTB7xCIOPNmU= +golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/fsnotify/fsnotify.v1 v1.4.7/go.mod h1:Fyux9zXlo4rWoMSIzpn9fDAYjalPqJ/K1qJ27s+7ltE= +gopkg.in/tomb.v1 v1.0.0-20140529071818-c131134a1947/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/rabbit/eventbus.go b/rabbit/eventbus.go index 2ee236c0..702888c7 100644 --- a/rabbit/eventbus.go +++ b/rabbit/eventbus.go @@ -11,6 +11,11 @@ import ( "github.com/streadway/amqp" ) +const ( + defaultHeartbeat = 10 * time.Second + defaultLocale = "en_US" +) + // RawVersionedEvent represents the event that goes into rabbitmq type RawVersionedEvent struct { ID string `bson:"aggregate_id,omitempty"` @@ -22,20 +27,25 @@ type RawVersionedEvent struct { // EventBus ... type EventBus struct { - brokerDSN string - name string - exchange string + brokerDSN string + queue string + exchange string + connectionName string } // NewEventBus ... -func NewEventBus(brokerDSN string, name string, exchange string) *EventBus { - return &EventBus{brokerDSN, name, exchange} +func NewEventBus(brokerDSN, queue, exchange, connectionName string) *EventBus { + return &EventBus{brokerDSN, queue, exchange, connectionName} } // PublishEvents will publish events func (bus *EventBus) PublishEvents(events []*goengine.DomainMessage) error { // Connects opens an AMQP connection from the credentials in the URL. - conn, err := amqp.Dial(bus.brokerDSN) + conn, err := amqp.DialConfig(bus.brokerDSN, amqp.Config{ + Heartbeat: defaultHeartbeat, + Locale: defaultLocale, + Properties: amqp.Table{"connection_name": bus.connectionName + ".events-publisher"}, + }) if err != nil { return err } @@ -103,7 +113,7 @@ func (bus *EventBus) ReceiveEvents(options goengine.VersionedEventReceiverOption select { case ch := <-options.Close: defer conn.Close() - ch <- c.Cancel(bus.name, false) + ch <- c.Cancel(bus.queue, false) return case message, more := <-events: @@ -116,14 +126,18 @@ func (bus *EventBus) ReceiveEvents(options goengine.VersionedEventReceiverOption if nil != err { goengine.Log("EventBus.Cannot find event type", map[string]interface{}{"type": raw.Type}, nil) options.Error <- errors.New("Cannot find event type " + raw.Type) - message.Ack(true) + if err := message.Ack(true); err != nil { + goengine.Log("EventBus.Ack could not ack message", nil, err) + } } else { ackCh := make(chan bool) goengine.Log("EventBus.Dispatching Message", nil, nil) options.ReceiveEvent <- goengine.VersionedEventTransactedAccept{Event: domainEvent, ProcessedSuccessfully: ackCh} result := <-ackCh - message.Ack(result) + if err := message.Ack(result); err != nil { + goengine.Log("EventBus.Ack could not ack dispatched message", nil, err) + } } } } else { @@ -153,7 +167,11 @@ func (bus *EventBus) ReceiveEvents(options goengine.VersionedEventReceiverOption // DeleteQueue will delete a queue func (bus *EventBus) DeleteQueue(name string) error { - conn, err := amqp.Dial(bus.brokerDSN) + conn, err := amqp.DialConfig(bus.brokerDSN, amqp.Config{ + Heartbeat: defaultHeartbeat, + Locale: defaultLocale, + Properties: amqp.Table{"connection_name": bus.connectionName + ".queue-deleter"}, + }) if err != nil { return err } @@ -168,7 +186,11 @@ func (bus *EventBus) DeleteQueue(name string) error { } func (bus *EventBus) consumeEventsQueue(exclusive bool) (*amqp.Connection, *amqp.Channel, <-chan amqp.Delivery, error) { - conn, err := amqp.Dial(bus.brokerDSN) + conn, err := amqp.DialConfig(bus.brokerDSN, amqp.Config{ + Heartbeat: defaultHeartbeat, + Locale: defaultLocale, + Properties: amqp.Table{"connection_name": bus.connectionName + ".events-consumer"}, + }) if err != nil { return nil, nil, nil, err } @@ -187,21 +209,21 @@ func (bus *EventBus) consumeEventsQueue(exclusive bool) (*amqp.Connection, *amqp return nil, nil, nil, fmt.Errorf("exchange.declare: %v", err) } - if _, err = c.QueueDeclare(bus.name, true, false, false, false, nil); err != nil { + if _, err = c.QueueDeclare(bus.queue, true, false, false, false, nil); err != nil { return nil, nil, nil, fmt.Errorf("queue.declare: %v", err) } - if err = c.QueueBind(bus.name, bus.name, bus.exchange, false, nil); err != nil { + if err = c.QueueBind(bus.queue, bus.queue, bus.exchange, false, nil); err != nil { return nil, nil, nil, fmt.Errorf("queue.bind: %v", err) } - events, err := c.Consume(bus.name, bus.name, false, exclusive, false, false, nil) + events, err := c.Consume(bus.queue, bus.queue, false, exclusive, false, false, nil) if err != nil { return nil, nil, nil, fmt.Errorf("basic.consume: %v", err) } if err := c.Qos(1, 0, false); err != nil { - return nil, nil, nil, fmt.Errorf("Qos: %v", err) + return nil, nil, nil, fmt.Errorf("qos: %v", err) } return conn, c, events, nil From 2b02095f5e76d3b5aaaa68055e19b4fb5b9935bc Mon Sep 17 00:00:00 2001 From: Vladimir Garvardt Date: Wed, 25 Sep 2019 16:25:43 +0200 Subject: [PATCH 67/74] Added missing test deps --- .travis.yml | 3 +++ Makefile | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 78d51390..9e599720 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,6 +15,9 @@ env: before_install: - docker-compose up -d +install: + - make deps + script: - env GO111MODULE=on make $MAKE_TASK diff --git a/Makefile b/Makefile index e9fd7cdc..003b492d 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ OK_COLOR=\033[32;01m PKG_SRC := github.com/hellofresh/goengine deps: - @echo "$(OK_COLOR)==> Installing dependencies$(NO_COLOR)" + @echo "$(OK_COLOR)==> Installing test dependencies$(NO_COLOR)" @go get -u github.com/onsi/ginkgo/ginkgo @go get -u github.com/onsi/gomega From 5867b6903cc1a2671abad99e051751cd1fab0773 Mon Sep 17 00:00:00 2001 From: Vladimir Garvardt Date: Wed, 25 Sep 2019 16:29:54 +0200 Subject: [PATCH 68/74] No more go1.11 support --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 9e599720..2dc38b3e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,6 @@ services: - docker go: - - "1.11" - "1.12" - "stable" From 5b1d5b60dbcf68b6fc0706182ef4f276338c4468 Mon Sep 17 00:00:00 2001 From: Vladimir Garvardt Date: Wed, 21 Apr 2021 21:05:09 +0200 Subject: [PATCH 69/74] Run pipeline in GH Actions --- .github/workflows/testing.yml | 55 +++++++++++++++++++++++++++++++++++ .gitignore | 3 +- .golangci.yml | 15 ++++++++++ .travis.yml | 24 --------------- Makefile | 37 +++++------------------ docker-compose.yml | 2 +- 6 files changed, 80 insertions(+), 56 deletions(-) create mode 100644 .github/workflows/testing.yml create mode 100644 .golangci.yml delete mode 100644 .travis.yml diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml new file mode 100644 index 00000000..973dc4fd --- /dev/null +++ b/.github/workflows/testing.yml @@ -0,0 +1,55 @@ +name: Testing + +on: + push: + branches: [ v0.3 ] + pull_request: + branches: [ v0.3 ] + +jobs: + lint: + name: Lint + runs-on: ubuntu-latest + steps: + - name: Check out code + uses: actions/checkout@v2 + - name: golangci-lint + uses: golangci/golangci-lint-action@v2 + + test: + name: Test + runs-on: ubuntu-latest + needs: [ lint ] + + services: + rabbit: + image: rabbitmq:3.6-management-alpine + ports: + - "5672" + - "15672" + + mongo: + image: mongo:3 + ports: + - "27017" + + steps: + - name: Set up Go + uses: actions/setup-go@v2 + - name: Check out code + uses: actions/checkout@v2 + - name: Run unit tests + run: go test -cover -coverprofile=coverage.txt -covermode=atomic ./... + - name: Run integration tests + if: success() + run: go run ./cmd/goengine/... + env: + BROKER_DSN: amqp://guest:guest@localhost:${{ job.services.rabbit.ports[5672] }}/ + STORAGE_DSN: mongodb://localhost:${{ job.services.mongo.ports[27017] }}/ + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v1 + if: success() + with: + file: ./coverage.txt + fail_ci_if_error: false diff --git a/.gitignore b/.gitignore index ff91de9e..54ebba76 100644 --- a/.gitignore +++ b/.gitignore @@ -24,4 +24,5 @@ _testmain.go *.test *.prof debug -gin-bin \ No newline at end of file +gin-bin +coverage.txt diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 00000000..ad50dd7c --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,15 @@ +# See https://golangci-lint.run/usage/configuration/#config-file for more information +run: + timeout: 5m +linters: + disable-all: true + enable: + - gofmt + - golint + - goimports + fast: false +linters-settings: + gofmt: + simplify: false +issues: + exclude-use-default: false diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 2dc38b3e..00000000 --- a/.travis.yml +++ /dev/null @@ -1,24 +0,0 @@ -language: go - -services: - - docker - -go: - - "1.12" - - "stable" - -env: - - MAKE_TASK=test-unit - - MAKE_TASK=test-integration - -before_install: - - docker-compose up -d - -install: - - make deps - -script: - - env GO111MODULE=on make $MAKE_TASK - -after_script: - - docker-compose down -v diff --git a/Makefile b/Makefile index 003b492d..8e1a9a46 100644 --- a/Makefile +++ b/Makefile @@ -1,37 +1,14 @@ NO_COLOR=\033[0m OK_COLOR=\033[32;01m -PKG_SRC := github.com/hellofresh/goengine - -deps: - @echo "$(OK_COLOR)==> Installing test dependencies$(NO_COLOR)" - @go get -u github.com/onsi/ginkgo/ginkgo - @go get -u github.com/onsi/gomega - -vet: - @echo "$(OK_COLOR)==> checking code correctness with 'go vet' tool$(NO_COLOR)" - @go vet ./... - -lint: tools.golint - @echo "$(OK_COLOR)==> checking code style with 'golint' tool$(NO_COLOR)" - @go list ./... | xargs -n 1 golint -set_exit_status - -test-integration: lint vet +test-integration: @echo "$(OK_COLOR)==> Running integration tests$(NO_COLOR)" - @STORAGE_DSN=mongodb://localhost:27017/ BROKER_DSN=amqp://guest:guest@localhost:5672/ go run $(PKG_SRC)/cmd/goengine/... + @STORAGE_DSN=mongodb://localhost:27017/ BROKER_DSN=amqp://guest:guest@localhost:5672/ go run ./cmd/goengine/... -test-unit: lint vet +test-unit: @echo "$(OK_COLOR)==> Running unit tests$(NO_COLOR)" - @ginkgo -r - -#--------------- -#-- tools -#--------------- - -tools: tools.golint + @go test -cover -coverprofile=coverage.txt -covermode=atomic ./... -tools.golint: - @command -v golint >/dev/null ; if [ $$? -ne 0 ]; then \ - echo "--> installing golint"; \ - go get golang.org/x/lint/golint; \ - fi +lint: + @echo "$(OK_COLOR)==> Linting with golangci-lint$(NO_COLOR)" + @docker run -it --rm -v $(pwd):/app -w /app golangci/golangci-lint:v1.39.0 golangci-lint run -v diff --git a/docker-compose.yml b/docker-compose.yml index 1e2bca6b..d2b1d88c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,6 +8,6 @@ services: - "5672:5672" mongo: - image: mongo + image: mongo:3 ports: - "27017:27017" From 395a23a59f95d1b98cdd3d1053fa190f9a61a410 Mon Sep 17 00:00:00 2001 From: Vladimir Garvardt Date: Thu, 22 Apr 2021 10:03:51 +0200 Subject: [PATCH 70/74] Updated mongo driver to the latest stable version --- go.mod | 14 +----- go.sum | 152 ++++++++++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 132 insertions(+), 34 deletions(-) diff --git a/go.mod b/go.mod index ee598435..75e7e960 100644 --- a/go.mod +++ b/go.mod @@ -1,21 +1,11 @@ module github.com/hellofresh/goengine -go 1.12 +go 1.15 require ( - github.com/go-stack/stack v1.8.0 // indirect github.com/gofrs/uuid v3.2.0+incompatible - github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db // indirect github.com/onsi/ginkgo v1.7.0 github.com/onsi/gomega v1.4.3 github.com/streadway/amqp v0.0.0-20181205114330-a314942b2fd9 - github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c // indirect - github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc // indirect - go.mongodb.org/mongo-driver v1.0.0 - golang.org/x/crypto v0.0.0-20190130090550-b01c7a725664 // indirect - golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3 // indirect - golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 // indirect - golang.org/x/sys v0.0.0-20190130150945-aca44879d564 // indirect - gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect - gopkg.in/yaml.v2 v2.2.2 // indirect + go.mongodb.org/mongo-driver v1.5.1 ) diff --git a/go.sum b/go.sum index 076fade5..82bcf5c5 100644 --- a/go.sum +++ b/go.sum @@ -1,47 +1,155 @@ +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/aws/aws-sdk-go v1.34.28 h1:sscPpn/Ns3i0F4HPEWAVcwdIRaZZCuL7llJ2/60yPIk= +github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= +github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY= +github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg= +github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/flect v0.1.0/go.mod h1:d2ehjJqGOH/Kjqcoz+F7jHTBbmDb38yXA598Hb50EGs= +github.com/gobuffalo/flect v0.1.1/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= +github.com/gobuffalo/flect v0.1.3/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= +github.com/gobuffalo/genny v0.0.0-20190329151137-27723ad26ef9/go.mod h1:rWs4Z12d1Zbf19rlsn0nurr75KqhYp52EAGGxTbBhNk= +github.com/gobuffalo/genny v0.0.0-20190403191548-3ca520ef0d9e/go.mod h1:80lIj3kVJWwOrXWWMRzzdhW3DsrdjILVil/SFKBzF28= +github.com/gobuffalo/genny v0.1.0/go.mod h1:XidbUqzak3lHdS//TPu2OgiFB+51Ur5f7CSnXZ/JDvo= +github.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk= +github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw= +github.com/gobuffalo/gogen v0.0.0-20190315121717-8f38393713f5/go.mod h1:V9QVDIxsgKNZs6L2IYiGR8datgMhB577vzTDqypH360= +github.com/gobuffalo/gogen v0.1.0/go.mod h1:8NTelM5qd8RZ15VjQTFkAW6qOMx5wBbW4dSCS3BY8gg= +github.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+71xfDNE= +github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8= +github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= +github.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= +github.com/gobuffalo/packd v0.0.0-20190315124812-a385830c7fc0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= +github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= +github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ= +github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0= +github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w= -github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/hpcloud/tail v0.0.0-20180514194441-a1dbeea552b7/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= +github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= +github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= +github.com/klauspost/compress v1.9.5 h1:U+CaK85mrNNb4k8BNOfgJtJ/gr6kswUCFj6miSzVC6M= +github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= +github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= +github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/streadway/amqp v0.0.0-20181205114330-a314942b2fd9 h1:37QTz/gdHBLQcsmgMTnQDSWCtKzJ7YnfI2M2yTdr4BQ= github.com/streadway/amqp v0.0.0-20181205114330-a314942b2fd9/go.mod h1:1WNBiOZtZQLpVAyu0iTduoJL9hEsMloAK5XWrtW0xdY= -github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c h1:u40Z8hqBAAQyv+vATcGgV0YCnDjqSL7/q/JyPhhJSPk= -github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= -github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc h1:n+nNi93yXLkJvKwXNP9d55HC7lGK4H/SRcwB5IaUZLo= -github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= -go.mongodb.org/mongo-driver v1.0.0 h1:KxPRDyfB2xXnDE2My8acoOWBQkfv3tz0SaWTRZjJR0c= -go.mongodb.org/mongo-driver v1.0.0/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= -golang.org/x/crypto v0.0.0-20190130090550-b01c7a725664 h1:YbZJ76lQ1BqNhVe7dKTSB67wDrc2VPRR75IyGyyPDX8= -golang.org/x/crypto v0.0.0-20190130090550-b01c7a725664/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +github.com/streadway/amqp v1.0.0 h1:kuuDrUJFZL1QYL9hUNuCxNObNzB0bV/ZG5jV3RWAQgo= +github.com/streadway/amqp v1.0.0/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.0.2 h1:akYIkZ28e6A96dkWNJQu3nmCzH3YfwMPQExUYDaRv7w= +github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= +github.com/xdg-go/stringprep v1.0.2 h1:6iq84/ryjjeRmMJwxutI51F2GIPlP5BfTvXHeYjyhBc= +github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= +github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA= +github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= +go.mongodb.org/mongo-driver v1.5.1 h1:9nOVLGDfOaZ9R0tBumx/BcuqkbFpyTCU2r/Po7A2azI= +go.mongodb.org/mongo-driver v1.5.1/go.mod h1:gRXCHX4Jo7J0IJ1oDQyUxF7jfy19UfxniMS4xxMmUqw= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= +golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 h1:xMPOj6Pz6UipU1wXLkrtqpHbR0AVFnyPEQq/wRWz9lM= +golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3 h1:ulvT7fqt0yHWzpJwI57MezWnYDVpCAYBVuYst/L+fAY= -golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190130150945-aca44879d564 h1:o6ENHFwwr1TZ9CUPQcfo1HGvLP1OPsPOTB7xCIOPNmU= -golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2 h1:T5DasATyLQfmbTpfEXx/IOL9vfjzW6up+ZDkmHvIf2s= +golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/fsnotify/fsnotify.v1 v1.4.7/go.mod h1:Fyux9zXlo4rWoMSIzpn9fDAYjalPqJ/K1qJ27s+7ltE= -gopkg.in/tomb.v1 v1.0.0-20140529071818-c131134a1947/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= From 3867c46c6b43b3168424b848af2b97efa260d0b6 Mon Sep 17 00:00:00 2001 From: Vladimir Garvardt Date: Thu, 22 Apr 2021 10:18:12 +0200 Subject: [PATCH 71/74] Updated amqp library to the latest stable version --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 75e7e960..2fb0ab2f 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,6 @@ require ( github.com/gofrs/uuid v3.2.0+incompatible github.com/onsi/ginkgo v1.7.0 github.com/onsi/gomega v1.4.3 - github.com/streadway/amqp v0.0.0-20181205114330-a314942b2fd9 + github.com/streadway/amqp v1.0.0 go.mongodb.org/mongo-driver v1.5.1 ) From 776716f80572b822c7193ed930aa43914620e6fc Mon Sep 17 00:00:00 2001 From: Vladimir Garvardt Date: Thu, 22 Apr 2021 10:19:19 +0200 Subject: [PATCH 72/74] Updated ginkgo and gomega --- go.mod | 6 ++-- go.sum | 88 ++++++++++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 74 insertions(+), 20 deletions(-) diff --git a/go.mod b/go.mod index 2fb0ab2f..198d4b0a 100644 --- a/go.mod +++ b/go.mod @@ -4,8 +4,10 @@ go 1.15 require ( github.com/gofrs/uuid v3.2.0+incompatible - github.com/onsi/ginkgo v1.7.0 - github.com/onsi/gomega v1.4.3 + github.com/onsi/ginkgo v1.16.1 + github.com/onsi/gomega v1.11.0 github.com/streadway/amqp v1.0.0 go.mongodb.org/mongo-driver v1.5.1 + golang.org/x/net v0.0.0-20210421230115-4e50805a0758 // indirect + golang.org/x/sys v0.0.0-20210421221651-33663a62ff08 // indirect ) diff --git a/go.sum b/go.sum index 82bcf5c5..1fcf3f63 100644 --- a/go.sum +++ b/go.sum @@ -4,11 +4,13 @@ github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY= github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg= @@ -35,13 +37,22 @@ github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/V github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= @@ -63,11 +74,17 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= -github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= -github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.16.1 h1:foqVmeWDD6yYpK+Yz3fHyNIxFYNxswxqNFjSKe+vI54= +github.com/onsi/ginkgo v1.16.1/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.11.0 h1:+CqWgvj0OZycCaqclBD1pxKHAU+tOkHmQIWvDHq2aug= +github.com/onsi/gomega v1.11.0/go.mod h1:azGKhqFUon9Vuj0YmTfLSmx0FUwqXYSTl5re8lQLTUg= github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -83,14 +100,13 @@ github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMB github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/streadway/amqp v0.0.0-20181205114330-a314942b2fd9 h1:37QTz/gdHBLQcsmgMTnQDSWCtKzJ7YnfI2M2yTdr4BQ= -github.com/streadway/amqp v0.0.0-20181205114330-a314942b2fd9/go.mod h1:1WNBiOZtZQLpVAyu0iTduoJL9hEsMloAK5XWrtW0xdY= github.com/streadway/amqp v1.0.0 h1:kuuDrUJFZL1QYL9hUNuCxNObNzB0bV/ZG5jV3RWAQgo= github.com/streadway/amqp v1.0.0/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= @@ -103,24 +119,34 @@ github.com/xdg-go/stringprep v1.0.2 h1:6iq84/ryjjeRmMJwxutI51F2GIPlP5BfTvXHeYjyh github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.mongodb.org/mongo-driver v1.5.1 h1:9nOVLGDfOaZ9R0tBumx/BcuqkbFpyTCU2r/Po7A2azI= go.mongodb.org/mongo-driver v1.5.1/go.mod h1:gRXCHX4Jo7J0IJ1oDQyUxF7jfy19UfxniMS4xxMmUqw= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= -golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 h1:xMPOj6Pz6UipU1wXLkrtqpHbR0AVFnyPEQq/wRWz9lM= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210421230115-4e50805a0758 h1:aEpZnXcAmXkd6AvLb2OPt+EN1Zu/8Ne3pCqPjja5PXY= +golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -128,28 +154,54 @@ golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2 h1:T5DasATyLQfmbTpfEXx/IOL9vfjzW6up+ZDkmHvIf2s= golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210421221651-33663a62ff08 h1:qyN5bV+96OX8pL78eXDuz6YlDPzCYgdW74H5yE9BoSU= +golang.org/x/sys v0.0.0-20210421221651-33663a62ff08/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= From 353968e489f3ff75f110f162ef4e453da0486ac7 Mon Sep 17 00:00:00 2001 From: Vladimir Garvardt Date: Thu, 22 Apr 2021 10:21:13 +0200 Subject: [PATCH 73/74] Updated uuid --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 198d4b0a..e50e4ea5 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/hellofresh/goengine go 1.15 require ( - github.com/gofrs/uuid v3.2.0+incompatible + github.com/gofrs/uuid v4.0.0+incompatible github.com/onsi/ginkgo v1.16.1 github.com/onsi/gomega v1.11.0 github.com/streadway/amqp v1.0.0 diff --git a/go.sum b/go.sum index 1fcf3f63..c11402ec 100644 --- a/go.sum +++ b/go.sum @@ -35,8 +35,8 @@ github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWe github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ= github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0= github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= -github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE= -github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= +github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= From 91a255d43ed0a294839d94d1e7d9f2a49b5afc46 Mon Sep 17 00:00:00 2001 From: Vladimir Garvardt Date: Thu, 7 Oct 2021 19:35:04 +0200 Subject: [PATCH 74/74] Replaced gofrs uuid with google uuid --- aggregate_root.go | 4 ++-- go.mod | 2 +- go.sum | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/aggregate_root.go b/aggregate_root.go index edcd3f9b..a9c8cd0a 100644 --- a/aggregate_root.go +++ b/aggregate_root.go @@ -3,7 +3,7 @@ package goengine import ( "fmt" - "github.com/gofrs/uuid" + "github.com/google/uuid" "github.com/hellofresh/goengine/reflection" ) @@ -26,7 +26,7 @@ type AggregateRootBased struct { // NewAggregateRootBased ... func NewAggregateRootBased(source interface{}) *AggregateRootBased { - return NewEventSourceBasedWithID(source, uuid.Must(uuid.NewV4()).String()) + return NewEventSourceBasedWithID(source, uuid.NewString()) } // NewEventSourceBasedWithID ... diff --git a/go.mod b/go.mod index e50e4ea5..344f005c 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/hellofresh/goengine go 1.15 require ( - github.com/gofrs/uuid v4.0.0+incompatible + github.com/google/uuid v1.3.0 github.com/onsi/ginkgo v1.16.1 github.com/onsi/gomega v1.11.0 github.com/streadway/amqp v1.0.0 diff --git a/go.sum b/go.sum index c11402ec..ead1e821 100644 --- a/go.sum +++ b/go.sum @@ -35,8 +35,6 @@ github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWe github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ= github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0= github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= -github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= -github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= @@ -53,6 +51,8 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=