mirror of
https://github.com/greenart7c3/Amber.git
synced 2026-10-06 03:18:23 +00:00
Merge #1ed68583: Debounce relay-status counter updates (notification ra…
Debounce relay-status counter updates (notification rate limit) nostr:nevent1qqspa459s04qpe5h3k6m0dg2amne9fl247pxjk3w6ylnq7m4rw3pk2cpz3mhxue69uhhyetvv9ujumn8d96zuer9wc4mf4tk PR-Author: greenart7c3 nostr:npub1w4uswmv6lu9yel005l3qgheysmr7tk9uvwluddznju3nuxalevvs2d0jr5 PR description: Fixes the relay-status notification (id=2) hitting Android's per-app notification rate limit during relay activity bursts. addSent/addFailed called notify(2) synchronously for every relay event (NostrClientLoggerListener.onSent), so bursts of 7-34 notifies/sec against the ~5/sec limit were shed by NotificationManagerService and the status notification froze on stale text. The counter path now emits Unit ticks into a MutableSharedFlow (capacity 1, DROP_OLDEST) collected with debounce(300): a burst collapses into one notification update, the last tick always renders, and tryEmit never suspends or fails on Quartz IO threads. No numeric counter, so nothing overflows or wraps no matter how long the process runs. Connection-state updates keep their existing debounce so connect/disconnect still shows promptly. Issue: nevent1qy28wumn8ghj7un9d3shjtnwva5hgtnyv4mqqg80gw6ushd8jyj6rt8qseup7hngj0xhqa2ms3dvam60lhc760zvkyq6uts9 Validated: ktlintCheck, lint, :app:testFreeDebugUnitTest.
This commit is contained in:
@@ -25,6 +25,8 @@ import com.vitorpamplona.quartz.nip01Core.relay.client.NostrClient
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.displayUrl
|
||||
import kotlinx.coroutines.FlowPreview
|
||||
import kotlinx.coroutines.channels.BufferOverflow
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.debounce
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
@@ -39,6 +41,23 @@ class AmberRelayStats(
|
||||
var available = emptySet<NormalizedRelayUrl>()
|
||||
var connected = emptySet<NormalizedRelayUrl>()
|
||||
|
||||
// Counter updates arrive per relay event (NostrClientLoggerListener.onSent),
|
||||
// which can burst at 30+ events/sec and trip Android's per-app notification
|
||||
// rate limit (~5/sec): NotificationManager sheds every update and the status
|
||||
// notification freezes on stale text until the burst ends. Emitting a tick
|
||||
// defers notify() to the debounced collector started in
|
||||
// createNotificationChannel(), so a burst collapses into one notification
|
||||
// update. Connection-state changes keep their own (also debounced)
|
||||
// collectors so connect/disconnect still shows promptly.
|
||||
// Unit events instead of a numeric counter: nothing to overflow or wrap no
|
||||
// matter how long the app runs. DROP_OLDEST + capacity 1 keeps only the
|
||||
// newest tick, so tryEmit never fails and the last event of a burst always
|
||||
// renders.
|
||||
private val counterTick = MutableSharedFlow<Unit>(
|
||||
extraBufferCapacity = 1,
|
||||
onBufferOverflow = BufferOverflow.DROP_OLDEST,
|
||||
)
|
||||
|
||||
@OptIn(FlowPreview::class)
|
||||
@SuppressLint("MissingPermission")
|
||||
val relayStatus = combine(client.availableRelaysFlow(), client.connectedRelaysFlow()) { available, connected ->
|
||||
@@ -107,6 +126,14 @@ class AmberRelayStats(
|
||||
updateNotification()
|
||||
}
|
||||
}
|
||||
Amber.instance.applicationIOScope.launch {
|
||||
// Trailing-edge debounce for the counter path (addSent/addFailed):
|
||||
// the last tick of a burst always renders, at most one notify per
|
||||
// 300ms window.
|
||||
counterTick.debounce(300).collect {
|
||||
updateNotification()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val innerCache = mutableMapOf<NormalizedRelayUrl, AmberRelayStat>()
|
||||
@@ -253,12 +280,16 @@ class AmberRelayStats(
|
||||
|
||||
fun addSent(url: NormalizedRelayUrl) {
|
||||
get(url).addSent()
|
||||
updateNotification()
|
||||
scheduleNotificationUpdate()
|
||||
}
|
||||
|
||||
fun addFailed(url: NormalizedRelayUrl) {
|
||||
get(url).addFailed()
|
||||
updateNotification()
|
||||
scheduleNotificationUpdate()
|
||||
}
|
||||
|
||||
private fun scheduleNotificationUpdate() {
|
||||
counterTick.tryEmit(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user