xxfast / KStore

A tiny Kotlin multiplatform library that assists in saving and restoring objects to and from disk using kotlinx.coroutines, kotlinx.serialisation and kotlinx.io
https://xxfast.github.io/KStore/
Apache License 2.0
506 stars 16 forks source link

No gaurantee collectors will receive data before put returns #129

Open fergdev opened 2 weeks ago

fergdev commented 2 weeks ago

I have 2 functions one that writes to KStore and one that invokes a function that uses that data and is observed in a flow from KStore. The data is not delivered to the collector before the write method completes.

// Writes to KStore using putString settings.alertSettingsManager.setTTSVoice(settingsIntent.voiceId)

// Sound manager observes voiceId from settings and should "speak" with the observed voiceId soundManager.textToSpeech("Work. Rest. Finished.")

Expected behaviour. The value from putString should be delivered to collectors of that Key before the function returns.

Actual behaviour. The value from putString is delivered to collectors after the function returns.

I am not sure if my expectations are correct here, it seems like KStore is launching a few coroutines under the hood, and from a few chats it seems this is an interesting design decision. Are you able to provide any incite on why this method was chosen?

If this is not a bug, are you able to outline a way to ensure collectors receive values from kStore before the put functions complete?

I have tried many different methods on and/ios/desktop/wasm to get this to work correctly and am struggling.

ShreyashKore commented 1 week ago

I couldn't find the putString method that you are taking about. If by putString, you mean Store.set method, i think the current design is correct.. i.e. it will only notify the observers after the set function returns.

xxfast commented 1 week ago

Hi @fergdev The API you shared is reminiscent of multiplatform-settings, not KStore

Nevertheless - In regards how KStore's set works, the following test case demonstrates how it is intended to work

@Test
fun testUpdates() = runTest {
  store.updates.test { // <-- `updates` lets you observe the changes to the store
    assertEquals(null, awaitItem()) //  <--  it immediately emits the stored value (or default value if there's no stored value)
    store.set(MYLO) // <-- set is a suspending call, will emit the given value after it is done encoding it
    assertEquals(MYLO, awaitItem())  // <-- it will notify the collectors of the said value *after it is set*
  }
}

it seems like KStore is launching a few coroutines under the hood, and from a few chats it seems this is an interesting design decision. Are you able to provide any incite on why this method was chosen

KStore doesn't launch any coroutines under the hood. It is using the coroutine that the call-site launches. This is why all the API signatures to the store are suspended.

If this is not a bug, are you able to outline a way to ensure collectors receive values from kStore before the put functions complete?

Is there a reason why your collector can't receive the value directly? If you want the collector to receive the value first, you could always store the value after 🤔