watson-developer-cloud / node-sdk

:comet: Node.js library to access IBM Watson services.
https://www.npmjs.com/package/ibm-watson
Apache License 2.0
1.48k stars 669 forks source link

[speech-to-text] Lack of 'error' listener on emit causes service using recognizeStream to crash #1201

Open acothran-becklar opened 9 months ago

acothran-becklar commented 9 months ago

Check service status Issue is related to STT and general IBM latency issues, causing intermittent failures.


Overview The client service is using node v18.16.0 and ibm-watson@8.0.0 RecognizeStream and SpeechToTextV1 classes to stream audio for Speech-To-Text services. When the class encounters an error and emits an 'error' to the server, the class does not have an 'error' listener, and crashes the client. The client always emits a stop() and end(), but, intermittently, the issue appears when the client does not receive expected confirmation events 'close' and 'end' and receives a Session timeout 'message' event 30 seconds later.

Expected behavior The RecognizeStream instance should be using the 'error' listener added on init to handle emitting errors

Actual behavior The 'error' message is emitted when a Session timeout 'message' event is received, but causes the client to crash as if missing an 'error' listener.

How to reproduce Client builds an object that holds an instance of RecognizeStream with additional listeners. Parameters include inactivityTimeout: -1 to intentionally stream silence. When finished, omit the stop() and end() methods to ensure the socket does not close and wait 30 seconds for the Session timeout 'message' event.

this.recognizeStream = this.speechToText.recognizeUsingWebSocket(params);

 // Listen for events.

 // Captures error events like "WebSocket connection error"
 this.recognizeStream.on('error', (event) => {
    this.recognizeStream.stop();
    this.recognizeStream.end();
 });

 this.recognizeStream.on('close', (event: unknown) => {
    // logs that the close event was received
 });

 this.recognizeStream.on('open', (event: unknown) => {
     ...
 });

 this.recognizeStream.on('end', (event: unknown) => {
    // logs that the end event was received
 });

Screenshots From logs:

Emitted 'error' event on RecognizeStream instance at:
    at emitError (...)
    at socket.onmessage (...)
    [... lines matching original stack trace ...]
    at process.processTicksAndRejections (node:internal/process/task_queues:77:11) {
  raw: _Event {
    type: 'message',
    isTrusted: false,
    _yaeti: true,
    data: '{\n   "error": "Session timed out."\n}',
    target: W3CWebSocket {
   ...

If I edit the javascript from the installed package and debug, I can resolve the crash by adding a listener before the emit: edited-recognize-stream This does not behave the same if I add the listener to the socket: image

SDK Version 8.0.0

Additional information:

Additional context Confused as to why the client emitting an error event also needs to listen for one, I used a separate node library to implement a standalone client and server connected by websocket. On either side, if the 'error' event is emitted without an 'error' listener, the emitting service crashes as if hitting an unhandled exception. I'm not extremely well-versed in websockets, but I've never encountered this behavior with previous, non-Node implementations.