Я написал собственный модуль Node, используя Rust + Neon Bindings. Общая цель — запросить базу данных, расшифровать результаты и вернуть массив JSON в Node. Для некоторых наборов данных это работает, как и ожидалось, однако для других это вызывает панику. Я пытаюсь его отладить, однако не могу понять, как получить трассировку стека. Единственный выход:

fatal runtime error: failed to initiate panic, error 5
    Abort trap: 6

Мои попытки отладки включают:

  • включая «обратную трассировку» в Cargo.toml
  • компиляция без "--release"
  • установка RUST_BACKTRACE=1 и DEBUG=true
  • создание файла test.js для печати вывода из модуля

Вывод сборки:

> neon build
neon info running cargo
  ... all the compilation steps.
  Finished dev [unoptimized + debuginfo] target(s) in 2m 17s
neon info generating native/index.node

Тестовый файл:

const Addon = require('./lib');
const addon = new Addon();
(async function() {
  console.log(`process.env.RUST_BACKTRACE = ${process.env.RUST_BACKTRACE}`);
  const i = await addon.getData(237);
  console.log(i, i.length)
}());

Тестовый результат:

> RUST_BACKTRACE=1 DEBUG=true node test.js 
process.env.RUST_BACKTRACE = 1
fatal runtime error: failed to initiate panic, error 5
Abort trap: 6

Для других значений, переданных addon.getData(), я возвращаю массив данных JSON, как и ожидалось. Набор данных, в котором произошел сбой, довольно велик, поэтому я не смог определить какие-либо различия.

> rustc --version
rustc 1.38.0 (625451e37 2019-09-23)
> cargo --version
cargo 1.38.0 (23ef9a4ef 2019-08-20)
> node --version
v11.15.0
> neon version
0.3.1

Я реализовал синхронную версию кода, а также асинхронную, используя в этом примере. Асинхронный обратный вызов преобразуется в обещание в ./lib/index.js. После обновления test.js для использования синхронной версии кода я получил следующий результат:

(node:45229) UnhandledPromiseRejectionWarning: Error: internal error in Neon module: called `Option::unwrap()` on a `None` value

Я добавил кучу println!() в свой код и смог найти ошибку (отсутствие обязательного свойства в расшифрованном объекте JSON), но так и не смог получить правильную трассировку стека. Похоже, Neon, должно быть, поглощает их в асинхронном коде.

2
doublesharp 28 Окт 2019 в 20:14
Набор данных, в котором произошел сбой, довольно велик — возможно, вам просто не хватает памяти? Используя некоторые инструменты мониторинга процессов, сколько оперативной памяти используется процессом?
 – 
Shepmaster
28 Окт 2019 в 20:54
- памяти не хватает, в вопросе была недостающая информация, которую я забыл. Ошибка поглощается асинхронным кодом из этот пример, если я запускаю его синхронно, я получаю ошибку JavaScript UnhandledPromiseRejectionWarning: Error: internal error in Neon module: called `Option::unwrap()` on a `None` value, которая помогает сузить его, но похоже, что Neon блокирует трассировку стека.
 – 
doublesharp
28 Окт 2019 в 21:38

1 ответ

Я столкнулся с той же проблемой, что и вы, и для себя я решил ее, правильно обработав результат с помощью предложения match и используя этот метод для обработки результатов ошибки, поэтому обратный вызов правильно сгенерирует ошибку NodeJS на моей стороне.

Часть моего фрагмента:

use std::sync::{Arc, Mutex};

use crate::utils::convert_uids_map;

use neon::prelude::*;

use dgraph_tonic::{DgraphError, Mutation, MutationResponse};
use dgraph_tonic::sync::{Mutate};

pub struct MutateTask<M> where M: Mutate {
  pub txn: Arc<Mutex<Option<M>>>,
  pub mu: Mutation,
}

impl<M> Task for MutateTask<M> where M: Mutate + 'static {
  type Output = MutationResponse;
  type Error = DgraphError;
  type JsEvent = JsValue;

  fn perform(&self) -> Result<Self::Output, Self::Error> {
    let mut mutex_guard = self.txn.lock().unwrap();
    let txn = mutex_guard.as_mut();
    match txn {
      Some(t) => t.mutate(self.mu.clone()),
      None => Err(DgraphError::EmptyTxn)
    }
  }

  fn complete(self, mut ctx: TaskContext, result: Result<Self::Output, Self::Error>) -> JsResult<Self::JsEvent> {
    match result {
      Ok(x) => Ok(convert_uids_map(&mut ctx, &x.uids).unwrap().upcast()),
      Err(e) => ctx.throw_error(format!("MutateTask Error - {:?}", e))
    }
  }
}

А затем я получил значимую ошибку, чтобы продолжить:

(node:50781) UnhandledPromiseRejectionWarning: Error: MutateTask Error - GrpcError(CannotDoRequest(Status { code: Unknown, message: "key error: subject:\"_:dg.1759080630.67\" predicate:\"@timestamp\" object_value:<str_val:\"2020-04-28T02:22:19.570Z\" > : predicate \"@timestamp\": Has invalid characters" }))
(node:50781) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:50781) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
1
lhr0909 13 Май 2020 в 06:06