@@ -164,60 +164,87 @@ export const quizAPI = {
164164 // AI 피드백 SSE 스트리밍 (주관식)
165165 streamAiFeedback : ( answerId : string , onData : ( data : string ) => void , onComplete : ( ) => void , onError : ( error : Event ) => void ) => {
166166 let isCompleted = false ;
167+ let eventSource : EventSource | null = null ;
167168
168- const eventSource = new EventSource ( `${ apiUrl } /quizzes/${ answerId } /feedback` , {
169- withCredentials : true
170- // EventSource는 자동으로 Accept: text/event-stream 헤더 설정
171- } ) ;
172-
173- eventSource . onmessage = ( event ) => {
174- if ( isCompleted ) return ;
169+ try {
170+ eventSource = new EventSource ( `${ apiUrl } /quizzes/${ answerId } /feedback` , {
171+ withCredentials : true
172+ // EventSource는 자동으로 Accept: text/event-stream 헤더 설정
173+ } ) ;
174+
175+ eventSource . onmessage = ( event ) => {
176+ if ( isCompleted ) return ;
177+
178+ // [종료] 메시지를 받으면 정상 종료
179+ if ( event . data === '[종료]' || event . data === '[완료]' || event . data === 'END' ) {
180+ isCompleted = true ;
181+ if ( eventSource ) {
182+ eventSource . close ( ) ;
183+ eventSource = null ;
184+ }
185+ onComplete ( ) ;
186+ return ;
187+ }
188+
189+ onData ( event . data ) ;
190+ } ;
175191
176- // [종료] 메시지를 받으면 정상 종료
177- if ( event . data === '[종료]' || event . data === '[완료]' || event . data === 'END' ) {
192+ eventSource . onerror = ( error ) => {
193+ if ( isCompleted ) return ; // 이미 정상 완료된 경우 에러 무시
194+
195+ console . log ( 'SSE 연결 에러 발생!' , new Date ( ) . toISOString ( ) ) ;
196+ console . log ( 'SSE 연결 에러:' , error ) ;
178197 isCompleted = true ;
179- eventSource . close ( ) ;
180- onComplete ( ) ;
181- return ;
182- }
198+ if ( eventSource ) {
199+ eventSource . close ( ) ;
200+ eventSource = null ;
201+ }
202+ onError ( error ) ;
203+ } ;
183204
184- onData ( event . data ) ;
185- } ;
186-
187- eventSource . onerror = ( error ) => {
188- if ( isCompleted ) return ; // 이미 정상 완료된 경우 에러 무시
205+ eventSource . addEventListener ( 'complete' , ( ) => {
206+ if ( ! isCompleted ) {
207+ isCompleted = true ;
208+ if ( eventSource ) {
209+ eventSource . close ( ) ;
210+ eventSource = null ;
211+ }
212+ onComplete ( ) ;
213+ }
214+ } ) ;
189215
190- console . log ( 'SSE 연결 에러:' , error ) ;
191- eventSource . close ( ) ;
192- onError ( error ) ;
193- } ;
194-
195- eventSource . addEventListener ( 'complete' , ( ) => {
196- if ( ! isCompleted ) {
197- isCompleted = true ;
198- eventSource . close ( ) ;
199- onComplete ( ) ;
200- }
201- } ) ;
202-
203- // 타임아웃 설정 (선택사항 - 너무 오래 걸리면 자동 종료)
204- const timeout = setTimeout ( ( ) => {
205- if ( ! isCompleted ) {
206- console . log ( 'SSE 스트리밍 타임아웃' ) ;
207- isCompleted = true ;
208- eventSource . close ( ) ;
209- onError ( new Event ( 'timeout' ) ) ;
210- }
211- } , 60000 ) ; // 60초 타임아웃
212-
213- // 정리 함수 반환
214- return {
215- close : ( ) => {
216- isCompleted = true ;
217- clearTimeout ( timeout ) ;
218- eventSource . close ( ) ;
219- }
220- } ;
216+ // 타임아웃 설정 (선택사항 - 너무 오래 걸리면 자동 종료)
217+ const timeout = setTimeout ( ( ) => {
218+ if ( ! isCompleted ) {
219+ console . log ( 'SSE 스트리밍 타임아웃' ) ;
220+ isCompleted = true ;
221+ if ( eventSource ) {
222+ eventSource . close ( ) ;
223+ eventSource = null ;
224+ }
225+ onError ( new Event ( 'timeout' ) ) ;
226+ }
227+ } , 60000 ) ; // 60초 타임아웃
228+
229+ // 정리 함수 반환
230+ return {
231+ close : ( ) => {
232+ isCompleted = true ;
233+ clearTimeout ( timeout ) ;
234+ if ( eventSource ) {
235+ eventSource . close ( ) ;
236+ eventSource = null ;
237+ }
238+ }
239+ } ;
240+ } catch ( error ) {
241+ console . error ( 'SSE 연결 생성 실패:' , error ) ;
242+ console . error ( '에러 상세:' , error ) ;
243+ onError ( error as Event ) ;
244+ return {
245+ close : ( ) => { }
246+ } ;
247+ }
221248 } ,
222249} ;
223250
0 commit comments