i'm connecting to my neo4j running on a docker container and i'm getting an error when i try to attempt to make another connection/query. The error is "This socket has been ended by the other party". This is my Dockerfile with the opened ports:
EXPOSE 7474 7473 7687
This is my driver utility:
var neo4j = require("neo4j-driver").v1,
config = require("../../config");
(function(module){
module.exports = function(){
config.neo4j.server = 'localhost';
return neo4j.driver("bolt://" + config.neo4j.server, neo4j.auth.basic(config.neo4j.user, config.neo4j.password));
}
}(module));
The way i'm making my queries to neo4j:
(function(module){
var driver = require('../../../utils/neo4j-driver')(),
Q = require('q'),
logger = require('../../../utils/logger'),
BaseNeo4jModel = require('../../../utils/neo4j-model');
function userDBAuth(user){
var deferred = Q.defer();
var session = driver.session();
session
//.run( "MATCH (a:Person) RETURN a.name AS name, a.uuid as uuid" )
.run("MATCH (user:User {email:{email}})"
+ "RETURN user",
{ email: user.email})
.then(function (result) {
logger.debug('fetching results...');
if(result.records.length > 0){
var records = [];
result.records.forEach(function(record){
records.push(new BaseNeo4jModel(record));
});
done();
deferred.resolve(records);
} else {
deferred.reject({sucess: false, message: 'User not Found'});
}
}).catch( function(err) {
logger.error(err);
done();
deferred.reject(err.fields[0]);
});
return deferred.promise;
function done(){
session.close();
driver.close();
}
}
module.exports = userDBAuth;
}(module));
And this is my stack trace:
{"name":"auth-services","hostname":"MacBook-Pro-de-Vinicius.local","pid":16292,"level":50,"err":{"message":"This socket has been ended by the other party","name":"Error","stack":"Error: This socket has been ended by the other party
at TLSSocket.writeAfterFIN [as write] (net.js:286:12)
at NodeChannel.write (/Users/viniciussouza/Sites/WeddSocial/backend/weddsocial-auth/node_modules/neo4j-driver/lib/v1/internal/ch-node.js:285:20)
at Chunker.flush (/Users/viniciussouza/Sites/WeddSocial/backend/weddsocial-auth/node_modules/neo4j-driver/lib/v1/internal/chunking.js:114:18)
at Connection.sync (/Users/viniciussouza/Sites/WeddSocial/backend/weddsocial-auth/node_modules/neo4j-driver/lib/v1/internal/connector.js:487:21)
at Session.run (/Users/viniciussouza/Sites/WeddSocial/backend/weddsocial-auth/node_modules/neo4j-driver/lib/v1/session.js:89:20)
at userDBAuth (/Users/viniciussouza/Sites/WeddSocial/backend/weddsocial-auth/app/api/auth/services/userDBAuth.js:13:7)
at Object._auth [as auth] (/Users/viniciussouza/Sites/WeddSocial/backend/weddsocial-auth/app/api/auth/services/auth.js:9:3)
at Server.auth (/Users/viniciussouza/Sites/WeddSocial/backend/weddsocial-auth/app/api/auth/resources/auth.js:7:12)
at next (/Users/viniciussouza/Sites/WeddSocial/backend/weddsocial-auth/node_modules/restify/lib/server.js:906:30)
at f (/Users/viniciussouza/Sites/WeddSocial/backend/weddsocial-auth/node_modules/once/once.js:25:25)","code":"EPIPE"},"msg":"This socket has been ended by the other party","time":"2016-09-27T11:12:33.163Z","v":0}
I'm desperate, please help me!
Just a suggestion - but it looks like your success path doesn't always call the done() method and hence the session isn't always closed out and returned to the pool.
Might i suggest you amend the following:
if(result.records.length > 0){
var records = [];
result.records.forEach(function(record){
records.push(new BaseNeo4jModel(record));
});
done();
deferred.resolve(records);
} else {
deferred.reject({sucess: false, message: 'User not Found'});
}
To add a done() call in the else block:
if(result.records.length > 0){
var records = [];
result.records.forEach(function(record){
records.push(new BaseNeo4jModel(record));
});
done();
deferred.resolve(records);
} else {
done();
deferred.reject({sucess: false, message: 'User not Found'});
}
We were getting the same errors and traced it down to our code where we were sometimes committing our transaction before all the queries in the transaction were complete.
Having a look at your code, I'd suggest something like:
(function (module) {
var driver = require('../../../utils/neo4j-driver')(),
Q = require('q'),
logger = require('../../../utils/logger'),
BaseNeo4jModel = require('../../../utils/neo4j-model');
function userDBAuth(user) {
var session = driver.session();
return session
.run("MATCH (user:User {email:{email}}) RETURN user", {email: user.email})
.then(function (result) {
logger.debug('fetching results...');
if (result.records.length === 0) {
return Q.reject({success: false, message: 'User not Found'}); // will be caught by the .catch() below
}
var records = result.records.map(function(record) {
return new BaseNeo4jModel(record); // assume this is synchronous and doesn't return a promise
});
done();
return records;
})
.catch(function (err) {
logger.error(err);
done();
Q.reject(err.fields[0]); // return a rejected promise that can be caught by the caller of userDBAuth
});
function done() {
session.close();
driver.close();
}
}
module.exports = userDBAuth;
}(module));
Not certain that this will solve your problem as you're not doing exactly what we are, just a suggestion based on what we found.
Related
I'm using mysql connection pool to create connection. The code looks like the following.
var pool = mysql.createPool(connectionProps);
by accessing pool, I'll get the an Object, even if the connection is not Successful. I checked it with starting and stopping mysql.
What I want is that, I need to check connection is successful or not as follows.
if(pool){ // mysql is started && connected successfully.
console.log('Connection Success');
doSomething();
}else{
console.log('Cant connect to db, Check ur db connection');
}
I want something like this. So how can we do this with the mysql pool Object. Can someone please help me?
Thanks n Regards
Commonly you would do something like select something arbitrary from the db, and catch an error if that failed. Example from the docs.
const pool = mysql.createPool(connectionProps);
pool.query('SELECT 1 + 1 AS solution', (error, results, fields) => {
if (error) throw error;
console.log('The solution is: ', results[0].solution);
});
var pool = mysql.createPool(config.db);
exports.connection = {
query: function () {
var queryArgs = Array.prototype.slice.call(arguments),
events = [],
eventNameIndex = {};
pool.getConnection(function (err, conn) {
if (err) {
if (eventNameIndex.error) {
eventNameIndex.error();
}
}
if (conn) {
var q = conn.query.apply(conn, queryArgs);
q.on('end', function () {
conn.release();
});
events.forEach(function (args) {
q.on.apply(q, args);
});
}
});
return {
on: function (eventName, callback) {
events.push(Array.prototype.slice.call(arguments));
eventNameIndex[eventName] = callback;
return this;
}
};
}
};
And require to use it like:
db.connection.query("SELECT * FROM `table` WHERE `id` = ? ", row_id)
.on('result', function (row) {
setData(row);
})
.on('error', function (err) {
callback({error: true, err: err});
});
I my Node backend have the following end-point:
usersRoute.get('/get', function(req, res) {
//If no date was passed in - just use todays date
var date = req.query.date || dateFormat(new Date(), 'yyyy-mm-dd'),
search = req.query.search;
users.getAllUsers(date, search)
.then(function(results) {
res.json(results);
}, function(err) {
res.status(500).json({
success: false,
message: 'Server error.',
data: []
});
});
});
I have changed my sql table name to something else to trigger the function(err){} part
When I use this in my service it looks like this:
function getUsers(date, search) {
return $http.get('/api/users/get', {
params: {
date: UtilsService.formatDate(date),
search: search
}
})
.then(getData)
.catch(handleErr);
function getData(response) {
return response.data;
}
function handleErr(err) {
LoggerService.error('Could not retrieve users.', err ,'Ooops');
}
}
Knowing the server will return an http status code 500, I thought it would go right to the catch block. But it also returns the data /which is undefined in the then block
I use my service in my controller like this:
function getUsers(date, search) {
isAdmin();
vm.loading = true;
vm.filteredUsers = [];
return UsersService.getUsers(date, search).then(function(data) {
vm.loading = false;
allUsers = data || [];
vm.filteredUsers = allUsers.slice(0, 50);
vm.distribution = UsersService.getDistribution(allUsers);
return vm.filteredUsers;
});
}
My problem is, since the then part is triggered in my service. I'm trying to slice undefined
My question is: What are som best practices when it comes to this sort of pattern.
The problem is that your catching the error from your API and then returning the promise created by .catch.
Quick example
promise.then(function(data) {
throw 'Some error';
}).catch(function (err) {
console.log(err) // will output 'Some error'
}).then(function () {
// This will run even though we have a catch before
});
So how can we prevent the .then it's easy we throw an error inside the .catch
promise.then(function(data) {
throw 'Some error';
}).catch(function (err) {
console.log(err) // will output 'Some error'
throw 'You shall not pass'
}).then(function () {
// This will not run
});
So in your case you have two options, one throw an error as I said or two inject the $q service into your service:
function getUsers(date, search) {
return $http.get('/api/users/get', {
params: {
date: UtilsService.formatDate(date),
search: search
}
})
.then(getData)
.catch(handleErr);
function getData(response) {
return response.data;
}
function handleErr(err) {
LoggerService.error('Could not retrieve users.', err ,'Ooops');
return $q.reject(err);
}
}
You could do something like that
function getUsers(date, search, cb) {
return $http.get('/api/users/get', {
params: {
date: UtilsService.formatDate(date),
search: search
}
})
.then(cb)
.catch(handleErr);
function handleErr(err) {
LoggerService.error('Could not retrieve users.', err ,'Ooops');
}
}
And then in your controller
UsersService.getUsers(date, search, function(data) {
vm.loading = false;
allUsers = data || [];
vm.filteredUsers = allUsers.slice(0, 50);
vm.distribution = UsersService.getDistribution(allUsers);
});
I've turned my hand from game dev to writing a supporting back-end. Thus far everything seems to work out but when i got to writing a friend system i ran into this function flow which seemed very dirty to me. And i'm certain i'm just hacking it together at this point. Any node.js wizards about to tell me how I can improve this?
Fairly certain i should be caching player lookups in Redis as well.
acceptfriend: function(req, res){
//Find our user
User.findById( req.decoded._id, function(err, user){
//error occured
if(err){
return res.status(401).send(err);
}
//no user found
if(!user){
return res.status(401).json({
succes: false,
message: 'no user found with that id'
} );
}
//Does the request exist?
if( !_.any( user.social.friendRequests, {id: req.params.id} ) ){
return res.status(401).json( {
succes: false,
message: 'friend request not found'
} );
}
//find the user that belongs to the request
User.findById( req.params.id, function(err, friend){
//error occured
if(err){
return res.send(err);
}
//user doesnt exist
if(!friend){
return res.status(401).json({
succes: false,
message: 'no user found with that id'
} );
}
//Pull the request from the friendRequests array
user.social.friendRequests.pull( req.params.id );
//Add the friend
user.social.friends.addToSet( {
user_id: friend._id,
name: friend.username,
corp: 'n/a'
} );
//Add the user to the friends list as well
friend.social.friends.addToSet({
user_id: user._id,
name: user.username,
corp: 'n/a'
});
//save the docs
user.save();
friend.save();
} );
//return success
return res.status(200).json({
success: true,
message: 'friend succesfully added'
});
} );
}
1- First of all, you have a big function. You have to split it into some functions. Doing this you gain the possibility to test them with any testing framework.
2- Delegate the handle of error responses to the controller.
from -> return res.status(401).send(err);
to (with Promises)-> deferred.reject(err);
to (normal way) -> throw new Error(err);
3- You can use Promises to manage the asynchronous behaviour of node to clear the code.
I created an example, maybe is not working at first time, feel free to fix the incorrent references. The User ref, the 'acceptfriend' method...
Gist: https://gist.github.com/aitoraznar/b7099ad88ead0cdab256
var Promise = require('bluebird');
var _ = require('lodash');
//var User = app.models.User;
var ERRORS = {
userNotFoundError: {
code: 401,
success: false,
message: 'no user found with that id'
},
friendRequestNotFoundError: {
code: 401,
success: false,
message: 'friend request not found'
},
friendNotFoundError: {
code: 401,
success: false,
message: 'no friend found with that id'
}
}
var SUCCESS_MESSAGES= {
friendAddedSuccessfully: {
success: true,
message: 'friend succesfully added'
}
};
var userDAO = {
/*
*
*/
getUserById: function(id) {
var deferred = Promise.pending();
User.findById(id, function(err, user) {
//error occured
if (err) {
err.code = 401;
return deferred.reject(err);
}
//no user found
if (!user) {
return deferred.reject(ERRORS.userNotFoundError);
}
deferred.resolve(user);
});
return deferred.promise;
},
/*
* Does the request exist?
*/
checkFriendRequest: function(user, friendId) {
var deferred = Promise.pending();
if (userDAO.haveFriendRequestFrom(user, friendId)) {
deferred.resolve(user, friendId);
} else {
return deferred.reject(ERRORS.friendRequestNotFoundError);
}
return deferred.promise;
},
/*
*
*/
haveFriendRequestFrom: function(user, friendId) {
return _.any(user.social.friendRequests, {id: friendId });
},
/*
*
*/
getFriend: function(user, friendId) {
var deferred = Promise.pending();
userDAO.getUserById(friendId)
.then(function(friend) {
deferred.resolve(user, friend);
},
function(error) {
if (error === ERRORS.userNotFoundError) {
// Then the error is friend not found
// Override the error
error = ERRORS.friendNotFoundError;
}
return deferred.reject(error);
});
return deferred.promise;
},
/*
*
*/
makeFriendship: function(user, friend) {
var deferred = Promise.pending();
//Pull the request from the friendRequests array
user.social.friendRequests.pull(friend._id);
//Add the friend
user.social.friends.addToSet( {
user_id: friend._id,
name: friend.username,
corp: 'n/a'
} );
//Add the user to the friends list as well
friend.social.friends.addToSet({
user_id: user._id,
name: user.username,
corp: 'n/a'
});
//save the docs
user.save();
friend.save();
// Return the new friendship
var friendship = {
user: user,
friend:friend
};
deferred.resolve(friendship);
return deferred.promise;
},
/*
*
*/
friendRequestError: function(err) {
var deferred = Promise.pending();
// Propagate de error
deferred.reject(err);
return deferred.promise;
},
/*
*
*/
friendRequest: function(userId, friendId) {
var deferred = Promise.pending();
// Get user by ID
userDAO.getUserById(userId)
// Check if the user is able to add the friend
.then(userDAO.checkFriendRequest, userDAO.friendRequestError)
// Get the friend to add
.then(userDAO.getFriend, userDAO.friendRequestError)
// Make the friendship
.then(userDAO.makeFriendship, userDAO.friendRequestError)
// Response to the controller
.then(
function(friendship) {
// Resolve with new friendship
// This goes to 'success' function in controller
deferred.resolve(friendship);
}, function(error) {
// This goes to 'error' function in controller
deferred.reject(error);
})
return deferred.promise;
}
};
// Controller
var acceptfriend = function(req, res, next) {
var userId = req.decoded._id;
var friendId = req.params.id;
userDAO.friendRequest(userId, friendId)
.then(function(friendRequest) {
console.log('---> SUCCESS');
//return success
return res.status(200)
.json(SUCCESS_MESSAGES.friendAddedSuccessfully);
}, function(error) {
console.error('---> ERROR', error);
return res.status(error.code).json(error);
});
}
4- Create database indexes in the collection/table
Regards,
Aitor
I've been struggling with a simple test that involves mocking promises with no luck. I'm using jasmine spies. Hope somebody can help me. I've successfully mocked findByUserName method but there appears to be something wrong with the promise. The tests just fails without any error. Please see my code:
Module CertificationSettingsManager.FindUser being tested:
'use strict';
var CertificationSettingsManagerFindUser = function(usersRepository, accountsRepository, userName, next) {
if (userName) {
usersRepository.findByUserName(userName)
.then(function(user) {
if (user && user.password) {
delete user.password;
}
return user;
})
.then(function(user) {
if (user) {
accountsRepository.findAllAssignedTo(user.userId).then(function(results) {
user.hasAccountsAssigned = (results.count > 0);
user.belongsRepHierarchy = true;
user.isMemberOfReconOrPrep = true;
next(null, user);
});
}
})
.catch(function(err) {
if (err) {
next(err);
}
});
} else {
next();
}
};
module.exports = CertificationSettingsManagerFindUser;
And this is the test spec:
'use strict';
var findUserModule = require('./CertificationSettingsManager.FindUser');
var Q = require('q');
describe('CertificationSettingsManager findUser module', function() {
var userSpy;
var accounstSpy;
var nextCallbackSpy;
var inputUserTemplate;
var accountsResult;
beforeEach(function() {
inputUserTemplate = {
userId: 1234
};
accountsResult = {
count: 0
};
userSpy = jasmine.createSpyObj('UserRepository', ['findByUserName']);
accounstSpy = jasmine.createSpyObj('ProfileRepository', ['findAllAssignedTo']);
nextCallbackSpy = jasmine.createSpy('nextCallback spy');
});
it('when userName was not supplied it should call next with no parameters', function() {
findUserModule(null, null, null, nextCallbackSpy);
expect(nextCallbackSpy).toHaveBeenCalledWith();
});
//done callback passed so it can be asynchronous
it('if user has password, it should remove the password', function(done) {
inputUserTemplate.password = 'there is some password here';
accounstSpy.findAllAssignedTo.and.returnValue(Q.resolve(accountsResult));
userSpy.findByUserName.and.returnValue(Q.resolve(inputUserTemplate));
findUserModule(userSpy, accounstSpy, 'rassiel', function(){
expect(inputUserTemplate.password).toBeUndefined();
// done being called
done();
});
});
});
The second test: it('if user has password, it should remove the password' is failing, but when I try to debug the test it never hits the then inside:
usersRepository.findByUserName(userName)
.then(function(user) {
**UPDATED!!!****
After adding the done callback to the it method, the test is working now... that's what I was missing. Then done should be called after the expects statements.
Is there a better way of doing this?
I want to convert the following code to use promise. It is working and output a user's attributes within the active directory.
var client = ldap.createClient({
url: ldap_url
});
client.bind(ldap_username, ldap_password, function (err) {
client.search(ldap_dn_search, opts, function (err, search) {
search.on('searchEntry', function (entry) {
var user = entry.object;
// It is working!!!. It outputs all user attributes.
console.log(user);
});
});
});
The following is my attempt, butit doesn't output anything.
var Promise = require('promise');
var client_bind = Promise.denodeify(client.bind);
var client_search = Promise.denodeify(client.search);
client_bind(ldap_username, ldap_password)
.then(function(err){
client_search(ldap_dn_search, opts)
.then(function(search){
var search_on = Promise.denodeify(search.on);
search_on('searchEntry')
.then(function(entry){
var user = entry.object;
// It doesn't output anything !!!
console.log(user);
});
});
});
I had the same problem.
Search emits events, so we need something that processes them and passes further along the chain.
Here is piece of code, that works for me:
var ldap = require('ldapjs');
var promise = require('bluebird');
var client = ldap.createClient({url: app.settings['ldap']['server']});
var uid;
promise.promisifyAll(client);
function searchPromise(res, notfoundtext) {
return new Promise(function(resolve, reject) {
var found = false;
res.on('searchEntry', function(entry) {
found = true;
resolve(entry);
});
res.on('error', function(e) {
reject(e.message);
});
res.on('end', function() {
if (!found) {
reject(notfoundtext);
}
});
});
}
client.searchAsync(app.settings['ldap']['baseDn'], {filter: '(mail='+credentials.email+')', scope: 'sub'})
.then(function(res) {
return searchPromise(res, 'User isn\'t exists.');
})
.then(function (entry) {
uid = entry.object.uid;
return client.bindAsync(entry.object.dn, credentials.password);
})
.then(function() {
return client.searchAsync('cn='+app.settings['ldap']['group']+',cn=groups,'+app.settings['ldap']['baseDn'], {scope: 'sub', filter: '(memberUid='+uid+')'});
})
.then(function(res) {
return searchPromise(res, 'User is not in group ' + app.settings['ldap']['group']);
})
.then(function() {
console.log('All is ok');
})
.catch(function(message) {
console.log('Error:' + message);
});
Immediately after the search I add one more step that catches the events, processes them, and passes it further along the chain. This makes the function searchPromise.
Good luck coding )
Most likely those methods do require to be called on client as a context, so you will need to bind() them before passing them to Promise.denodeify:
var client_bind = Promise.denodeify(client.bind.bind(client));
var client_search = Promise.denodeify(client.search.bind(client));
Also, a proper use of promises would look like this:
client_bind(ldap_username, ldap_password).then(function() {
return client_search(ldap_dn_search, opts);
// ^^^^^^ always return something from the callback
}).then(function(search) { // flatten your chain
return Promise.denodeify(search.on).call(search, 'searchEntry');
// ^^^^^^ an alternative to `bind`
}).then(function(entry){
var user = entry.object;
console.log(user);
}).catch(function(err) { // always catch errors!
console.error(err);
});
Using Bluebird Promises, the easy way to do this is to create your client normally, and then run the promisifyAll() on the client.
var ldap = require('ldapjs');
var Promise = require('bluebird');
var client = ldap.createClient({
url: 'ldap://my-server:1234',
});
Promise.promisifyAll(client);
Now you can call client.addAsync() and client.searchAsync() and such.
client.bindAsync(secUserDn, secUserPassword)
.then(doSearch) // if it works, call doSearch
.catch(function (err) { // if bind fails, handle it
console.error('Error on bind', err)
});
function doSearch(data) {
client.searchAsync('CN=A Test,OU=Users,DC=website,DC=com', options)
.then(function (data) { // Handle the search result processing
console.log('I got a result');
})
.catch(function (err) { // Catch potential errors and handle them
console.error('Error on search', err);
});
}
i had the same issue here but i solved it by adding promise and resolve the response without using bluebird, this is an exemple of my code :
async getLdapUser(username: any): Promise<any> {
let myPromise = new Promise<boolean>((resolve, reject) => {
console.log('ssssssssss', username);
const adSuffix = 'OU=xxxx,OU=xxxxx,DC=xxxxxxx,DC=xxxxxx';
const password = 'xxxxxxxxxxxxx';
// Create client and bind to AD
const client = ldap.createClient({
url: 'ldap://1.1.1.1:389',
});
// promise.promisifyAll(client);
let resp = false;
// console.log(client);
client.bind('userTest', password,(err: any) => {
console.log('RESP', resp);
if (err) {
console.log('Error in new connetion ' + err);
} else {
/*if connection is success then go for any operation*/
console.log('Success');
const searchOptions: {} = {
scope: 'sub',
filter: '(sAMAccountName=' + username + ')',
attributes: ['sAMAccountName'],
};
client.search(adSuffix, searchOptions, (err: any, res: any) => {
assert.ifError(err);
res.on('searchEntry', (entry: any) => {
resp = true;
});
res.on('error', (error: any) => {
console.log('err');
reject(error.message);
});
await res.on('end', (result: any) => {
resolve(resp);
});
});
}
});
});
return myPromise;
}