I'm trying to get a value in sequelize that I increment by 1 in a setInterval but when I try to do that on the ready event it returns the same value every time.
I tried doing it in a counter ( setInterval ) outside the listener (ready event) and it works fine.
client.once("ready", async () => {
console.log("Ready!");
Tags.sync();
client.channels.map((x) => {
if (x.type === "voice") {
x.members.map(async (y) => {
const user = await Tags.findOne({
where: { id: ID },
});
user.increment("rank");
setTimeout(() => {
console.log("start");
setInterval(async () => {
//Here the value is always the same
console.log("Test", user.get("level"));
user.increment("rank");
}, millisPerHour);
}, millisToTheHour);
});
}
});
});
How can I fix it? which could be a workaround for this "behaviour"?
Related
I have defined a promise like this ...
const result = await Promise.race([
new Promise(resolve => {
consumer.run({
eachMessage: ({ message }) => {
const data = JSON.parse(message.value.toString());
if (data.payload.template
&& data.payload.template.id === '...'
&& data.payload.to[0].email === email) {
console.log('Should resolve!')
resolve(data.payload.template.variables.link);
console.log('resolved');
consumer.pause();
consumer.disconnect();
}
},
});
}),
new Promise((_, reject) => setTimeout(reject, 3000))
]);
console.log('result is ', result);
return result;
I can get to resolved but it doesnt print the result at the end, it seems like neither did the timeout nor the actual promise work as expected? Why is that? I suspect its something to do with using resolve inside the kafka js callback?
UPDATE: Seems like its Promise.race() thats not resolving, but why?
My suspicion is that your "success-side" promise inadvertently throws and you're swallowing the error silently.
Using a mock-up minimal implementation of the consumer (that succeeds or fails 50/50), the following code works.
Run the code sample a couple of times to see both cases.
var consumer = {
interval: null,
counter: 0,
run: function (config) {
this.interval = setInterval(() => {
this.counter++;
console.log(`Consumer: message #${this.counter}`);
config.eachMessage({message: this.counter});
}, 250);
},
pause: function () {
console.log('Consumer: paused');
clearInterval(this.interval);
},
disconnect: function () {
console.log('Consumer: disconnected');
}
};
Promise.race([
new Promise(resolve => {
const expectedMsg = Math.random() < 0.5 ? 3 : 4;
consumer.run({
eachMessage: ({ message }) => {
if (message === expectedMsg) resolve("success");
}
});
}),
new Promise((_, reject) => setTimeout(() => {
reject('timeout');
consumer.pause();
consumer.disconnect();
}, 1000))
]).then((result) => {
console.log(`Result: ${result}`);
}).catch((err) => {
console.log(`ERROR: ${err}`);
});
I have also moved consumer.pause() and consumer.disconnect() to the "timeout-side" promise, this way the consumer is guaranteed to disconnect, albeit it might run a tiny bit longer than necessary in the success case.
hello guys im trying with online/offline system:
backend:
var userCount = 0;
var onlineuserList = [];
io.sockets.on('connection', function (socket) {
userCount++;
io.sockets.emit('userCount', { userCount: userCount });
socket.on('login', function (data) {
onlineuserList = onlineuserList.filter(user=> user !== data);
onlineuserList.push(data);
setInterval(function(){
io.sockets.emit('onlineuserList', onlineuserList);
}, 1000);
});
socket.on('logout', function (data) {
onlineuserList = onlineuserList.filter(user=> user !== data)
io.sockets.emit('onlineuserList', { onlineuserList: onlineuserList });
});
socket.on('disconnect', function() {
userCount--;
io.sockets.emit('userCount', { userCount: userCount });
});
});
frontend:
useEffect(() => {
socket.on('onlineuserList', (onlineuserList) => {
if(onlineuserList.length > 0){
onlinesetuserList(onlineuserList && onlineuserList);
setStatus(onlineuserList && onlineuserList.includes(props.id));
} else {
onlinesetuserList([]);
setStatus(false);
}
});
return () => socket.off('onlineuserList', onlineuserList);
}, []);
Everything working only, but in console log i getting this error:
Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
And one more question is it good and secure to set setinterval on every second in backend?
I think the problem is that you're not providing the original callback function to the socket.off method, so the socket listener doesn't get cleaned up as the component unmounts.
I would suggest the following fix:
useEffect(() => {
const onlineUserListHandler = (onlineuserList) => {
if(onlineuserList.length > 0){
onlinesetuserList(onlineuserList && onlineuserList);
setStatus(onlineuserList && onlineuserList.includes(props.id));
} else {
onlinesetuserList([]);
setStatus(false);
}
}
socket.on('onlineuserList', onlineUserListHandler);
return () => socket.off('onlineuserList', onlineUserListHandler);
}, []);
I have a system that checks a database to see if their UserToken is in the database, If it's not it will stop the bot and display an error message, I'm trying to make the bot repeat the same function every minute to see if my database has been updated. Here is the code I'm using:
setInterval(() => {
const getToken = dtoken => new Promise((resolve, reject) => {
MongoClient.connect(url, {
useUnifiedTopology: true,
}, function(err, db) {
if (err) {
reject(err);
} else {
let dbo = db.db("heroku_fkcv4mqk");
let query = {
dtoken: dtoken
};
dbo.collection("tokens").find(query).toArray(function(err, result) {
resolve(result);
});
}
})
})
bot.on("ready", async message => {
const result = await getToken(dtoken)
if (result.length == 1) {
return
} else {
console.error('Error:', 'Your token has been revoked.')
bot.destroy()
}
})
}, 5000);
But it doesn't work and I keep getting this error message:
(node:9808) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 ready listeners added to [Client]. Use emitter.setMaxListeners() to increase limit
if I could get some help with the timeout that would be amazing.
Bot object listens to the event ready on each execution in setInterval(). So after every 5 seconds, a new listener is being added on bot object which you have never removed. That's why it is throwing an error that the maximum limit has been reached.
I think you can take the listener out of the setInterval. It will work.
Updated Code:::
let isReady = false;
bot.on("ready", () => {
isReady = true;
});
const getToken = dtoken => new Promise((resolve, reject) => {
MongoClient.connect(url, {
useUnifiedTopology: true,
}, function(err, db) {
if (err) {
reject(err);
} else {
let dbo = db.db("heroku_fkcv4mqk");
let query = {
dtoken: dtoken
};
dbo.collection("tokens").find(query).toArray(function(err, result) {
resolve(result);
});
}
})
})
setInterval(() => {
if (isReady) {
const result = await getToken(dtoken)
if (result.length == 1) {
return
} else {
console.error('Error:', 'Your token has been revoked.')
isReady = false
bot.destroy()
}
}
}, 5000);
I have this snippet of code in my nodejs application.
The problem is that it doesn't wait before it renders the config page and passes the object thebalances.
app.get("/config", (req, res) => {
var thebalances = [];
client.rest.account.listAccounts().then(accounts => {
accounts.forEach(element => {
client.rest.product.getProductTicker(element.currency + '-USD').then(priceInfo => {
thebalances.push({
currency: element.currency
});
});
res.render("config", { balance: thebalances });
})
});
I have modified it to this now: but i think it errors out on some and like mentioned below it is all failing.
// GET /about
app.get("/config", (req, res) => {
let thebalances = [];
client.rest.account.listAccounts().then(async accounts => {
let promises = [];
accounts.forEach(element => {
promises.push(client.rest.product.getProductTicker(element.currency + '-USD'));
});
await Promise.all(promises).then(
results => {
results.forEach(priceInfo => {
thebalances.push({ currency: element.currency });
});
}
).catch(
error => {}
)
console.log(results);
res.render("config", { balances: thebalances });
})
});
I'm not sure how i can handle the multiple variable# of promises inside the foreach loop. I need to let that do its thing first before i can render the config page.
Any help would be greatly appreciated. I'm using coinbase api.
client.rest.account.listAccounts().then(async accounts => {
let promises = [];
accounts.forEach(element => {
promises.push(client.rest.product.getProductTicker(element.currency + '-USD'));
});
await Promise.all(promises).then(
results => {
results.forEach(priceInfo => {
thebalances.push({currency: element.currency});
});
}
).catch(
error => {
}
)
res.render("config", { balance: thebalances });
Please read up on this ... https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
There's some con with using Promise.all if one fail its fail.
edit: missing await
If it's really the case that one or more promise is failing, and it's really the case that this is okay from an app perspective, then...
// ...
let promises = accounts.map(element => {
return getProductTicker(element.currency);
});
// ...
function getProductTicker(currency) {
return client.rest.product.getProductTicker(currency + '-USD').catch(error => {
// debug here, if the error is a problem, otherwise
return null
})
}
Now promise all will contain proper resolutions of getProductTicker as well as nulls wherever that call failed. To clean it up...
await Promise.all(promises).then(results => {
let maybeWeShouldDebugHere = results.filter(r => !!!r)
})
I have a problem testing ldapjs client search operation. It returns an EventEmitter that you have to make listen for some specific event. I wrapped this operations to promisify it and to define my logic and I would like to unit-test it.
findUser(username) {
return new Promise((resolve, reject) => {
logger.debug('Searching user: ', username);
this.ldapClient.bind(user.name, .user.password, err => {
if (err) return reject(err);
else
this.ldapClient.search(root, {filter: `(cn=${username})`}, (errSearch, resSearch) => {
if (errSearch) return reject(errSearch);
const entries = [];
resSearch.on('searchEntry', entry => entries.push(entry.object));
resSearch.on('searchReference', referral => reject(new Error(`Received search referall: ${referral}`)));
resSearch.on('error', err => reject((err));
resSearch.on('end', result => {
if (result.status === 0 && entries.length === 1) {
return resolve({
cn: entries[0].cn,
objectclass: entries[0].objectclass,
password: entries[0].password
});
} else {
return reject(new Error(`Wrong search result: ${result}`));
}
});
});
});
});
}
I am using mockery and Sinon to replace ldapjs dependency inside my module:
beforeEach(function () {
searchEM = new EventEmitter();
sandbox = sinon.createSandbox();
ldapClientStub = Stubs.getLdapClientStub(sandbox);
ldapClientStub.bind.yields(null);
ldapClientStub.search.withArgs('o=ldap', {filter: `(cn=${findParam})`}).yields(null, searchEM);
mockery.registerMock('ldapjs', Stubs.getLdapStub(ldapClientStub));
mockery.registerAllowable('../src/client');
UserClientCls = require('../src/client').default;
userClient = new UserClientCls(config.get());
});
it('should return user with given username', function (done) {
setTimeout(() => {
searchEM.emit('searchEntry', users[1]);
searchEM.emit('end', {status: 0});
console.log('emitted');
}, 500);
searchEM.on('end', res => console.log(res));
userClient.findUser(findParam)
.then(user => {
user.cn.should.equal(users[1].attributes.cn);
user.objectclass.should.equal(users[1].attributes.objectclass);
user.password.should.equal(users[1].attributes.password);
return done();
})
.catch(err => done(err));
});
The problem is that listeners defined inside findUser are never called (but the function itself is called). The listener I defined in the test (just to debug the behaviour) is correctly called.
I do not understand if I miss something about how EventEmitters works or if I am doing the test in a wrong way. Or maybe I wrote a bad piece of code that cannot be tested.
I found a solution to my problem. I extended the base EventEmitter: I added the logic to store which event I want to emit and overrode its on method with a logic to emit my fake event.
class TestEventEmitter extends EventEmitter {
constructor() {
super();
}
setFakeEmit(fakeEmit) {
this.fakeEmit = fakeEmit;
}
on(eventName, cb) {
super.on(eventName, cb);
if (super.eventNames().length === 4)
this.fakeEmit.forEach(f => this.emit(f.name, f.obj));
}
}
So, in beforeEach I can stub ldapClientStub.search to make it return my TestEventEmitter:
beforeEach(function() {
searchEM = new TestEventEmitter();
searchEM.setFakeEmit([{
name: 'searchEntry',
obj: { object: users[1].attributes }
}, {
name: 'end',
obj: { status: 0 }
}]);
...
ldapClientStub.search.withArgs('o=ldap', { filter: `(&(cn=${findParam})(objectclass=astsUser))` }).yields(null, searchEM);
})
This solution may be not very elegant, but it works. If someone can post a better solution I'll be glad to have a look.