I have a question I am using node-soap and pg-promise. I have a problem where when I make a request to the soap service the response is delayed, in other words I have to send the request twice (using soap ui) before the response comes back:
Im wondering if I am not passing the response from the database call correctly to node soap call back:
Here is the sample code from node-soap website:
var myService = {
MyService: {
MyPort: {
MyFunction: function(args) {
return {
name: args.name
};
},
// This is how to define an asynchronous function.
MyAsyncFunction: function(args, callback) {
// do some work
callback({
name: args.name
});
},
// This is how to receive incoming headers
HeadersAwareFunction: function(args, cb, headers) {
return {
name: headers.Token
};
},
// You can also inspect the original `req`
reallyDeatailedFunction: function(args, cb, headers, req) {
console.log('SOAP `reallyDeatailedFunction` request from + req.connection.remoteAddress);
return {
name: headers.Token
};
}
}
}
};
var xml = require('fs').readFileSync('myservice.wsdl', 'utf8'),
server = http.createServer(function(request,response) {
response.end("404: Not Found: " + request.url);
});
Here is my code:
var http = require('http');
var soap = require('soap');
global.results = '';
var promise = require('bluebird'); //
var options = {
promiseLib: promise // switch to bluebird lib
};
// Database connection details;
var cn = {
host: '',
port: 5432,
database: '',
user: '',
password: ''
};
var pgp = require('pg-promise')(options);
var db = pgp(cn);
var cancelService = {
cancelService: {
Cancel_PortType: {
getAgreement: function(args,callback,headers) {
var values = {
vin: args.vin
};
db.any("select contract_num as contract, " +
"CASE WHEN sg_con_status='A' THEN 'Active ' " +
"WHEN sg_con_status='X' THEN 'Expired' " +
"WHEN sg_con_status='C' THEN 'Cancelled' " +
"END AS agreementStatus, " +
"tfs_product_type as productType, " +
"vin, cust_first_name as customerFirstName, cust_last_name as customerLastName," +
"TO_CHAR(original_busdate,'YYYY-MM-DD') as purchaseDate, TO_CHAR(expire_date,'YYYY-MM-DD') as expirationDate " +
"from tfs_contract_summary, sg_con_m1 where sg_con_m1.sg_con_contract = tfs_contract_summary.contract_num " +
" AND vin = ${vin}",values)
.then(function(data) {
//set value of DB return to global
global.results = data;
console.log("DATAAAAAAA:", data);
})
.catch(function(error) {
console.log("ERROR:", error); // print the error;
})
.finally(function() {
pgp.end(); //closing the connection pool.
});
// }
callback({
contracts: global.results
});
}
}
}
}
var xml = require('fs').readFileSync('CancelService.wsdl', 'utf8'),
server = http.createServer(function(request, response) {
response.end("404: Not Found: " + request.url)
});
server.listen(8000);
soap.listen(server, '/wsdl', cancelService, xml);
All of my console.log() show the data coming back everytime I fire off a request in SOAPUI but the response does not come back until the 2 time I sent the request:
For example
Hit button once: vin = 12312364812736498
I expect John doe info to return - console.log(John doe's info) SOAP RESPONSE = empty
Hit Button twice console.log(John doe's info) SOAP RESPONSE = John doe's info
If I use the soap client sample code provided and issue a request:
console.log works everytime:
Do I have a scope issue where the global.results value has a race condition???
I'm pretty sure it's probably something wrong with my code as I am a newbie to Node JS etc...
Am I passing to the callback of the soap-server incorrectly??
callback({
contracts: global.results
});
Any insight would be greatly appreciated.
I think the problem is that you are calling the callback function before you set global.results
(even though it is at the bottom of your function).
All the code in your promise's .then
and .catch
blocks run asynchronously - meaning they are shuffled off to the event loop to be run later; AFTER the current code completes.
Here's the order of what happens in your code:
callback({contracts: global.results})
. At this point, global.results
is undefined..then
s and .catch
es as appropriate. Here's where you set global.results
(too late, of course)global.results
is already set to the result from the last query.Solution would be to forget about using global
and put the callback in a .then
of your promise:
db.any("my_awesome_sql")
.then(function(data) {
console.log("DATAAAAAAAA!!!", data);
callback({contracts: data});
})
.catch(function(error) {
// Handle error
})
.finally(function() {
// Cleanup
});