@@ -26,6 +26,18 @@ import { FederationService } from './federation.service';
2626import { MissingEventService } from './missing-event.service' ;
2727import { PartialStateResolutionError , StateService } from './state.service' ;
2828
29+ const MAX_EVENT_RETRY =
30+ ( ( maxRetry ?: string ) => {
31+ if ( ! maxRetry ) return ;
32+
33+ const n = Number . parseInt ( maxRetry , 10 ) ;
34+ if ( ! Number . isNaN ( n ) && n >= 0 ) {
35+ return n ;
36+ }
37+
38+ throw new Error ( 'Invalid MAX_EVENT_RETRY value' ) ;
39+ } ) ( process . env . MAX_EVENT_RETRY ) ?? 10 ;
40+
2941class MissingAuthorizationEventsError extends Error {
3042 constructor ( message : string ) {
3143 super ( message ) ;
@@ -62,16 +74,6 @@ export class StagingAreaService {
6274 }
6375
6476 async processEventForRoom ( roomId : string ) {
65- let event = await this . eventService . getLeastDepthEventForRoom ( roomId ) ;
66- if ( ! event ) {
67- this . logger . debug ( { msg : 'No staged event found for room' , roomId } ) ;
68- await this . lockRepository . releaseLock (
69- roomId ,
70- this . configService . instanceId ,
71- ) ;
72- return ;
73- }
74-
7577 const roomIdToRoomVersion = new Map < string , RoomVersion > ( ) ;
7678 const getRoomVersion = async ( roomId : string ) => {
7779 if ( roomIdToRoomVersion . has ( roomId ) ) {
@@ -88,9 +90,32 @@ export class StagingAreaService {
8890 return PersistentEventFactory . createFromRawEvent ( pdu , version ) ;
8991 } ;
9092
91- while ( event ) {
93+ let event : EventStagingStore | null = null ;
94+
95+ do {
96+ event = await this . eventService . getLeastDepthEventForRoom ( roomId ) ;
97+ if ( ! event ) {
98+ this . logger . debug ( { msg : 'No staged event found for room' , roomId } ) ;
99+ break ;
100+ }
101+
102+ if ( event . got > MAX_EVENT_RETRY ) {
103+ this . logger . warn (
104+ `Event ${ event . _id } has been tried ${ MAX_EVENT_RETRY } times, removing from staging area` ,
105+ ) ;
106+ await this . eventService . markEventAsUnstaged ( event ) ;
107+ continue ;
108+ }
109+
92110 this . logger . info ( { msg : 'Processing event' , eventId : event . _id } ) ;
93111
112+ // if we got an event, we need to update the lock's timestamp to avoid it being timed out
113+ // and acquired by another instance while we're processing a batch of events for this room
114+ await this . lockRepository . updateLockTimestamp (
115+ roomId ,
116+ this . configService . instanceId ,
117+ ) ;
118+
94119 try {
95120 const addedMissing = await this . processDependencyStage ( event ) ;
96121 if ( addedMissing ) {
@@ -123,33 +148,18 @@ export class StagingAreaService {
123148 } ) ;
124149 } else if ( err instanceof MissingEventsError ) {
125150 this . logger . info ( {
126- msg : 'Added missing events, postponing current event processing' ,
151+ msg : 'Added missing events, postponing event processing' ,
127152 eventId : event . _id ,
128153 } ) ;
129154 } else {
130155 this . logger . error ( {
131- msg : 'Error processing event' ,
156+ msg : 'Error processing event, postponing event processing ' ,
132157 event,
133158 err,
134159 } ) ;
135-
136- await this . eventService . markEventAsUnstaged ( event ) ;
137160 }
138161 }
139-
140- // TODO: what should we do to avoid infinite loops in case the next event is always the same event
141-
142- event = await this . eventService . getLeastDepthEventForRoom ( roomId ) ;
143-
144- // if we got an event, we need to update the lock's timestamp to avoid it being timed out
145- // and acquired by another instance while we're processing a batch of events for this room
146- if ( event ) {
147- await this . lockRepository . updateLockTimestamp (
148- roomId ,
149- this . configService . instanceId ,
150- ) ;
151- }
152- }
162+ } while ( event ) ;
153163
154164 // release the lock after processing
155165 await this . lockRepository . releaseLock (
0 commit comments