티스토리 뷰

주어진 문제

아래처럼 구조 요청을 보내면 현재 1km안에 위치한 사람들을 확인 할수가 있다.

현재는 1km안에 있는 사람만 찾아서 알림을 보낼수가 있다.

하지만 우리는 1km ~ 2km ~ 3km ~ 를 탐색하면서 나를 도와줄수 있는 사람을 찾는걸 원한다.

 

또한 우리는 헬퍼가 어떻게 수락한걸 찾을수 있을 지 고민해야했다.

1. 1km안에 있는 헬퍼들에게 알림 보내기
2. 헬퍼들이 수락을 누르게 되면 디비에 정보가 쌓임
3. 정보가 쌓이지 않으면 헬퍼들이 수락을 누르지 않은 것임
4. 첫번째알림을 보낸지 3분이 지나도 수락이 쌓이지 않았는지 확인
5. 2km로 거리를 늘려 2km안에 있는 헬퍼들에게 알림을 다시보냄
6. 3분동안 DB를 확인하면서 DB에 helper_id가 null이 아닌지 확인
7. 총 6분이 지났는데도 안잡힌다면 다시 3km로 거리를 늘려 알림을 다시보냄
8. 마지막으로 9분이 지났는데도 잡히지 않는다면 알림 보내는 것을 멈춘다.

 

이런순서로 다시 한번 생각을 해보았다.

 

일단 생각나는대로 로직을 짜봤다.

    // 알림 요청이 수락됬는지 확인하기 -> db를 돌아보며 null이 아니라면 수락이 된것.
    // 알림 요청이 수락이 안됬다면 다음으로 넘어가기
   if (true) {
      const helpers = await this.findHelperDistance(
        1000,
        user.location.latitude,
        user.location.longitude,
      );
      console.log('helpers => ', helpers);
    } else if (true) {
      await this.findHelperDistance(
        2000,
        user.location.latitude,
        user.location.longitude,
      );
    } else if (true) {
      await this.findHelperDistance(
        3000,
        user.location.latitude,
        user.location.longitude,
      );
    } else {
    }

 

일단 다 조건을줘서 이런 방식으로 했어야 했다.

일단 이렇게 진행 된다는것만 생각하고 넘어갔다.

 

 

시도 해본것.

Task Scheduling 적용하기

cron, Interval을 사용해서 시도해 보려 했다.

하지만 스케줄러는 우리가 직접해야 하는 일을 자동적으로 해주는 것이였다.

이 말은 즉, 서버가 시작되면 자동적으로 계속 계속해서 돌아가는것이였다.

 

이방법은 우리와 맞지 않았다.

우리는 api가 호출될때 그때만 자동적으로 2분가량 시간이 지남에 따라 구조자가 수락하지 않으면 거리를 넓혀가며

찾기를 원했다.

 

 

setInterval 적용하기

그 다음 생각한것이 setInterval이다.

서버가 자동으로 실행하면 안된다. 그럼 우리가 api를 눌렀을때 작동하게 하면 되지 않는가?

    private setIntervalId: NodeJS.Timeout;
    
  async sendRequestRescue(){
  	 
     const message;
     this.setIntervalId = setInterval(
       async () => {
         currentDistance += 1000;
         message = await this.checkHelperResponse(
           userId,
           currentDistance,
           user.location.latitude,
           user.location.longitude,
           user.name,
           context,
         );
         console.log('최종 나온 메세지 => ', message);
       },
       // 3 * 60 * 1000,
       60 * 1000,
     );
     
     return message
  }
  
  async checkHelperResponse(){
    const record = await this.findGetMaydayRecord(userId);
    console.log('distance => ', distance);

    if (record.helper_id) {
      clearInterval(this.setIntervalId);
      console.log('헬퍼아이디가 있다면 setInterval멈추기 진입');
      return { message: 'Accepted' };
      
    } else if (distance > 3000) {
      clearInterval(this.setIntervalId);
      console.log('총 9분이 지나 setInterval멈추기 진입');
      return { message: 'NotAccept' };
      
    } else if (_.isNil(record.helper_id)) {
      await this.sendAlert(distance, latitude, longitude, name, message);
      console.log('시간도 안지났고 헬퍼아이디도 없어서 재알림 보냄');
    }
  
  }

