Node.JS для стартапа или о проблемах на продакшене

в 13:49, , рубрики: javascript, mongodb, node.js, метки: , ,

Доброго времени суток. Мне хотелось бы поделится с хабросообществом о своем опыте использования Node.JS на живом проекте. Пять месяцев назад я начал воплощать одну из своих старых задумок — сервис достижений.
Node.JS для стартапа или о проблемах на продакшене
При разработке проектов я предпочитаю придерживаться точке зрения, что выбор технологии должен быть обоснован дешевизной ее использования. Поэтому для своего проекта я выбрал стек — Node.JS + mongoDB, так как это те технологии, которыми я лучше всего владею.


Хочу заметить, что здесь я буду описывать только те проблемы с которыми сталкивался сам.

Принудительная Асинхронность

Node.JS известен своей идеологией в том, что все вызовы I/O должны происходить асинхронно. Такой подход предоставляет очень широкие возможности, хотя иногда и приводит к определенным проблемам. Например банальная ситуация — необходимо сделать запрос к БД и на основе результата сделать еще один запрос, например в другую таблицу. По религиозным причинам я не использовал mongoose(ORM для mongodb). В связи с этим использовал node-mongodb-native. Проблема в том, что при использовании этого модуля приходится работать с курсором БД, что приводит к появлению лишнего колбэка:

db.collection('table', function(err, collection) {
  collection.findOne({uid:uid}, function(err, doc) {
    cb(doc);
  });
});

Таким образом описанная выше задача сводится к банальному колбэк хэллу:

db.collection('table', function(err, collection) {
  collection.findOne({uid:uid}, function(err, doc) {
    db.collection('table2', function(err, collection) {
      collection.findOne({size:doc.size}, function(err, doc) {
        cb(doc);
      });
    });
  });
});

Подобные проблемы принято решать посредством использование Coffescript или модуля async оба способа делают код более читаемым и адекватным. Как промежуточнее решения я разделил вызовы на функции — такой вариант приводит код в более или менее вертикальный вид, но так же, при достаточно длинной цепочке вызовов создает проблему отслеживания ошибки в этой самой цепочке.

Дебаггинг

Крашлог в Node.JS в общих задачах не вызывает никаких претензий, но иногда выпадают эксепшены по которым, не ясно в чем ошибка, ясно только то что она есть.

events.js:71
        throw arguments[1]; // Unhandled 'error' event
                       ^
Error: socket hang up
    at createHangUpError (http.js:1264:15)
    at Socket.socketOnEnd [as onend] (http.js:1352:23)
    at TCP.onread (net.js:419:26)

По такому логу ясно что ошибка в вызове модуля http. А если в приложении больше одного вызова http? Какой из них вызвал ошибку не ясно. Приходиться смотреть уже логи на другой стороне.

Forever

Разработчики использующие Node.JS наверняка знакомы с модулем forever. Этот модуль позволяет запускать node процессы и отслеживать его краши. Но проблема состоит в том, что forever форкает себя для отслеживания каждого запущенного вами приложения. В итоге в топе мы видим N количество процессов ноды, и не ясно какой из процессов сколько ресурсов потребляет. Pid конечно можно получить из forever list, но это неудобно.

Отлов ошибок

Сам Node.JS и многие модули к нему придерживаются концепций CommonJS в частности то, что ошибки исполнения функций должна быть возвращена в колбэке первым аргументом. В связи с этим ошибка возможна после каждого вызова I/O, что может привести к эксепшену. Значит необходимо обрабатывать каждое исключение(за это кстати постоянно «пинают» Node.JS =) ). Так как мой проект находится на стадии «глубокой» беты такие проблемы я решаю «на живую» т.е. обработка ошибок реализовывается только тогда, когда она начинает возникать. Так как приложение имеет модульную структуру такое позволительно — пользователь не видит никаких ошибок.

Вот пожалуй и все. Стоит заметить, что хоть я и описал только отрицательные стороны Node.JS с которыми я столкнулся, но все же для меня положительных моментов гораздо больше) Всем спасибо за внимание)

P.S. Если кому интересно ссылка на проект.

Автор: baboon

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js