Skip to content

Commit 9d2415a

Browse files
committed
fallback try catch
1 parent 9eb1210 commit 9d2415a

File tree

1 file changed

+73
-21
lines changed

1 file changed

+73
-21
lines changed

firebase-sessions/src/main/kotlin/com/google/firebase/sessions/SharedSessionRepository.kt

Lines changed: 73 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ import javax.inject.Inject
2727
import javax.inject.Singleton
2828
import kotlin.coroutines.CoroutineContext
2929
import kotlinx.coroutines.CoroutineScope
30+
import kotlinx.coroutines.flow.catch
3031
import kotlinx.coroutines.launch
32+
import org.jetbrains.annotations.VisibleForTesting
3133

3234
/** Repository to persist session data to be shared between all app processes. */
3335
internal interface SharedSessionRepository {
@@ -48,20 +50,37 @@ constructor(
4850
@Background private val backgroundDispatcher: CoroutineContext,
4951
) : SharedSessionRepository {
5052
/** Local copy of the session data. Can get out of sync, must be double-checked in datastore. */
51-
private lateinit var localSessionData: SessionData
53+
@VisibleForTesting lateinit var localSessionData: SessionData
54+
55+
/**
56+
* Either notify the subscribers with general multi-process supported session or fallback local
57+
* session
58+
*/
59+
private enum class NotificationType {
60+
GENERAL,
61+
FALLBACK
62+
}
5263

5364
init {
5465
CoroutineScope(backgroundDispatcher).launch {
55-
sessionDataStore.data.collect { sessionData ->
56-
localSessionData = sessionData
57-
val sessionId = sessionData.sessionDetails.sessionId
58-
59-
FirebaseSessionsDependencies.getRegisteredSubscribers().values.forEach { subscriber ->
60-
// Notify subscribers, regardless of sampling and data collection state
61-
subscriber.onSessionChanged(SessionSubscriber.SessionDetails(sessionId))
62-
Log.d(TAG, "Notified ${subscriber.sessionSubscriberName} of new session $sessionId")
66+
sessionDataStore.data
67+
.catch {
68+
val newSession =
69+
SessionData(
70+
sessionDetails = sessionGenerator.generateNewSession(null),
71+
backgroundTime = timeProvider.currentTime()
72+
)
73+
Log.d(
74+
TAG,
75+
"Init session datastore failed with exception message: ${it.message}. Emit fallback session ${newSession.sessionDetails.sessionId}"
76+
)
77+
emit(newSession)
78+
}
79+
.collect { sessionData ->
80+
localSessionData = sessionData
81+
val sessionId = sessionData.sessionDetails.sessionId
82+
notifySubscribers(sessionId, NotificationType.GENERAL)
6383
}
64-
}
6584
}
6685
}
6786

@@ -74,9 +93,14 @@ constructor(
7493
Log.d(TAG, "App backgrounded on ${getProcessName()} - $sessionData")
7594

7695
CoroutineScope(backgroundDispatcher).launch {
77-
sessionDataStore.updateData {
78-
// TODO(mrober): Double check time makes sense?
79-
sessionData.copy(backgroundTime = timeProvider.currentTime())
96+
try {
97+
sessionDataStore.updateData {
98+
// TODO(mrober): Double check time makes sense?
99+
sessionData.copy(backgroundTime = timeProvider.currentTime())
100+
}
101+
} catch (ex: Exception) {
102+
Log.d(TAG, "App backgrounded, failed to update data. Message: ${ex.message}")
103+
localSessionData = localSessionData.copy(backgroundTime = timeProvider.currentTime())
80104
}
81105
}
82106
}
@@ -91,15 +115,43 @@ constructor(
91115

92116
if (shouldInitiateNewSession(sessionData)) {
93117
CoroutineScope(backgroundDispatcher).launch {
94-
sessionDataStore.updateData { currentSessionData ->
95-
// Double-check pattern
96-
if (shouldInitiateNewSession(currentSessionData)) {
97-
val newSessionDetails = sessionGenerator.generateNewSession(sessionData.sessionDetails)
98-
sessionFirelogPublisher.mayLogSession(sessionDetails = newSessionDetails)
99-
currentSessionData.copy(sessionDetails = newSessionDetails)
100-
} else {
101-
currentSessionData
118+
try {
119+
sessionDataStore.updateData { currentSessionData ->
120+
// Double-check pattern
121+
if (shouldInitiateNewSession(currentSessionData)) {
122+
val newSessionDetails =
123+
sessionGenerator.generateNewSession(sessionData.sessionDetails)
124+
sessionFirelogPublisher.mayLogSession(sessionDetails = newSessionDetails)
125+
currentSessionData.copy(sessionDetails = newSessionDetails)
126+
} else {
127+
currentSessionData
128+
}
102129
}
130+
} catch (ex: Exception) {
131+
Log.d(TAG, "App appForegrounded, failed to update data. Message: ${ex.message}")
132+
val newSessionDetails = sessionGenerator.generateNewSession(sessionData.sessionDetails)
133+
localSessionData = localSessionData.copy(sessionDetails = newSessionDetails)
134+
sessionFirelogPublisher.mayLogSession(sessionDetails = newSessionDetails)
135+
136+
val sessionId = newSessionDetails.sessionId
137+
notifySubscribers(sessionId, NotificationType.FALLBACK)
138+
}
139+
}
140+
}
141+
}
142+
143+
private fun notifySubscribers(sessionId: String, type: NotificationType) {
144+
CoroutineScope(backgroundDispatcher).launch {
145+
FirebaseSessionsDependencies.getRegisteredSubscribers().values.forEach { subscriber ->
146+
// Notify subscribers, regardless of sampling and data collection state
147+
subscriber.onSessionChanged(SessionSubscriber.SessionDetails(sessionId))
148+
if (type == NotificationType.GENERAL) {
149+
Log.d(TAG, "Notified ${subscriber.sessionSubscriberName} of new session $sessionId")
150+
} else {
151+
Log.d(
152+
TAG,
153+
"Notified ${subscriber.sessionSubscriberName} of new fallback session $sessionId"
154+
)
103155
}
104156
}
105157
}

0 commit comments

Comments
 (0)