web3cket-соединение предотвращает выход из процесса узла - PullRequest
0 голосов
/ 31 мая 2018

У меня есть процесс узла js, который создает соединение web3cket web3, например:

web3 = new Web3('ws://localhost:7545')

Когда процесс завершается (я отправляю SIGTERM), он не завершается, а скорее зависает навсегда снет вывода на консоль.

Я зарегистрировал слушателя на SIGINT и SIGTERM, чтобы наблюдать за тем, с какими дескрипторами процесс имеет выдающиеся результаты с process._getActiveRequests() и process._getActiveHandles(), я вижу это:

 Socket {
    connecting: false,
    _hadError: false,
    _handle: 
     TCP {
       reading: true,
       owner: [Circular],
       onread: [Function: onread],
       onconnection: null,
       writeQueueSize: 0 },
    <snip>
    _peername: { address: '127.0.0.1', family: 'IPv4', port: 7545 },
    <snip>
}

ДляДля полноты, вот код, который прослушивает сигналы:

async function stop() {
  console.log('Shutting down...')

  if (process.env.DEBUG) console.log(process._getActiveHandles())

  process.exit(0)
}

process.on('SIGTERM', async () => {
  console.log('Received SIGTERM')
  await stop()
})

process.on('SIGINT', async () => {
  console.log('Received SIGINT')
  await stop()
})

Похоже, web3 держит сокет открытым, что имеет смысл, поскольку я никогда не говорил ему закрывать соединение.Просматривая документацию и прибегая к помощи, не похоже, что есть метод закрытия или завершения для объекта web3.

Ручное закрытие сокета в stop выше позволяет процессу успешно завершиться:

web3.currentProvider.connection.close()

У кого-нибудь есть более элегантное или официально санкционированное решение?Мне кажется смешным, что вы должны делать это вручную, а не уничтожать объект в конце процесса.Другие клиенты, кажется, делают это автоматически, без явного указания им закрыть свои соединения.Возможно, было бы лучше сказать всем клиентам, созданным процессом вашего узла, в любом случае закрыть свои дескрипторы / соединения при завершении работы, но для меня это было неожиданным.

Ответы [ 3 ]

0 голосов
/ 26 июня 2018

Мне кажется смешным, что вы должны делать это вручную, а не уничтожать сам объект в конце процесса

Это забавно, потому что вы, вероятно, подвергались более синхронному программированиюпо сравнению с асинхронным.Рассмотрим приведенный ниже код

fs = require('fs')
data = fs.readFileSync('file.txt', 'utf-8');
console.log("Read data", data)

Когда вы запустите выше, вы получите вывод

$ node sync.js
Read data Hello World

Это синхронный код.Теперь рассмотрим асинхронную версию того же

fs = require('fs')
data = fs.readFile('file.txt', 'utf-8', function(err, data) {
    console.log("Got data back from file", data)
});
console.log("Read data", data);

При запуске вы получите следующий вывод

$ node async.js
Read data undefined
Got data back from file Hello World

Теперь, если вы считаете себя синхронным программистом, программа должна была завершиться впоследний console.log("Read data", data);, но вы получите еще одно утверждение, напечатанное впоследствии.Теперь это смешно?Давайте добавим оператор выхода в процесс

fs = require('fs')
data = fs.readFile('file.txt', 'utf-8', function(err, data) {
    console.log("Got data back from file", data)
});
console.log("Read data", data);
process.exit(0)

Теперь, когда вы запускаете программу, она заканчивается на последнем утверждении.

$ node async.js
Read data undefined

Но файл фактически не читается.Зачем?потому что вы никогда не давали движку JavaScript время для выполнения ожидающих обратных вызовов.В идеале процесс автоматически завершается, когда для него не осталось работы (нет ожидающих обратных вызовов, вызовов функций и т. Д.).Так работает асинхронный мир.Есть несколько хороших SO тем и статей, которые вы должны посмотреть в

https://medium.freecodecamp.org/walking-inside-nodejs-event-loop-85caeca391a9

https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/

Как выйти в Node.js

Почему мой процесс Node.js не завершается после удаления всех слушателей?

Как процесс node.js узнает, когда остановиться?

Так что в асинхронном мире вам нужно либо сказать процессу завершиться, либо он автоматически завершится, когда нет ожидающих задач (которые вы знаете, как проверить - process._getActiveRequests() и process._getActiveHandles())

0 голосов
/ 19 мая 2019

API поставщика для модуля JavaScript web3 недавно претерпел некоторые существенные изменения в связи с реализацией EIP-1193 и готовящимся выпуском Web3 1.0.0 .

За код , похоже, web3.currentProvider.disconnect() должно работать.Этот метод также принимает необязательные аргументы code и reason, как описано в справочных документах MDN для WebSocket.close(...).

Важно: вы заметите, что я ссылалсяисходный код выше, а не документация.Это потому, что в настоящее время метод disconnect не считается частью общедоступного API.Если вы используете его в своем коде, вы должны обязательно добавить для него тестовый пример, так как он может сломаться в любое время! Из того, что я вижу, WebSocketProvider.disconnect был введен в web3@1.0.0-beta.38 и все еще присутствуетв последнем выпуске на сегодня, который web3@1.0.0-beta.55.Учитывая, что стабильная версия 1.0.0 должна скоро упасть, я не думаю, что это сильно изменится с настоящего момента до web3@1.0.0, но нет никаких препятствий, когда речь идет о структуре внутренних API.

Я обсуждал вопрос обнародования внутренних провайдеров с текущим сопровождающим, Сэмюэлем Фюртером, он же nividia на GitHub.Я не совсем согласен с его решением оставить его здесь внутренним, но в его защиту он является единственным сопровождающим в настоящее время, и у него есть руки на 1026 * очень полных для стабилизации давней работы в процессе 1.0 branch.

В результате этих обсуждений мое мнение на данный момент заключается в том, что те, кому нужен стабильный API для их провайдера WebSocket, должны написать собственного провайдера, совместимого с EIP-1193, и опубликовать его наNPM для использования другими.Пожалуйста, следуйте за semver для этого и включите аналогичный метод disconnect в ваш собственный публичный API.Бонусные баллы, если вы напишите это в TypeScript, поскольку это дает вам возможность явно объявить членов класса как public, protected или private.

Если вы сделаете это, помните, чтоEIP-1193 все еще находится в черновом состоянии, поэтому вам нужно следить за обсуждениями EIP-1193 по EthereumMagicians и по Discord Ring Discord , чтобы оставаться на вершине любогоизменения, которые могут произойти.

0 голосов
/ 20 июня 2018

В конце вашего узла js-процесса просто вызовите:

web3.currentProvider.connection.close()
...