dnvriend / akka-persistence-inmemory

Akka-persistence-inmemory is a plugin for akka-persistence that stores journal and snapshot messages memory, which is very useful when testing persistent actors, persistent FSM and akka cluster
Apache License 2.0
134 stars 41 forks source link

Using wrong compareTo function for TimeBasedUUIDs in eventsByTag #36

Closed SebastianMax closed 7 years ago

SebastianMax commented 7 years ago

Hi,

I am using akka-persistence-inmemory not only for unit-testing, but also for a proof-of-concept application that runs longer than some seconds. The application "writes" events to the inmemory-journal and synchronizes them via PersistenceQuery using readJournal.eventsByTag. The offset-mode is set to uuid.

During testing I stumbled over the problem that after a (random) amount of time the eventsByTag source stops emitting events that are persisted. I currently assume this is because the InMemoryJournalStorage.eventsByTag uses > to compare two TimeBasedUUIDs, which uses the java.util.UUID.compareTo (InMemoryJournalStorage)

However, this compareTo function does not use the same ordering as the TimeBasedUUIDs which are generated in UUIDS.timeBased().

Therefore, it may happen that a current timeBasedUUID is less than an older timeBasedUUID, and thus the eventsByTag does not return the old (but not yet delivered) event.

A small failing test confirms this behaviour:

    import java.time.{OffsetDateTime, ZoneOffset}
    import akka.persistence.inmemory.util.UUIDs
    import akka.persistence.query.TimeBasedUUID
    import org.scalatest.{Matchers, WordSpecLike}

    class TimeBasedUUIDSpec
      extends WordSpecLike with Matchers {

      "The TimeBasedUUID" when {
        "comparing two TimeBasedUUIDs that differ by a second using '<' " should {
          "compare correctly" in {

            val one = TimeBasedUUID(UUIDs.startOf(OffsetDateTime.of(2002, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC).toEpochSecond * 1000))
            val two = TimeBasedUUID(UUIDs.startOf(OffsetDateTime.of(2002, 1, 1, 0, 0, 1, 0, ZoneOffset.UTC).toEpochSecond * 1000))

            one.value.timestamp() < two.value.timestamp() shouldBe true
            one < two shouldBe true
          }
        }
      }
    }

A possible fix could be to use a different compare function, like it is done here.

dnvriend commented 7 years ago

Hi, could you please test 2.4.18.2-SNAPSHOT (the master branch) and check if you still have the issue. I've made some small changes.

SebastianMax commented 7 years ago

Hi, sorry for the late reply, I did not see your improvements until now. Looks very good and works for me, thank you!

toerni commented 7 years ago

Can the same bug also be fixed for the 2.5 version of akka?