디비를 정해진 시간마다 왔다 갔다 하면서 체크해주면서 조건문을 왔다갔다 하면 됐다.

이거다!! 라고 생각을 하고 보니 결과값의 message는 항상 undefined로 들어갔다..

왜지..? 아니 정해진 조건에 부합하게 setInterval로 this로 멈춰줬는데 왜 값이 안들어가지 ?

전역변수로 message도 줬는데 왜 안들어가는거지?

라고 생각을 했다..

 

여기서 문제는 JavaScript 의 시스템을 제대로 이해하고 있지 않아서 발생한 문제였다.

JavaScript에서 setInterval은 비동기적으로 실행되며, return문은 동기적으로 실행된다.

따라서 setInterval이 실행되고 있을 때

return문이 먼저 실행되어 해당 시점에는 message 변수가 아직 값이 할당되지 않은 상태일 수 있다.

즉, setInterval은 이벤트 루프안에서 돌지만 return은 동기식으로 스택에 쌓여 먼저 진행되기 때문에 발생한문제였다.

 

promise사용하여 setInterval 적용하기

그렇게 다시 생각해볼수 있는게 이 방법은 틀린 방법은 아니였다.

다만 우리는 return을 하기 전에 settime함수를 끝내고 return을 해야한다.

우리는 비동기 작업을 다 완료한 후에 값을 반환하는 Promise를 적용시켜 봤다.

    const checkHelperResponsePromise = (userId,currentDistance,latitude, longitude,name,context) => {
      return new Promise((resolve) => {
        const setIntervalId = setInterval(async () => {
          currentDistance += 1000;
          const message = await this.checkHelperResponse(userId,currentDistance,latitude,longitude,name, context,setIntervalId);
          if (message) {
            resolve(message); // Promise 완료
          }
        }, 30 * 1000);
      });
    };
    return await checkHelperResponsePromise(userId, currentDistance,user.location.latitude, user.location.longitude, user.name, context,);


  async checkHelperResponse(userId: number,distance: number,latitude: number, longitude: number,name: string,message: string,setIntervalId) {
    const record = await this.findGetMaydayRecord(userId);

    if (record.helper_id) {
      clearInterval(setIntervalId);
      return { message: 'Accepted' };
      
    } else if (distance > 3000) {
      clearInterval(setIntervalId);
      return { message: 'NotAccept' };
      
    } else if (_.isNil(record.helper_id)) {
      await this.sendAlert(distance, latitude, longitude, name, message);

    }
  }

위처럼 SetInterval을 다 돈다음에 해당하는 return message값을 반환하여 컨트롤러에 전해준뒤

프론트에서 해결하면 되는 문제였다.

 

즉 유저와 헬퍼사이를 주기적으로 확인을 하면서 서로의 상호작용을 완료할수가 있었다.

그런뒤 우리는

프론트 쪽에서 메세지 문자열을 받아 가공하여 처리하면 되었다.

      if (response.ok) {
        const responseData = await response.json();
        // 여기서 헬퍼가 수락완료한 정보가 있는 페이지로 넘어가는거지
        // 여기서 그걸 구분하는것은 message
        
        // message가 NotAccept라면 다시 요청 페이지로 넘어가기
        if (responseData.message === 'NotAccept') {
          alert('요청이 수락되지 않았습니다..')
          window.location.href = '/mayday/findHelper'
        } else if (responseData.message === 'Accepted') {
          alert('헬퍼가 수락을 하였습니다.!!')
        }

        // message가 Accept라면 헬퍼가 수락완료한 정보가 있는 페이지로 넘어가기
      } else {
        console.error('요청 실패:', response.statusText);
        alert('요청 실패하였습니다..')
        window.location.href = '/mayday/findHelper'
      }

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함