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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions