Why am I getting data from the database slowly? - node.js

I use nestjs with typeorm and postgresql, I get data from the database in 150-200ms, but if you wait 20 seconds and send a request to the backend again and get the data, then I get the data in 1000ms or 1500ms, although in theory and in general it should usually be 150- 200ms? Tried to use sequelize result was same. As if, if you wait, the server starts to fall asleep and wakes up for a long time when the request goes to it again.
This is code how I do request to database:
async getProducts() {
const products = await this.productRepository.find();
return products;
}
Please any ideas, answers, options

It is very unlikely that Nestjs is adding a significant delay here. The code you posted looks okay-ish.
Try removing the "surroundings" (as in moving parts) to get to the bottom of this. E.g. execute this method in the main.ts
Hint: if your service would be called MyService you could access it there like this:
const service = app.get(MyService);
Another way would be to remove everything that is involved in the response of the request:
Your code from controller -> service -> repository
Code that could intercept: Middlewares, Pipes, Guards, Interceptors
By switching Sequelize to TypeORM you kinda removed the DB communication layer as a suspect, if your investigation does not yield anything helpful you should consider looking into the underlying DB and the specified connection options (if any, e.g. pool size). Most likely the causing code should be in the application tho. For Sequelize and TypeScript, you can also enable logging to get better insights. Good luck on your research!

Related

AsyncLocalStorage not working for each request

