Skip to content

Reusing aggregate instances inside circular sync handlers leads to WrongExpectedEventVersion error #290

Open
@andrzejkrzywda

Description

@andrzejkrzywda

Probably the code will tell it clearier than I can explain ;)

In short - we're having two aggregates. There's a circular dependency between them (via events).
Once we started caching (here simulated with $global_var) the first aggregate we noticed a WrongExpectedEventVersion exception.

The fix was to set the version and unpublished_events manually.

class AggregateRootBugTest < ActiveSupport::TestCase

  def test_versioning_broken
    event_store = RailsEventStore::Client.new(
      repository: RubyEventStore::InMemoryRepository.new,
    )
    $aggregate_1 = Aggregate_1.new
    $aggregate_1.load("stream_1", event_store: event_store)

    event_store.subscribe(
      -> _ {
        aggregate = Aggregate_2.new
        aggregate.load("stream_2", event_store: event_store)
        aggregate.publish_event_2
        aggregate.store("stream_2", event_store: event_store)
      },
      to: [Event_1]
    )

    event_store.subscribe(
      -> _ {
        # uncommenting the code should fix the bug (and fail the test)
        # $aggregate_1.instance_variable_set(:@version, ($aggregate_1.instance_variable_get(:@version) || -1) + $aggregate_1.unpublished_events.size)
        # $aggregate_1.instance_variable_set(:@unpublished_events, [])
        $aggregate_1.do_something_in_reaction_to_event_2
        assert_raise(RubyEventStore::WrongExpectedEventVersion, bug_fixed_message) do
          $aggregate_1.store("stream_1", event_store: event_store)
        end
      },
      to: [Event_2]
    )
    $aggregate_1.publish_event_1

    $aggregate_1.store("stream_1", event_store: event_store)
  end

  def bug_fixed_message
    "If this test fails, it means that AggregateRoot has the bug fixed. "+
    "Go and remove the hack in Foo::Bar (global cache) " +
    "It has something to do with setting ivars for version and events"
  end

  class Aggregate_1
    include AggregateRoot

    def publish_event_1
      apply(Event_1.new(data: {}))
    end

    def do_something_in_reaction_to_event_2
    end

    def apply_event_1(event)
    end

  end


  class Aggregate_2
    include AggregateRoot

    def publish_event_2
      apply(Event_2.new(data: {}))
    end

    def apply_event_2(event)
    end

  end

  class Event_1 < RailsEventStore::Event
  end

  class Event_2 < RailsEventStore::Event
  end
end

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions