Reputation: 649
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.
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 ...
});
});
Upvotes: 0
Views: 273
Reputation: 649
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.
Upvotes: 1