@@ -22,6 +22,7 @@ import {QualifiedId} from '@wireapp/api-client/lib/user/';
2222import { amplify } from 'amplify' ;
2323import ko from 'knockout' ;
2424import { container } from 'tsyringe' ;
25+ import { isError } from 'underscore' ;
2526
2627import { WebAppEvents } from '@wireapp/webapp-events' ;
2728
@@ -218,8 +219,25 @@ export class ContentViewModel {
218219 ) ;
219220 }
220221
221- private isConversationNotFoundError ( error : any ) : boolean {
222- return error . type === ConversationError . TYPE . CONVERSATION_NOT_FOUND ;
222+ private isConversationNotFoundError ( error : unknown ) : boolean {
223+ return isError ( error ) && 'type' in error && error . type === ConversationError . TYPE . CONVERSATION_NOT_FOUND ;
224+ }
225+
226+ private async retryFetchConversationWithBackoff (
227+ conversationId : QualifiedId ,
228+ maxRetries : number = 3 ,
229+ initialDelayMs : number = 100 ,
230+ ) : Promise < boolean > {
231+ for ( let attempt = 0 ; attempt < maxRetries ; attempt ++ ) {
232+ try {
233+ await new Promise ( resolve => setTimeout ( resolve , initialDelayMs * ( attempt + 1 ) ) ) ;
234+ await this . conversationRepository . fetchBackendConversationEntityById ( conversationId ) ;
235+ return true ;
236+ } catch ( error ) {
237+ this . logger . warn ( `Retry attempt ${ attempt + 1 } /${ maxRetries } failed for conversation fetch` , error ) ;
238+ }
239+ }
240+ return false ;
223241 }
224242
225243 /**
@@ -264,7 +282,6 @@ export class ContentViewModel {
264282 }
265283
266284 const isOpenedConversation = this . isConversationOpen ( conversationEntity , isActiveConversation ) ;
267-
268285 this . handleConversationState ( isOpenedConversation , openNotificationSettings , conversationEntity ) ;
269286 if ( ! isActiveConversation ) {
270287 this . conversationState . activeConversation ( conversationEntity ) ;
@@ -274,8 +291,20 @@ export class ContentViewModel {
274291 const messageEntity = openFirstSelfMention ? conversationEntity . getFirstUnreadSelfMention ( ) : exposeMessageEntity ;
275292 this . changeConversation ( conversationEntity , messageEntity ) ;
276293 this . showAndNavigate ( conversationEntity , openNotificationSettings , filePath ) ;
277- } catch ( error : any ) {
294+ } catch ( error : unknown ) {
278295 if ( this . isConversationNotFoundError ( error ) ) {
296+ // Retry fetching the conversation to handle race conditions
297+ const fetchSucceeded = await this . retryFetchConversationWithBackoff ( {
298+ id : conversation . domain ,
299+ domain : conversation . domain ,
300+ } ) ;
301+
302+ if ( fetchSucceeded ) {
303+ // Conversation was found after retry, attempt to show it again
304+ return this . showConversation ( conversation , options ) ;
305+ }
306+
307+ // All retries failed, show the error modal
279308 return this . showConversationNotFoundErrorModal ( ) ;
280309 }
281310
0 commit comments