2017-11-17 2 views
0

노드 JS 앱을 만들었습니다. 데이터베이스에서 100000 개가 넘는 레코드를 명시 적으로 다운로드하고 있습니다. 요청이 진행되는 동안 이전 요청이 완료되지 않으면 응답하지 않는 다른 브라우저에서 동일한 애플리케이션에 로그인하려고합니다. 어떤 생각? 이벤트 루프 또는 스레드와 관련된 작업은 무엇입니까 ?? 여기 내 논리가 있습니다. 1 단계에서 API 요청을합니다. API는 2 단계에서 데이터베이스 계층을 호출합니다. 데이터베이스는 단지 21 개의 레코드 만 반환합니다. json2csv의로드를 테스트하기 위해 무거운 렌더링을 만들기 위해 100000 * 21을 명시 적으로 반복하고 있습니다. 이렇게하는 동안 서버에 대한 다른 요청은 마지막 처리가 완료 될 때까지 응답하지 않습니다.노드 JS 요청이 다른 요청을 차단합니다.

Step 1: 

router.get('/report/downloadOverdueTrainings/:criteria', function (req, res, next) { 
     var overDueTrainings = []; 
     var reportManager = new ReportManager(); 
     var result = reportManager.getOverdueTrainings(JSON.parse(req.params.criteria)); 
     result.then(function (result) { 
      var fields = ['Over Due Trainings']; 
      for (var i = 0; i < 100000; i++) { //Testing purpose 
       for (var training of result) { 
        overDueTrainings.push({ 
         'Over Due Trainings': training.OverDueTrainings 
        }) 
       } 
      } 
      json2csv({ 
       data: overDueTrainings, 
       fields: fields 
      }, function (err, csv) { 
       if (err) 
        throw err; 
       res.setHeader('Content-disposition', 'attachment; filename=OverdueTrainings.csv'); 
       res.set('Content-Type', 'text/csv'); 
       res.send(csv); 
      }); 
     }).catch(function (err) { 
      next(err); 
     }); 
    }); 

Step 2: Database Logic 
var xtrDatabaseConnection =require('./xtrDatabaseConnection').XTRDatabaseConnection; 
     ReportData.prototype.getOverdueTrainings = async function (params) { 
     var connection = new xtrDatabaseConnection(); 
     var sequelize = connection.getSequelize(); 
     try { 
      var query = "CALL report_getOverdueTrainings(:p_CourseCode,:p_Revision,:p_RevisionNo,:p_UserGroup,:p_Username,:p_Status,:p_SortColoumnNo,:p_SortColoumnDirection,:p_callType,:p_StartIndex,:p_PageSize)"; 
      var replacements = { 
       p_CourseCode: params.CourseCode, 
       p_Revision: params.Revision, 
       p_RevisionNo: (params.RevisionNo == '' || params.RevisionNo == null) ? 0 : params.RevisionNo, 
       p_UserGroup: params.UserGroup, 
       p_Username: params.Username, 
       p_Status: params.Status, 
       p_SortColoumnNo: params.SortColoumnNo, 
       p_SortColoumnDirection: params.SortColoumnDirection, 
       p_callType: params.callType, 
       p_StartIndex: params.startIndex, 
       p_PageSize: params.pageSize 
      }; 
      //console.log(replacements); 
      return await connection.executeQuerySequelize(sequelize, query, Sequelize.QueryTypes.RAW, replacements); 
     } catch (e) { 
      throw (e); 
     } finally { 
      //To close connections 
      sequelize.connectionManager.close().then(() => console.log('Connection Closed')); 
     } 
    } 




XTRDatabaseConnection.prototype.executeQuerySequelize = function (sequelize, query, queryType, replacements) { 
    return sequelize.authenticate() 
     .then(() => { 
      return sequelize.query(query, { 
       replacements: replacements, 
       type: queryType 
      }). 
      then(result => result) 
       .catch(err => { 
        throw (err); 
       }); 
     }) 
     .catch(err => { 
      xtrUtility.logErrorsToWinstonTransports('Unable to connect to the database or some error occurred while executing your query. ', err); 
      throw new AppError(err, "dbError", "Unable to connect to the database or some error occurred while executing your query."); 
     }); 
} 
+0

어떤 오류가 발생 했습니까? –

+0

CSV 파일을 다운로드하라는 요청을 생성 할 때 어떤 오류도 발생하지 않습니다. 파일이 다운로드 될 때까지 응답하지 않는 다른 모든 기능을 수행합니다. 뭔가가 차단되고 있음을 의미합니다. –

+0

그것은 for 루프 때문에 이벤트 루프를 막았습니다. 클러스터 또는 자식 프로세스를 사용해 볼 수 있습니다 –

답변

0

이 차단되어 실행이 완료

for (var i = 0; i < 100000; i++) { //Testing purpose 
     for (var training of result) { 
      overDueTrainings.push({ 
       'Over Due Trainings': training.OverDueTrainings 
      }) 
     } 
    } 

때까지.

또한

var result = reportManager.getOverdueTrainings(JSON.parse(req.params.criteria)); 
    result.then(function (result) { 
/****/ 
return await connection.executeQuerySequelize(sequelize, query, Sequelize.QueryTypes.RAW, replacements); 
+0

이것이 실제로 차단되어 있고이 루프가 실행되는 동안 node.js 프로세스 (다른 이벤트 또는 요청 포함)의 다른 Javascript가 실행될 수 없기 때문에 이것이 왜 하향 투표되었는지 확실하지 않습니다. – jfriend00

+0

그래서 어떻게 이것을 루프의 대안으로 테스트 할 수 있습니까 ?? –

+0

@ jfriend00 예, 왜, 당신이 옳은지 모르겠어요. @ saad-zulfiqar 당신은 테스트 블록킹 부분을 백엔드에 넣어야합니다. –

0

NodeJS 단일 스레드, 하나의 프로세스이다. 자바 스크립트 기능이 실행되고있는 한 다른 것은 실행할 수 없습니다. 이는 의도적으로 설계된 동작입니다. 함수가 실행을 중지하면 이벤트 루프가 다시 시작됩니다.

+0

질문과 관련하여 나는 당신의 대답을 완전히 거부했습니다. node.js에는 많은 접근법이 있습니다. 나는 당신이 쓴 것을 동의했지만. –

+0

정말 질문이 없었지만 OP로 왜 그것을 차단하는지 묻습니다. 모든 주목받는 node.js 개발자가 해결 방법을 시작하기 전에 javascript 이벤트 루프를 이해하는 것이 중요하다고 생각합니다. – Evert

0

Node.js가 단일 스레드에서 작동 중입니다. 따라서 비동기 호출을 사용하여 작은 프로세스에 사용해야합니다. async/await을 사용하면 콜백 함수가 차단됩니다.

그래서 데이터베이스 기능을 반드시 사용해야합니다. 비동기로 작동합니다.

.query('CALL someFunction()') 
.then(function(response){ 
     //done 
    }).error(function(err){ 
    //error 
}); 

그러나 문제가 있습니다. 결과를 21 번로드해야합니다. 따라서이 경우 재귀 함수를 사용해야합니다. 재귀 호출을 완료하면 비동기로 클라이언트에 데이터를 보낼 수 있습니다.

관련 문제