I am using NestJS as a backend framework in NodeJS +16
I am trying to implement:
https://medium.com/#sascha.wolff/advanced-nestjs-how-to-have-access-to-the-current-user-in-every-service-without-request-scope-2586665741f
My idea is to have a #Injectable() service that will have, among other things, methods like:
hasUserSomeStuff(){
const user = UserStorage.get()
if(user) {
// do magic
}
and then pass this service around as it is usually done in NestJS
To avoid passing the request down the rabbit hole, or bubbling up the request scope so every dependency gets instantiated for each request, but also avoiding to use UserStorage everywhere where I need to get the user from the current request and do stuff
I've gone through the docs many times, it is my understanding that node would take care of instantiating a new storage for each async context (in my case each request), but what seems to happen to me is that when I first run my backend, it works just fine, I've got the user from the current request, but once the first async context / promise is completed, I retrieved data for the consumer, and in the next request UserStorage returns a undefined (as doc states it will if you are outside of the same async context, which I guess it is not what happens, as it should be a brand new async context)
However if I debug, what seems to happen is that this UserStorage is called and a new AsyncLocalStorage is instantiated at init, before the app is ready to be used, and then the very first request returns a undefined user.
I am failing to understand what is going on, can anyone help me on this, or any better approach to achieve my goal?
Thanks in advance

Handling uninitialized or erroneous Redis connection on AWS Lambda

My Scenario
I'm trying to utilize the global scope of Node.js to initialize a database connection once, and use the initialized connection when the lambda function is invoked.
This can save a lot of resources and time, as opening a DB connection is a lengthy process:
// Global scope: Runs only once
const redis = require('redis');
const client = redis.createClient({ <HOST>, <PORT> });
// Function scope: runs per invocation
exports.handler = (event, context, callback) => {
do-something-with-redis
};
My Problem
Some common connection errors may occur
Uninitialized connection: Since Node.js is asynchronous, the function may start executing code before redis.create returns, hence using an uninitialized connection.
Timeout: If the connection attempt times out for some reason, the function will have an erroneous handler.
Runtime error: If a connection error happens during code execution, following invocation will have an erroneous handler.
My Question
What's the proper way to overcome errors (initialization, timeout and runtime) of a global Redis connection used by an AWS Lambda function?
Lambda functions were designed to be stateless, so I don't know if there is one best answer to this. There's a really helpful GitHub comment about Lambda and RDS, but it mostly applies. It mentions that the answer depends on how many requests it'll be making.
Regardless, this SO answer is more or less how I would do it; though I prefer a Promise-based API for the Redis library. The author handles the Uninitialized Connection issue by using callbacks to wait until the connection is opened before trying to use the connection. The other two issues you raise are also handled in that SO answer. Basically: if (err) callback(err).
I mean, given the GitHub comment message is from support at AWS, you need to make a connection inside the handler, so you may as well only do it there until you're sure you need the perf boost.
I realize this doesn't exactly answer the question, but the question has been open for a few days now and I'm curious. And there's nothing like being wrong on the internet to find out the right answer...

Using node ddp-client to insert into a meteor collection from Node

I'm trying to stream some syslog data into Meteor collections via node.js. It's working fine, but the Meteor client polling cycle of ~10sec is too long of a cycle for my tastes - I'd like it be be ~1 second.
Client-side collection inserts via console are fast and all clients update instantly, as it's using DDP. But a direct MongoDB insert from the server side is subject to the polling cycle of the client(s).
So it appears that for now I'm relegated to using DDP to insert updates from my node daemon.
In the ddp-client package example, I'm able to see messages I've subscribed to, but I don't see how to actually send new messages into the Meteor collection via DDP and node.js, thereby updating all of the clients at once...
Any examples or guidance? I'd greatly appreciate it - as a newcomer to node and Meteor, I'm quickly hitting my limits.
Ok, I got it working after looking closely at some code and realizing I was totally over-thinking things. The protocol is actually pretty straight forward, RPC ish stuff.
I'm happy to report that it absolutely worked around the server-side insert delay (manual Mongo inserts were taking several seconds to poll/update the clients).
If you go through DDP, you get all the real-time(ish) goodness that you've come to know and love with Meteor :)
For posterity and to hopefully help drive some other folks to interesting use cases, here's the setup.
Use Case
I am spooling some custom syslog data into a node.js daemon. This daemon then parses and inserts the data into Mongo. The idea was to come up with a real-timey browser based reporting project for my first Meteor experiment.
All of it worked well, but because I was inserting into Mongo outside of Meteor proper, the clients had to poll every ~10 seconds. In another SO post #TimDog suggested I look at DDP for this, and his suggestion looks to have worked perfectly.
I've tested it on my system, and I can now instantly update all Meteor clients via a node.js async application.
Setup
The basic idea here is to use the DDP "call" method. It takes a list of parameters. On the Meteor server side, you export a Meteor method to consume these and do your MongoDB inserts. It's actually really simple:
Step 1: npm install ddp
Step 2: Go to your Meteor server code and do something like this, inside of Meteor.methods:
Meteor.methods({
'push': function(k,v) { // k,v will be passed in from the DDP client.
console.log("got a push request")
var d = {};
d[k] = parseInt(v);
Counts.insert(d, function(err,result){ // Now, simply use your Collection object to insert.
if(!err){
return result
}else{
return(err)
}
});
}
});
Now all we need to do is call this remote method from our node.js server, using the client library. Here's an example call, which is essentially a direct copy from the example.js calls, tweaked a bit to hook our new 'push' method that we've just exported:
ddpclient.call('push', ['hits', '1111'], function(err, result) {
console.log('called function, result: ' + result);
})
Running this code inserts via the Meteor server, which in turn instantly updates the clients that are connected to us :)
I'm sure my code above isn't perfect, so please chime in with suggestions. I'm pretty new to this whole ecosystem, so there's a lot of opportunity to learn here. But I do hope that this helps save some folks a bit of time. Now, back to focusing on making my templates shine with all this real-time data :)
According to this screencast its possible to simply call the meteor-methods declared by the collection. In your case the code would look like this:
ddpclient.call('/counts/insert', [{hits: 1111}], function(err, result) {
console.log('called function, result: ' + result);
})

Node.js API choking with concurrent connections

