mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-08-10 08:27:04 +00:00
fix(dm): pin the history floor so un-delivered relays don't re-page; add sentinel/bootstrap trace logs
The floor (now - 7d) was recomputed on every call, so it drifted forward over time. For a relay that hadn't delivered yet (reachedUntil == null), reachedUntilFor returned that drifting floor, so its marker's reached cursor kept changing, the sentinel's LaunchedEffect(reachedUntil) key changed, and it re-fired advance() — observed as rooms.nip04.history re-advancing a silent vitor.nostr1.com every ~15s, with the retry's 'until' moving NEWER each time. Pin the floor once per account/conversation for the session (matching the pre-rewrite behavior) in all three history loaders, so an un-delivered relay parks at a stable cursor and its sentinel fires once. Also add diagnostics to catch this class of bug quickly: one log line per marker sentinel fire (key + reachedUntil — a loop repeats the same key, a drift shows a moving cursor) and one per advanceAll (empty-feed bootstrap).
This commit is contained in:
+10
-4
@@ -100,8 +100,13 @@ class AccountGiftWrapsHistoryEoseManager(
|
||||
private val _relayProgress = MutableStateFlow<Map<NormalizedRelayUrl, RelayPagingProgress>>(emptyMap())
|
||||
val relayProgress: StateFlow<Map<NormalizedRelayUrl, RelayPagingProgress>> = _relayProgress.asStateFlow()
|
||||
|
||||
// History starts just below the live tail's one-week floor and pages backward from there.
|
||||
private fun startUntil() = TimeUtils.now() - AccountGiftWrapsEoseManager.LIVE_TAIL_SECONDS
|
||||
// History starts just below the live tail's one-week floor and pages backward from there. Pinned per
|
||||
// account for the session: it must NOT drift forward on every recompute, or an un-delivered relay's
|
||||
// marker (which sits at this floor) would keep changing and re-trigger its on-screen sentinel. The
|
||||
// live tail covers everything newer than the floor.
|
||||
private val pinnedFloor = ConcurrentHashMap<HexKey, Long>()
|
||||
|
||||
private fun startUntil(pk: HexKey) = pinnedFloor.getOrPut(pk) { TimeUtils.now() - AccountGiftWrapsEoseManager.LIVE_TAIL_SECONDS }
|
||||
|
||||
private fun daysAgo(epochSeconds: Long) = (TimeUtils.now() - epochSeconds) / TimeUtils.ONE_DAY
|
||||
|
||||
@@ -144,6 +149,7 @@ class AccountGiftWrapsHistoryEoseManager(
|
||||
account.dmRelays.flow.value
|
||||
.forEach { if (arm(user, it)) any = true }
|
||||
if (any) {
|
||||
Log.d(TAG) { "[giftwrap.history] advanceAll (empty-feed bootstrap)" }
|
||||
_exhausted.value = false
|
||||
updateStatus(user)
|
||||
invalidateFilters()
|
||||
@@ -159,7 +165,7 @@ class AccountGiftWrapsHistoryEoseManager(
|
||||
val account = accounts[user.pubkeyHex] ?: return false
|
||||
if (relay !in account.dmRelays.flow.value) return false
|
||||
if (loadTracker.isInFlight(relay)) return false
|
||||
if (!pager.advance(user.pubkeyHex, relay, startUntil())) return false
|
||||
if (!pager.advance(user.pubkeyHex, relay, startUntil(user.pubkeyHex))) return false
|
||||
stalledRelays[user.pubkeyHex]?.remove(relay)
|
||||
loadTracker.bind(account.scope)
|
||||
loadTracker.onAdvance(relay)
|
||||
@@ -190,7 +196,7 @@ class AccountGiftWrapsHistoryEoseManager(
|
||||
if (activeUser != user.pubkeyHex) return
|
||||
val relays = accounts[user.pubkeyHex]?.dmRelays?.flow?.value ?: emptySet()
|
||||
_relayCount.value = loadTracker.count()
|
||||
val start = startUntil()
|
||||
val start = startUntil(user.pubkeyHex)
|
||||
_reachedBack.value = pager.deepestReached(user.pubkeyHex, relays, start)
|
||||
val stalled = stalledRelays[user.pubkeyHex] ?: emptySet()
|
||||
_relayProgress.value =
|
||||
|
||||
+7
-1
@@ -40,6 +40,7 @@ import androidx.compose.ui.unit.sp
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.ui.theme.DividerThickness
|
||||
import com.vitorpamplona.amethyst.ui.theme.HalfPadding
|
||||
import com.vitorpamplona.quartz.utils.Log
|
||||
|
||||
/** How far one relay has paged into the conversation, for an in-stream progress marker. */
|
||||
enum class RelayReachState {
|
||||
@@ -109,7 +110,12 @@ fun RelayWindowLimitMarkers(
|
||||
// Keyed identity so the effect isn't torn down on reorder; keyed on the reached cursor ONLY so
|
||||
// it re-fires per landed page (continue while visible) but NOT on stall/unstall churn.
|
||||
key(lim.key) {
|
||||
LaunchedEffect(lim.reachedUntil) { lim.advance() }
|
||||
LaunchedEffect(lim.reachedUntil) {
|
||||
// One line per sentinel fire — a re-fire LOOP shows the same key firing over and over
|
||||
// (and whether its reached cursor is drifting, which would point at a non-pinned floor).
|
||||
Log.d("DMPagination") { "marker fire ${lim.key} reachedUntil=${lim.reachedUntil}" }
|
||||
lim.advance()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+8
-3
@@ -91,7 +91,11 @@ class ChatroomNip04HistorySubAssembler(
|
||||
private var activeConvo: ConvoKey? = null
|
||||
private val exhaustedByConvo = ConcurrentHashMap<ConvoKey, Boolean>()
|
||||
|
||||
private fun startUntil() = TimeUtils.now() - AccountGiftWrapsEoseManager.LIVE_TAIL_SECONDS
|
||||
// Pinned per conversation for the session — must not drift forward, or an un-delivered relay's marker
|
||||
// would keep moving and re-trigger its sentinel. See AccountGiftWrapsHistoryEoseManager.
|
||||
private val pinnedFloor = ConcurrentHashMap<ConvoKey, Long>()
|
||||
|
||||
private fun startUntil(pk: ConvoKey) = pinnedFloor.getOrPut(pk) { TimeUtils.now() - AccountGiftWrapsEoseManager.LIVE_TAIL_SECONDS }
|
||||
|
||||
override fun user(key: ChatroomQueryState) = key.account.userProfile()
|
||||
|
||||
@@ -141,6 +145,7 @@ class ChatroomNip04HistorySubAssembler(
|
||||
relays.all.forEach { if (arm(key, it)) any = true }
|
||||
}
|
||||
if (any) {
|
||||
Log.d("DMPagination") { "[convo.nip04.history] advanceAll (empty-thread bootstrap)" }
|
||||
_exhausted.value = false
|
||||
updateStatus()
|
||||
invalidateFilters()
|
||||
@@ -155,7 +160,7 @@ class ChatroomNip04HistorySubAssembler(
|
||||
if (relay !in relays.all) return false
|
||||
val pk = convoKey(key)
|
||||
if (loadTracker.isInFlight(relay)) return false
|
||||
if (!pager.advance(pk, relay, startUntil())) return false
|
||||
if (!pager.advance(pk, relay, startUntil(pk))) return false
|
||||
stalledRelays[pk]?.remove(relay)
|
||||
loadTracker.bind(key.account.scope)
|
||||
loadTracker.onAdvance(relay)
|
||||
@@ -182,7 +187,7 @@ class ChatroomNip04HistorySubAssembler(
|
||||
val pk = activeConvo ?: return
|
||||
val relays = relaysFor(pk) ?: return
|
||||
_relayCount.value = loadTracker.count()
|
||||
val start = startUntil()
|
||||
val start = startUntil(pk)
|
||||
_reachedBack.value = pager.deepestReached(pk, relays.all, start)
|
||||
val stalled = stalledRelays[pk] ?: emptySet()
|
||||
_relayProgress.value =
|
||||
|
||||
+8
-3
@@ -79,7 +79,11 @@ class ChatroomListNip04HistorySubAssembler(
|
||||
private val _relayProgress = MutableStateFlow<Map<NormalizedRelayUrl, RelayPagingProgress>>(emptyMap())
|
||||
val relayProgress: StateFlow<Map<NormalizedRelayUrl, RelayPagingProgress>> = _relayProgress.asStateFlow()
|
||||
|
||||
private fun startUntil() = TimeUtils.now() - AccountGiftWrapsEoseManager.LIVE_TAIL_SECONDS
|
||||
// Pinned per account for the session — must not drift forward, or an un-delivered relay's marker
|
||||
// would keep moving and re-trigger its sentinel. See AccountGiftWrapsHistoryEoseManager.
|
||||
private val pinnedFloor = ConcurrentHashMap<HexKey, Long>()
|
||||
|
||||
private fun startUntil(pk: HexKey) = pinnedFloor.getOrPut(pk) { TimeUtils.now() - AccountGiftWrapsEoseManager.LIVE_TAIL_SECONDS }
|
||||
|
||||
override fun user(key: ChatroomListState) = key.account.userProfile()
|
||||
|
||||
@@ -123,6 +127,7 @@ class ChatroomListNip04HistorySubAssembler(
|
||||
var any = false
|
||||
allRelays(account).forEach { if (arm(user, it)) any = true }
|
||||
if (any) {
|
||||
Log.d("DMPagination") { "[rooms.nip04.history] advanceAll (empty-feed bootstrap)" }
|
||||
_exhausted.value = false
|
||||
updateStatus(user)
|
||||
invalidateFilters()
|
||||
@@ -136,7 +141,7 @@ class ChatroomListNip04HistorySubAssembler(
|
||||
val account = accounts[user.pubkeyHex] ?: return false
|
||||
if (relay !in allRelays(account)) return false
|
||||
if (loadTracker.isInFlight(relay)) return false
|
||||
if (!pager.advance(user.pubkeyHex, relay, startUntil())) return false
|
||||
if (!pager.advance(user.pubkeyHex, relay, startUntil(user.pubkeyHex))) return false
|
||||
stalledRelays[user.pubkeyHex]?.remove(relay)
|
||||
loadTracker.bind(account.scope)
|
||||
loadTracker.onAdvance(relay)
|
||||
@@ -168,7 +173,7 @@ class ChatroomListNip04HistorySubAssembler(
|
||||
val account = accounts[user.pubkeyHex]
|
||||
val relays = account?.let { allRelays(it) } ?: emptySet()
|
||||
_relayCount.value = loadTracker.count()
|
||||
val start = startUntil()
|
||||
val start = startUntil(user.pubkeyHex)
|
||||
_reachedBack.value = pager.deepestReached(user.pubkeyHex, relays, start)
|
||||
val stalled = stalledRelays[user.pubkeyHex] ?: emptySet()
|
||||
_relayProgress.value =
|
||||
|
||||
Reference in New Issue
Block a user