Skip to content

Commit b3f200e

Browse files
authored
Merge pull request #2363 from digma-ai/support-no-connection-in-auto-refresh
support no connection in auto refresh
2 parents 59f01ef + a447f04 commit b3f200e

File tree

2 files changed

+82
-41
lines changed

2 files changed

+82
-41
lines changed

ide-common/src/main/kotlin/org/digma/intellij/plugin/analytics/ApiErrorHandler.kt

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ class ApiErrorHandler : DisposableAdaptor {
6969
return myConnectionLostFlag.get()
7070
}
7171

72+
fun isConnectionOK(): Boolean {
73+
return !myConnectionLostFlag.get()
74+
}
7275

7376
//log connection exceptions only the first time and show an error notification.
7477
// while status is in error, following connection exceptions will not be logged, other exceptions
@@ -79,6 +82,7 @@ class ApiErrorHandler : DisposableAdaptor {
7982
method: Method,
8083
args: Array<Any?>?
8184
) {
85+
Log.log(logger::trace, "handleInvocationTargetException called with exception {}", findRootCause(invocationTargetException))
8286
try {
8387
myLock.lock()
8488
handleInvocationTargetExceptionImpl(project, invocationTargetException, method, args)
@@ -89,6 +93,7 @@ class ApiErrorHandler : DisposableAdaptor {
8993
if (myLock.isHeldByCurrentThread) {
9094
myLock.unlock()
9195
}
96+
Log.log(logger::trace, "handleInvocationTargetException completed")
9297
}
9398
}
9499

@@ -102,6 +107,8 @@ class ApiErrorHandler : DisposableAdaptor {
102107

103108
//todo: maybe show no connection on CantConstructClientException
104109

110+
Log.log(logger::trace, "handleInvocationTargetExceptionImpl called with exception {}", findRootCause(invocationTargetException))
111+
105112
val connectException =
106113
findConnectException(invocationTargetException) ?: findSslException(invocationTargetException)
107114

@@ -118,10 +125,15 @@ class ApiErrorHandler : DisposableAdaptor {
118125
)
119126

120127
if (isConnectionOK()) {
128+
Log.log(logger::trace, "connection ok, checking if need to mark connection lost")
129+
121130
//if more than one thread enter this section the worst that will happen is that we
122131
// report the error more than once but connectionLost will be fired once because
123-
// markConnectionLostAndNotify locks, marks and notifies only if connection ok.
132+
// markConnectionLostAndNotify is under lock, marks and notifies only if connection ok.
124133
if (isConnectionException) {
134+
135+
Log.log(logger::trace, "error is connection exception, calling markConnectionLostAndNotify")
136+
125137
markConnectionLostAndNotify()
126138
errorReportingHelper.addIfNewError(invocationTargetException)
127139
Log.warnWithException(
@@ -142,6 +154,9 @@ class ApiErrorHandler : DisposableAdaptor {
142154
}
143155

144156
} else {
157+
158+
Log.log(logger::trace, "error is not a connection exception,doing nothing")
159+
145160
Log.warnWithException(
146161
logger,
147162
invocationTargetException,
@@ -167,6 +182,7 @@ class ApiErrorHandler : DisposableAdaptor {
167182
} else {
168183

169184
//connection is not ok, marked lost
185+
Log.log(logger::trace, "already in no connection mode")
170186

171187
//if the callerProject is opened after connection is already marked lost this project doesn't know about it.
172188
// notify the project that there is no connection
@@ -208,10 +224,14 @@ class ApiErrorHandler : DisposableAdaptor {
208224
if (myLock.isHeldByCurrentThread) {
209225
myLock.unlock()
210226
}
227+
Log.log(logger::trace, "handleAuthManagerCantConnectError completed")
211228
}
212229
}
213230

214231
fun handleAuthManagerCantRefreshError(throwable: Throwable) {
232+
233+
Log.log(logger::trace, "handleAuthManagerCantRefreshError called with exception {}", throwable)
234+
215235
//todo: currently only reporting
216236
Log.warnWithException(logger, throwable, "error in AuthManager {}", throwable)
217237

@@ -229,6 +249,7 @@ class ApiErrorHandler : DisposableAdaptor {
229249
)
230250
}
231251
}
252+
Log.log(logger::trace, "handleAuthManagerCantRefreshError completed")
232253
}
233254

234255

@@ -237,11 +258,11 @@ class ApiErrorHandler : DisposableAdaptor {
237258
// us out of it so user must know about it.
238259
//it's not like handleInvocationTargetException from AnalyticsService which may or may not be a connection issue and next call
239260
// may succeed. without login we can't do anything.
240-
//the user will see the no connection screen and can click refresh, on refresh we call AuthManager to try
241-
// login or refresh again and if it will succeed the connection will be refreshed.
261+
//the user will see the no connection screen and can click refresh, on refresh we call BackendInfoHolder..refresh() and
262+
// refreshEnvironments that should refresh the connection mode and trigger loginOrRefresh if the connection is.
242263
private fun handleAuthManagerErrorImpl(throwable: Throwable, project: Project?) {
243264
Log.warnWithException(logger, throwable, "got AuthManager error {}", throwable)
244-
Log.log(logger::warn, "showing no connection on AuthManager error {}", throwable)
265+
Log.log(logger::trace, "calling markConnectionLostAndNotify on AuthManager error {}", throwable)
245266
markConnectionLostAndNotify()
246267

247268
//if a project is opened after connection is already marked lost the project doesn't know about it.
@@ -258,7 +279,7 @@ class ApiErrorHandler : DisposableAdaptor {
258279
//must run in a lock
259280
private fun markConnectionLostAndNotify() {
260281

261-
Log.log(logger::warn, "markConnectionLostAndNotify called")
282+
Log.log(logger::trace, "markConnectionLostAndNotify called")
262283

263284
//this is the second critical section of the race condition,
264285
// we are in error state so the performance penalty of locking is insignificant.
@@ -277,9 +298,11 @@ class ApiErrorHandler : DisposableAdaptor {
277298
myConnectionStatusNotifyAlarm.cancelAllRequests()
278299
myConnectionStatusNotifyAlarm
279300
.addRequest({
280-
Log.log(logger::warn, "notifying connectionLost")
301+
Log.log(logger::trace, "notifying connectionLost")
281302
fireConnectionLost()
282303
}, 2000)
304+
} else {
305+
Log.log(logger::trace, "already in no connection mode")
283306
}
284307

285308
}
@@ -313,6 +336,7 @@ class ApiErrorHandler : DisposableAdaptor {
313336
// if marked but never reset and to make sure that if we notified connectionLost we will also notify when its gained back.
314337

315338
myLock.lock()
339+
Log.log(logger::trace, "resetting connection mode after connection lost")
316340
resetConnectionLostAndNotifyIfNecessaryImpl()
317341

318342
} catch (e: Throwable) {
@@ -357,11 +381,6 @@ class ApiErrorHandler : DisposableAdaptor {
357381
}
358382

359383

360-
private fun isConnectionOK(): Boolean {
361-
return !myConnectionLostFlag.get()
362-
}
363-
364-
365384
private fun registerConnectionLostEvent() {
366385
findActiveProject()?.let { project ->
367386
ActivityMonitor.getInstance(project).registerConnectionLost()

ide-common/src/main/kotlin/org/digma/intellij/plugin/auth/AuthManager.kt

Lines changed: 52 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -480,55 +480,76 @@ class AuthManager(private val cs: CoroutineScope) : Disposable {
480480
while (isActive) {
481481

482482
try {
483-
Log.log(logger::trace, "${coroutineContext[CoroutineName]} looking for account")
484-
485-
val account = DigmaDefaultAccountHolder.getInstance().account
486-
if (account != null) {
487-
Log.log(logger::trace, "${coroutineContext[CoroutineName]} found account {}", account)
488-
489-
val credentials = try {
490-
//exception here may happen if we change the credentials structure,which doesn't happen too much,
491-
// user will be redirected to log in again
492-
DigmaAccountManager.getInstance().findCredentials(account)
493-
} catch (_: Throwable) {
494-
null
495-
}
496483

497-
if (credentials != null) {
484+
if (ApiErrorHandler.getInstance().isNoConnectionMode()) {
485+
Log.log(logger::trace, "${coroutineContext[CoroutineName]} no connection, waiting 10 minutes")
486+
delay = 10.minutes
487+
} else {
498488

499-
Log.log(logger::trace, "${coroutineContext[CoroutineName]} found credentials for account {}", account)
489+
Log.log(logger::trace, "${coroutineContext[CoroutineName]} looking for account")
490+
491+
val account = DigmaDefaultAccountHolder.getInstance().account
492+
val credentials = account?.let {
493+
try {
494+
//exception here may happen if we change the credentials structure,which doesn't happen too much,
495+
// user will be redirected to log in again
496+
DigmaAccountManager.getInstance().findCredentials(it)
497+
} catch (_: Throwable) {
498+
null
499+
}
500+
}
501+
502+
if (account == null) {
503+
Log.log(logger::trace, "${coroutineContext[CoroutineName]} account not found, waiting 10 minutes")
504+
delay = 10.minutes
505+
} else if (credentials == null) {
506+
//if credentials not found it will probably be created soon
507+
Log.log(logger::trace, "${coroutineContext[CoroutineName]} credentials for account not found, waiting 1 minute")
508+
delay = 1.minutes
509+
} else {
510+
Log.log(logger::trace, "${coroutineContext[CoroutineName]} found account and credentials {}", account)
500511

501512
val expireIn =
502-
max(0, (credentials.expirationTime - Clock.System.now().toEpochMilliseconds())).toDuration(DurationUnit.MILLISECONDS)
513+
max(
514+
0,
515+
(credentials.expirationTime - Clock.System.now().toEpochMilliseconds())
516+
).toDuration(DurationUnit.MILLISECONDS)
517+
503518
if (expireIn <= 1.minutes) {
504519
Log.log(
505520
logger::trace,
506-
"${coroutineContext[CoroutineName]} credentials for account expires in {} , refreshing account {}",
521+
"${coroutineContext[CoroutineName]} credentials expires in {} , refreshing account {}",
507522
expireIn,
508523
account
509524
)
510-
val loginHandler = LoginHandler.createLoginHandler(myAnalyticsProvider)
511-
loginHandler.refresh(account, credentials, "auto refresh job")
512-
fireChange()
513-
Log.log(logger::trace, "${coroutineContext[CoroutineName]} credentials for account refreshed {}", account)
514-
//immediately loop again and compute the next delay
515-
delay = ZERO
525+
526+
val refreshSuccess = try {
527+
val loginHandler = LoginHandler.createLoginHandler(myAnalyticsProvider)
528+
loginHandler.refresh(account, credentials, "auto refresh job")
529+
} catch (e: Throwable) {
530+
false
531+
}
532+
533+
if (refreshSuccess) {
534+
fireChange()
535+
Log.log(logger::trace, "${coroutineContext[CoroutineName]} credentials for account refreshed {}", account)
536+
//immediately loop again and compute the next delay
537+
delay = ZERO
538+
} else {
539+
Log.log(logger::trace, "${coroutineContext[CoroutineName]} refresh failed, waiting 5 minutes")
540+
delay = 5.minutes
541+
}
516542
} else {
517-
delay = max(0L, (expireIn.inWholeMilliseconds - 1.minutes.inWholeMilliseconds)).toDuration(DurationUnit.MILLISECONDS)
543+
delay =
544+
max(0L, (expireIn.inWholeMilliseconds - 1.minutes.inWholeMilliseconds)).toDuration(DurationUnit.MILLISECONDS)
518545
Log.log(
519546
logger::trace,
520547
"${coroutineContext[CoroutineName]} credentials for account expires in {}, waiting {}",
521548
expireIn,
522549
delay
523550
)
524551
}
525-
} else {
526-
Log.log(logger::trace, "${coroutineContext[CoroutineName]} credentials for account not found, waiting 1 minute")
527-
delay = 1.minutes
528552
}
529-
} else {
530-
Log.log(logger::trace, "${coroutineContext[CoroutineName]} account not found, waiting 10 minutes")
531-
delay = 10.minutes
532553
}
533554

534555
if (delay > ZERO) {
@@ -553,6 +574,7 @@ class AuthManager(private val cs: CoroutineScope) : Disposable {
553574
} catch (e: Throwable) {
554575
Log.warnWithException(logger, e, "${coroutineContext[CoroutineName]} error in autoRefreshJob")
555576
ErrorReporter.getInstance().reportError("AuthManager.autoRefreshJob", e)
577+
Log.log(logger::trace, "${coroutineContext[CoroutineName]} error from refresh, waiting 5 minutes")
556578
}
557579
}
558580

0 commit comments

Comments
 (0)