This is the first time I've used Node.js and Mongo, so please excuse any ignorance. I come from a PHP background. It was my understanding that Node.js scaled well because of the event-driven nature of it. As such, I built my API in node and have been testing it on a localhost. Today, I deployed it to my cloud server and everything works great, except...
As the requests start to pile up, they start to take a long time to fulfill. With just 2 clients connecting to the API, already I'm seeing 30sec+ page load times when both clients are trying to make several requests at once (which does sometimes happen).
Most of the work done by the API is either (a) reading/writing to MongoDB, which resides on a 2nd server on the cloud (b) making requests to other APIs, websites, etc. and returning the results. Both of these operations should not be blocking, but I can imagine the problem being something to do with a bottleneck either on the Mongo DB server (a) or to the external APIs (b).
Of course, I will have multiple application servers in the end, but I would expect each one to handle more than a couple concurrent clients without choking.
Some considerations:
1) I have some console.logs that I left in my node code, and I have a SSH client open to monitor the cloud server. I suspect that this could cause slowdown
2) I use express, mongoose, Q, request, and a handful of other modules
Thanks for taking the time to help a node newb ;)
Edit: added some pics of performance graphs after some responses below...
EDIT: here's a typical callback -- it is called by the express router, and it uses the Q module and OAuth to make a Post API call to Facebook:
post: function(req, links, images, callback)
{
// removed some code that calculates the target (string) and params (obj) variables
// the this.request function is a simple wrapper around the oauth.getProtectedResource function
Q.ncall(this.request, this, target, 'POST', params)
.then(function(res){
callback(null, res);
})
.fail(callback).end();
},
EDIT: some "upsert" code
upsert: function(query, callback)
{
var id = this.data._id,
upsertData = this.data.toObject(),
query = query || {'_id': id};
delete upsertData._id;
this.model.update(query, upsertData, {'upsert': true}, function(err, res, out){
if(err)
{
if(callback) callback(new Errors.Database({'message':'the data could not be upserted','error':err, 'search': query}));
return;
}
if(callback) callback(null);
});
},
Admittedly, my knowledge of Q/promises is weak. But, I think I have consistently implemented them in a way that does not block...
Your question has provided half of the relevant data: the technology stack. However, when debugging performance issues, you also need the other half of the data: performance metrics.
You're running some "cloud servers", but it's not clear what these servers are actually doing. Are they spiked on CPU? on Memory? on IO?
There are lots of potential issues. Are you running Express in production mode? Are you taking up too much IO on your MongoDB server? Are you legitimately downloading too much data? Did you get caught in an infinite Node.JS loop? (it happens)
I would like to provide better advice, but without knowing the status of the servers involved it's really impossible to start picking at any specific underlying technology. You may be a "Node newb", but basic server monitoring is pretty standard across programming languages.
Thank you for the extra details, I will re-iterate the most important part of my comments above: Where are these servers blocked?
CPU? (clearly not from your graph)
Memory? (doesn't seem likely here)
IO? (where are the IO graphs, what is your DB server doing?)

How does Meteor receive updates to the results of a MongoDB query?

I asked a question a few months ago, to which Meteor seems to have the answer.
Which, if any, of the NoSQL databases can provide stream of *changes* to a query result set?
How does Meteor receive updates to the results of a MongoDB query?
Thanks,
Chris.
You want query.observe() for this. Say you have a Posts collection with a tags field, and you want to get notified when a post with the important tag is added.
http://docs.meteor.com/#observe
// collection of posts that includes array of tags
var Posts = new Meteor.Collection('posts');
// DB cursor to find all posts with 'important' in the tags array.
var cursor = Posts.find({tags: 'important'});
// watch the cursor for changes
var handle = cursor.observe({
added: function (post) { ... }, // run when post is added
changed: function (post) { ... } // run when post is changed
removed: function (post) { ... } // run when post is removed
});
You can run this code on the client, if you want to do something in each browser when a post changes. Or you can run this on the server, if you want to say send an email to the team when an important post is added.
Note that added and removed refer to the query, not the document. If you have an existing post document and run
Posts.update(my_post_id, {$addToSet: {tags: 'important'}});
this will trigger the 'added' callback, since the post is getting added to the query result.
Currently, Meteor really works well with one instance/process. In such case all queries are going through this instance and it can broadcast it back to other clients. Additional, it polls MongoDB every 10s for changes to the database which were done by outside queries. They are plans for 1.0 to improve the scalability and hopefully allow multiple instances to inform each one about changes.
DerbyJS on the other hand is using Redis PubSub.
From the docs:
On the server, a collection with that name is created on a backend Mongo server. When you call methods on that collection on the server,
they translate directly into normal Mongo operations.
On the client, a Minimongo instance is created. Minimongo is essentially an in-memory, non-persistent implementation of Mongo in
pure JavaScript. It serves as a local cache that stores just the
subset of the database that this client is working with. Queries on
the client (find) are served directly out of this cache, without
talking to the server.
When you write to the database on the client (insert, update, remove),
the command is executed immediately on the client, and,
simultaneously, it's shipped up to the server and executed there too.
The livedata package is responsible for this.
That explains client to server
Server to client from what I can gather is the livedata and mongo-livedata packages.
https://github.com/meteor/meteor/tree/master/packages/mongo-livedata
https://github.com/meteor/meteor/tree/master/packages/livedata
Hope that helps.

Resources