Is it needed to sequentialize data sync? sync cont...
# android-architecture
u
Is it needed to sequentialize data sync? sync contains api get + db write. Db writes are synchronized. So only way this can get messed up if the 2nd concurrent sync arrived sooner than 1st Is this really relevant for production? Should I put Mutex everywhere?
g
DB already atomic, if you have it, why you need any kind mutex?
j
@gildor are there docs about that?
g
docs about what?
j
About any db being atomic
or more generic explanation is ACID: https://en.wikipedia.org/wiki/ACID
It’s not every database, I just assumed that it probably sqlite, because Vlastimil work on Android apps
also all common relational DBs are ACID
j
Thank you 🙏
u
What I meant was 2nd request might arrive sooner, so it enters the db transaction first i.e request1 sent at t0, request2 sent at t1, request2 response in t2, request1 response in t3
g
Why is it a problem?
If you worry that request with older data will arrive later, you can of course just pass update date as part of sql requeat and ignore older data
u
isnt that state smashing? request2 would carry the theoretically latest state or do we assume its fine since 99.999999% its the same?
g
But honestly for me it doesn't look like a real problem
No, it wouldn't be the same if you explicitly set what request has newer data, so db would compare last update time
Though, I'm not sure why you have such case with multiple requests for the same data which
If you have a single resource, wouldn't it be better to wrap it to some repository, which will ignore unnecessary duplicate requests. I believe duplicate requests are a bigger problem than the super small chance that one of the requests will aame 20ms older data than previous
u
well how would you deal with duplicates? if running then return? this means the suspend function would return successfully, lying to its callsite. So its either not care about concurrent requests, or throw, or Mutex, no?
Copy code
class DataRepository {
	suspend fun syncData() {
		val data = api.data()
		db.saveData(data)
	}
}
g
Well, this mutex not necessary should be mutex, also “Should I put Mutex everywhere” is not everywhere, but only on this syncData method
I see it something like this:
Copy code
class DataRepository(private val appScope: CoroutineScope) {
    private val syncJob: Job? = null
	suspend fun syncData() {
        if (syncJob?.isActive == true) {
            syncJob.join()
        } else {
            syncJob = scope.launch { 
              val data = api.data()
		      db.saveData(data)
            }
            syncDeferred?.await()
        }
	}
}
You can add atomic access to Job and mutex if want to make it completely thread safe Similar can be done with flow instead of job At least this approach avoid duplicate requests, also you can add cooldown time, like delay(SOME_DELAY_BEFORE_SYNC) after saveData, so no additional requests would be done
u
my issue with that is, this is only really a problem if responses come in different order to requests, which never happens so.. should I care? and its only valid if you get concurrent syncs which is practise is almost never
or maybe have a mutext at the api call level?
g
Global mutex will destroy all concurrency for network requests, which makes everything much slower
Why have global mutex, even in theory it a problem only when requesting the same data
u
Yea guess it doesnt matter if I put the mutex to left or right.
Its just almost all my GET api are not parametrized, so youre accessing the same resource, so such repo call, needs a mutex in your opinion? for every such domain specific sync?
g
Why do you need mutex for get requests? For sync yeah, it looks reasonable to have some mechanism preventing useless parallel requests, though I'm not sure that mutex is best solution, it will just prevent parallel requests, but then you will have multiple requests one after another receiving probably exactly the same data
u
because of force syncs, i.e. i have natural sync which sync every so often, and a force sync which overrides local flags, for example after a push message after som async action
my question actually is, is this even a issue? it only applies if parallel responses for the same resource arrive out of order, can that even happen?
g
It may happen in theory of course Force sync is easy to do with my example above, just pass a param like force, and cancel previous request If you always need force update, just always cancel previous active request (also easy to do if use Flow + mapLatest
u
well Id have to save with the job if the sync was force and not cancel it
and then quick return which is a lie
or throw which is a waste... or mutex
g
But you said that you have force update cases, in this case having one request after another is waste
I think you just should understand what kind semantics for requests (or sync, which I believe very different case) you would like to have, not trying to use some particular technical decision (like mutex) which has own, often not expected, behavior