New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Requests can only be made in the LoggedIn state, not the SentClientRequest state (code: 'EINVALIDSTATE') #458
Comments
There is a 'callback' property you can set on Request and there is a 'requestCompleted' event on Request, both seem work. And those are the two things we didn't try :) There may be some cleanup and documentation needed on this. Try these and see if it works. Using 'callback': request.callback = function (err, rowCount, rows) {
// rows is not being set but rowCount is. May be a bug.
if (err) {
// Error handling.
} else {
// Next SQL statement.
}
}; Using 'requestCompleted': request.on('requestCompleted', function () {
// Next SQL statement.
}); |
I'll actually put this notes in #61 and close this one as it's the same issue. |
Re-opening the issue. #61 is entirely unrelated. The issues referred to by @SaloniSonpal are actually closed. So reopening this for tracking. This needs some cleanup and documentation. |
Thanks @tvrprasad. Both these worked, and are way cleaner. |
(Sending from my phone, excuse the terseness).
Setting the callback property will overwrite the callback that you passed
to the Request constructor. Instead, you should call the callback from
async inside the callback passed to The Request constructor. This way you
can also forward errors correctly to async.
|
Ah, missed that callback is set to the callback passed in. So the right way would be: request = new Request(sqlQuery, function (err, rowCount, rows) {
if (err) {
// Error handling.
} else {
// Next SQL statement.
}
}); @arthurschreiber Any reason for the 'requestCompleted' event? Seems redundant. Another thing I notice is rows parameter passed in to the callback is always empty. Is there a scenario where it'll have valid data? I'll update documentation. |
There is the The main idea behind this is the following: If the I don't think this is optimal, having this configurable per-request instead of per-connection would probably be better - but the |
I'm not sure - this was added before I started working on tedious. |
Opened #459 to track the rowCollectionOnRequestCompletion issue. I'm sure we can add and handle that |
@arthurschreiber You're right. That is the right way to not override the results/ errors. Works like a charm :-) |
Created #464 to improve documentation on |
For people coming here from Google (like I did): tedious-connection-pool offers a great way of combatting this problem. Using |
Anyone please suggest, windows authentication mode is not working for nodejs2Sql connectivity. |
@wafaabbass |
Hey, everyone, I have the same problem. debug:
Is it resolved yet? This is my code.
If I call willIGetArea and willIGetSymptom, all this works but, if I call it with willGetModifier, I have the same problem as well. Thanks a lot. |
In case someone finds it helpful, since Google returns this page first for this error-message. class PromisedConnection {
constructor(config) {
// this.connection always points to a promise resolving after the last assigned request
// initial setting is either resolved once a new connection is established or rejected if an error occurs
this.connection = new Promise((resolve, reject) => {
const dbConnection = new Connection(config);
dbConnection.on("connect", function (err) {
if (err) {
reject(err);
}
else {
resolve(dbConnection);
}
});
});
}
execute(request) {
const nextConnection = new Promise((resolve, reject) => {
// after scheduling new request this.connection should be reassigned to be the last in promise queue
this.connection
.catch( (reason) => {
reject(reason);
} )
.then( (dbConnection) => { // a new request can be executed only within the connection is free again (resolved after the last request)
request.on("requestCompleted", () => { // add an additional event listener in order to release connection after the request is done
resolve(dbConnection);
});
dbConnection.execSql(request);
});
} );
this.connection = nextConnection;
}
} And the query itself can be executed as this: const dbConnection = new PromisedConnection(config);
function getObjList(query, parameters = []) {
return new Promise((resolve, reject) => {
const objList = [];
let request = new Request(
query,
function (err, rowCount, rows) {
if (err) {
reject(err);
} else if (rowCount < 1) {
reject(new Error("0 rows returned from DB"));
}
}
);
for (const {name, type, value} of parameters) {
request.addParameter(name, type, value);
};
request.on("row", (columns) => {
objList.push(Obj.fromColumns(columns)); // here I just make a specific object from each row
});
request.on("requestCompleted", () => {
resolve(objList);
});
dbConnection.execute(request);
});
} So getObjList now can be executed any time without checking the connection state. |
Concern here is well. In my code I do a connection request, a sql request, and then a insert request. It errors on insert request unless i do another connection request between sql and insert request even after i wait for the |
A common reason for this error is that only one query can be executed on a connection at a time. You need to wait until the request callback is executed, either with an error or with the result before making another request. Please visit the FAQ page here Since there seems to be too many various issues on this forum. The error
Thanks! 😄 |
Was able to resolve this, problem was on my side, didn't realize you need a separate connection for each request |
@mgarf What was your solution? I also didn't realize I need a separate connection for each request. I'm having concurrency issues like the others in this discussion. |
@mikebutak you don't necessarily need a separate connection for each request. You just need one connection handling one request at a time. To handle multiple request on one connection, you need to execute a new request in the callback of the previous one, after it's finished. For example, function executeStatement() {
request = new Request("select 42, 'hello world'", function(err, rowCount) {
if (err) {
console.log(err);
} else {
console.log(rowCount + ' rows');
}
connection.execSql(new Request("select 42, 'hello world'", function(err, rowCount) {
if (err) {
console.log(err);
} else {
console.log(rowCount + ' rows');
}
connection.close();
}))
});
connection.execSql(request); |
I am posting a full solution using callbacks for this issue. I had the same problem and when looking at google i ended up here. I load tested this code with a script executing 1 http call every second and also half a second with no issues. const {Connection, Request} = require("tedious");
const executeSQL = (sql, callback) => {
let connection = new Connection({
"authentication": {
"options": {
"userName": "USERNAME",
"password": "PASSWORD"
},
"type": "default"
},
"server": "SERVER",
"options": {
"validateBulkLoadParameters": false,
"rowCollectionOnRequestCompletion": true,
"database": "DATABASE",
"encrypt": true
}
});
connection.connect((err) => {
if (err)
return callback(err, null);
const request = new Request(sql, (err, rowCount, rows) => {
connection.close();
if (err)
return callback(err, null);
callback(null, {rowCount, rows});
});
connection.execSql(request);
});
};
executeSQL("SELECT * FROM users", (err, data) => {
if (err)
console.error(err);
console.log(data.rowCount);
});
//or
executeSQL("SELECT * FROM users", (err, {rowCount, rows}) => {
if (err)
console.error(err);
console.log(rowCount);
}); |
This solution works but is it a valid implementation? How feasible is that, considering there might be hundreds of thousands of inserts/selects and creating a connection for each of them? Thanks for the solution btw, I am just trying to understand if it is a viable solution. Especially if we are using an Azure Function? |
I tried your solution a few times and it seems to be working. Will check later on staging and production. Hopefully, it will work. |
This helped me to resolve |
In my example below, I'm trying to serially execute an array of functions. But the Requests can only be made in the LoggedIn state, so I had to check for that
connection.state !== connection.STATE.LOGGED_IN
. And as you can see in the Read function below had to put the request back in queue in order to get rid of the error.Is there a better way of achieving this? I see that a similar issues were brought up before #19 and #355. Is there a recommended way of executing multiple requests on a connection?
Code:
The text was updated successfully, but these errors were encountered: