'Convert async function consul.kv.get to sync function with deasync

I am trying to convert an async function consul.kv.get to a sync version of the same function. Searching led me to deasync and it's documentation suggests I should be able to do the following:

const fn = deasync(consul.kv.get);
expect(fn('foo')).to.eql('FOO');

Unfortunately when I do this I get the following error:

TypeError: Cannot read properties of undefined (reading '_defaults')
 at Kv.get (node_modules/consul/lib/kv.js:38:43)
 at /private/var/folders/_w/q9blb5897bz8510mt67v55180000gn/T/tmp.DDn1qWNr/node_modules/deasync/index.js:40:6
 at Context.<anonymous> (test/deasync-demo.spec.js:22:14)
 at processImmediate (node:internal/timers:464:21)

Since consul.kv.get has a version that can be called with a callback (found this via lsp hints) I thought I'd try invoke that in a small wrapper:

const fn = deasync((key, cb) => consul.kv.get(key, (err, data, res) => cb(err, data.Value)));
expect(fn('foo')).to.eql('FOO');

This worked! However ... it only works if I call the wrapped function once. If I invoke it again:

const fn = deasync((key, cb) => consul.kv.get(key, (err, data, res) => cb(err, data.Value)));
expect(fn('foo')).to.eql('FOO');
expect(fn('foo')).to.eql('FOO');

I get the following error:

Error: async hook stack has become corrupted (actual: 29, expected: 11)
 1: 0x10320ff4b node::AsyncHooks::pop_async_context(double) [/Users/nonyiah/.nodenv/versions/16.13.0/bin/node]
 2: 0x10321cb3c node::AsyncWrap::PopAsyncContext(v8::FunctionCallbackInfo<v8::Value> const&) [/Users/nonyiah/.nodenv/versions/16.13.0/bin/node]
 3: 0x1034c4dd9 v8::internal::FunctionCallbackArguments::Call(v8::internal::CallHandlerInfo) [/Users/nonyiah/.nodenv/versions/16.13.0/bin/node]
 4: 0x1034c48a6 v8::internal::MaybeHandle<v8::internal::Object> v8::internal::(anonymous namespace)::HandleApiCallHelper<false>(v8::internal::Isolate*, v8::internal::Handle<v8::internal::HeapObject>, v8::internal::Handle<v8::internal::HeapObject>, v8::internal::Handle<v8::internal::FunctionTemplateInfo>, v8::internal::Handle<v8::internal::Object>, v8::internal::BuiltinArguments) [/Users/nonyiah/.nodenv/versions/16.13.0/bin/node]
 5: 0x1034c401f v8::internal::Builtin_HandleApiCall(int, unsigned long*, v8::internal::Isolate*) [/Users/nonyiah/.nodenv/versions/16.13.0/bin/node]
 6: 0x103d34eb9 Builtins_CEntry_Return1_DontSaveFPRegs_ArgvOnStack_BuiltinExit [/Users/nonyiah/.nodenv/versions/16.13.0/bin/node]
 7: 0x107fb3560 
 8: 0x107fb51df 

Has anyone come across this before? Am I misunderstanding the docs or something else?

My goal is to call consul.kv.get, an async function from within a sync function and would appreciate any assistance that can be provided.

Note:

The above tests are wrapped in the following setup:

const { expect } = require('chai');
const { describe } = require('mocha');
const nock = require('nock');
const Consul = require('consul');
const deasync = require('deasync');

describe.only('deasync consul.kv.get', () => {
  it('should convert async to sync function', () => {
    const consul = new Consul();
    const scope = nock('http://127.0.0.1:8500')
      .get('/v1/kv/foo')
      .reply(200, [{ Value: Buffer.from('FOO').toString('base64') }]);

    // test here ...
  });
});


Solution 1:[1]

DON'T!

The correct answer to this question is to not do it. If you find yourself in this position you should probably have another look at your design.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 j1n3l0