Strange behavior

I have a Meteor method, uploadIcingaConf, wherein I use scp call from scp2 library in synchronous fashion via Meteor.wrapAsync.

I call this meteor method, uploadIcingaConf, from client side. Now the target file in scp call does not have write permission. So scp call fails. But the behavior I observe is that the scp call failure restarts the application and the function uploadIcingaConf gets called again and again in gap of about 1 minute. This keeps on repeating, application restarts and function uploadIcingaConf is called, even though no action is being done via client GUI. In-fact if I restart the application via systemctl, the function uploadIcingaConf is still called. Now this is very strange behavior in my opinion. The error being thrown by scp call is ‘throw new Error(‘handle is not a Buffer’);’.

So my question is why is function uploadIcingaConf, is getting called again and again even though application has restarted. Is this expected behavior or some bug in scp2 library.

The function uploadIcingaConf is

export const uploadIcingaConf = new ValidatedMethod({
  name: 'monitoring.uploadIcingaConf',
  validate: null,
  run() {
    if (Meteor.isServer) {
      this.unblock();
      /* eslint-disable global-require */
      const scpClient = require('scp2');
      /* eslint-enable global-require */
      const icingaConfiguration = getParameter('icinga_configuration');
      console.log('called ' + icingaConfiguration.configurationDirectory);
      const scpSync = Meteor.wrapAsync(scpClient.scp);
      scpSync('assets/app/hosts.conf', {
        host: icingaConfiguration.serverName,
        username: icingaConfiguration.managementUser,
        privateKey: fs.readFileSync(icingaConfiguration.sshPrivateKeyPath),
        path: icingaConfiguration.configurationDirectory
      });
    }
  }
});

Do you get an error on the server?

If your application crashes without returning a result to the client, the client will retry the method (it just sees that the server was disconnected/reconnected, so it tries again). If you don’t want this behaviour you can pass in the noRetry option to the call:

export const uploadIcingaConf = new ValidatedMethod({
  applyOptions: {
    noRetry: true,
  },
  ...

More info here https://guide.meteor.com/methods.html#retries

1 Like

Yes it seems that client was retrying. The browser window was open, so I guess the client was repeatedly retrying the server call. Thanks for the help.

One more question I have is, if I put scpSync, in above method, in try catch block, the flow does not go the catch block. Instead the server crashes with the following error message ‘throw new Error(‘handle is not a Buffer’);’ in the file sftp.js. Any idea why this error is not caught by try catch block.

It depends on how that package works, I’ve had similar trouble with the AWS SDK, where errors inside their package were logged up the chain (of on("error"), try/catch and then/catch) but still crashed the process. I might suggest using the async version, and wrapping it in a promise, just to make sure that isn’t the problem

1 Like

Ok, thanks for the reply. I will try to implement it as a promise and see.

I suspect the promise won’t help either as it seems that sftp.js is throwing the error outside the execution flow of the method. If it was part of the same stack, then the try/catch would handle it.

Ideally the issue with the call to scp2 should be fixed.
What version of scp2 are you using?
Looking at the code in github, the docs (and your code) don’t actually seem to match the implementation :scream:

While it’s possible to prevent the server from crashing by adding a global process.on('uncaughtException') callback, it’s strongly recommended that you don’t. See the warning in the node docs for more detail
https://nodejs.org/api/process.html#process_event_uncaughtexception

My experience of this type of error in AWS SDK is that even process.on didn’t catch it, it would log it - but still crash :’(

Sorry I did not check this post before. Iam using scp2 v0.5.0 which seems to be the latest version, albeit 3 years old :frowning: (https://www.npmjs.com/package/scp2).

Iam just trying to understand what you mean by the crash is not part of the same stack. Does it mean that crash is in some I/O function which is called outside the stack?

Thanks

Every truly async call happens in a new turn of the event loop with a fresh call stack. try/catch can only catch errors that happen deeper in the same call stack as the try/catch statement. (The exception to this being when using await inside an async function)
Which is why callback based async api’s pass an error as the first argument of every callback. It’s the only way to propagate errors back to the caller.

Your error is happening somewhere where it isn’t passed back. I did some research and it looks like it’s coming from the ssh2_streams package

Considering how outdated the scp2 package is, it might make sense to refactor to use the ssh2 sftp methods directly

1 Like

Got it. Thanks a lot for clarifying.