Connection pool is never closed with node-oracledb and nodejs - node.js

I'm making a little API using Node Js and Oracle, using node-oracledb for that. I have been guided by the following article: API with OracleDB and Node JS
The project files contain the following:
/services/web-server.js
const http = require('http');
const morgan = require('morgan');
const express = require('express');
const webServerConfig = require('../config/web-server');
let httpServer;
function initialize(){
return new Promise((resolve, reject) => {
const app = express();
httpServer = http.createServer(app);
app.use(morgan('combined'));
app.get('/', (req, res) => {
res.end('Hello World');
});
httpServer.listen(webServerConfig.port, err => {
if(err){
reject(err);
return;
}
console.log(`Web server listening on localhost:${webServerConfig.port}`);
resolve();
});
});
}
module.exports.initialize = initialize;
function close(){
return new Promise((resolve, reject) => {
httpServer.close(err => {
if(err){
reject(err);
return;
}
resolve();
});
});
}
module.exports.close = close;
/services/database.js
const oracledb = require('oracledb');
const dbConfig = require('../config/database');
async function initialize(){
const pool = await oracledb.createPool(dbConfig.gtsmpPool);
}
module.exports.initialize = initialize;
async function close(){
await oracledb.getPool().close();
}
module.exports.close = close;
And /index.js
const webServer = require('./services/web-server');
const database = require('./services/database');
const dbConfig = require('./config/database');
const defaultThreadPoolSize = 4;
// Increase thread pool size by poolMax
process.env.UV_THREADPOOL_SIZE = dbConfig.gtsmpPool.poolMax + defaultThreadPoolSize;
async function startup(){
console.log('Starting application');
try{
console.log('Initializing database module');
await database.initialize();
}catch(err){
console.error(err);
process.exit(1); // Non-zero failure code
}
try{
console.log('Initializing web server module');
await webServer.initialize();
}catch(err){
console.error(err);
process.exit(1); // Non-zero failure code
}
}
startup();
async function shutdown(e){
let err = e;
console.log('Shutting down');
try{
console.log('Closing web server module');
await webServer.close();
}catch(e){
console.log('Encountered error', e);
err = err || e;
}
console.log('Exiting process');
try{
console.log('Closing database module');
await database.close();
}catch(err){
console.log('Encountered error', err);
err = err || e;
}
if(err){
process.exit(1); // Non-zero failure code
}else{
process.exit(0);
}
}
process.on('SIGTERM', () => {
console.log('Received SIGTERM');
shutdown();
});
process.on('SIGINT', () => {
console.log('Received SIGINT');
shutdown();
});
process.on('uncaughtException', err => {
console.log('Uncaught exception');
console.error(err);
shutdown(err);
});
/config/database.js
module.exports = {
gtsmpPool: {
user: process.env.GTSMP_USER,
password: process.env.GTSMP_PASSWORD,
connectString: process.env.GTSMP_CONNECTIONSTRING,
poolMin: 10,
poolMax: 10,
poolIncrement: 0
}
};
The connection to the database is succesful. The problem is that when I want to terminate the application and close the connection pool, the await statement oracledb.getPool().close() never gets resolved and seems to get stuck.
If I try to forcefully finish I get the following messages
Encountered error Error [ERR_SERVER_NOT_RUNNING]: Server is not running.
at Server.close (net.js:1604:12)
at Object.onceWrapper (events.js:416:28)
at Server.emit (events.js:310:20)
at emitCloseNT (net.js:1657:8)
at processTicksAndRejections (internal/process/task_queues.js:83:21) {
code: 'ERR_SERVER_NOT_RUNNING'
And
Encountered error Error: NJS-002: invalid pool
I'm using Oracle 18c XE on docker container, Node v12.16.3 and instantclient_18_5
Any idea how to fix it?
Thanks.

There are some notes in the node-oracledb pool example...
// Get the pool from the pool cache and close it when no
// connections are in use, or force it closed after 10 seconds.
// If this hangs, you may need DISABLE_OOB=ON in a sqlnet.ora file.
// This setting should not be needed if both Oracle Client and Oracle
// Database are 19c (or later).
await oracledb.getPool().close(10);

Related

Cannot conect to redis in Node

I'm trying to create a basic caching app just to test redis. Im using Redis Version: 4.0.6.
First I was getting error clientclosederror: the client is closed.
Then, after reading the docs, I added
let client;
(async ()=> {
client = redis.createClient()
await client.connect()
})();
But now, when trying on Postman, it just hangs, no response is returned
Full Code:
const express = require("express");
const redis = require("redis");
const axios = require('axios')
const app = express();
let client;
(async ()=> {
client = redis.createClient()
await client.connect()
})();
app.get('/result', async (req, res) => {
const searchTerm = req.query.name;
try {
await client.get(searchTerm, async (err, result) => {
console.log('cached called')
if (err) throw err;
if (result) {
res.status(200).send({
result: JSON.parse(result),
message: "data retrieved from the cache"
});
}
else {
const result = await axios.get(`https://api.agify.io/?name=${searchTerm}`);
await client.set(searchTerm, JSON.stringify(result.data));
return res.status(200).send({
result: result.data,
message: "cache miss"
});
}
})
} catch (error) {
console.log('get error', error)
return res.status(500).send({ message: error.message })
}
})
app.listen(process.env.PORT || 3000, () => {
console.log("Node server started");
});
client.get doesn't need a callback function. It's async. My guess is that it's never getting called and thus Express is not returning anything.
Try this instead:
const result = await client.get('foo')
if (result !== null) {
// it's a hit
} else {
// it's a miss
}

Redis giving error even after redis connected in nodejs

I have redis installed on my system and its running as well.
from node application, im using below code to work with redis.
redis.js
const redis = require("redis");
let client = redis.createClient(6379, '127.0.0.1', {});
let isRedis = false;
client.on("connect", function () {
console.log(`connected to redis`);
isRedis = true;
});
client.on("error", function (err) {
console.log("redis connection error " + err);
throw err;
});
client.on("end", function (err) {
console.log("redis connection end " + err);
});
module.exports = {
SetRedis,
GetKeys,
GetRedis,
GetKeyRedis,
delRedis
};
im using node index.js command to run the application which should also give me "connected to redis" when the connection is established, but i'm not getting this message on my console .
the npm package is also present in package.json
Node Redis 4.x doesn't allow you to pass in discrete arguments for the host and port. The canonical example of connecting to Redis with Node Redis is this:
import { createClient } from 'redis';
(async () => {
const client = createClient();
client.on('error', (err) => console.log('Redis Client Error', err));
await client.connect();
await client.set('key', 'value');
const value = await client.get('key');
})();
If you want to connect to somewhere other than localhost on port 6379, I recommend using a URL. Like this:
createClient({ url: 'redis://awesome.redis.server:6380' });
But if you want finer control, you can find all the gritty configuration options in the documentation on GitHub.
I guess you are making mistake while making connection.
It should have been
let client = redis.createClient('127.0.0.1', 6379, {});
rather than
let client = redis.createClient(6379, '127.0.0.1', {});
Working redis.js,
const redis = require("redis");
let isRedis = false;
(async () => {
let client = redis.createClient(6379, '127.0.0.1', {});// create config
client.on("connect", function () {
console.log(`connected to redis`);
isRedis = true;
});
client.on("error", function (err) {
console.log("redis connection error " + err);
throw err;
});
client.on("end", function (err) {
console.log("redis connection end " + err);
});
function GetKeyRedis(key) {
return new Promise(function (resolve, reject) {
console.log("dd----",key,isRedis);
if (isRedis) {
client.get(key).then((data,err) => {
if(err){
reject(err);
}
if(data){
resolve(data)
} else {
resolve(false);
}
});
} else {
resolve(false);
}
});
}
module.exports = {
GetKeyRedis
};
await client.connect();
})();

How to connect to Oracle DB from Node.js with `createPool()`

I tried to connect oracle database to my project. I used the createpool in order to call this function in the future for all the necessary requests from the database. my config.js file:
const oracledb = require('oracledb')
oracledb.outFormat = oracledb.OUT_FORMAT_OBJECT
const init = async function (query) {
try {
await oracledb.createPool({
user: 'almat',
password: 'almat789456123',
connectString: '(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=xepdb1)))'
})
console.log('Connection pool started')
await dostuff(query)
} catch (err) {
console.error('init() error: ' + err.message)
} finally {
// await closePoolAndExit()
}
}
async function dostuff (query) {
let connection
try {
connection = await oracledb.getConnection()
const sql = query
const binds = [1]
const options = { outFormat: oracledb.OUT_FORMAT_OBJECT }
const result = await connection.execute(sql, binds, options)
console.log(result)
} catch (err) {
console.error(err)
} finally {
if (connection) {
try {
await connection.close()
} catch (err) {
console.error(err)
}
}
}
}
async function closePoolAndExit () {
console.log('\nTerminating')
try {
await oracledb.getPool().close(10)
console.log('Pool closed')
process.exit(0)
} catch (err) {
console.error(err.message)
process.exit(1)
}
}
process
.once('SIGTERM', closePoolAndExit)
.once('SIGINT', closePoolAndExit)
module.exports.init = init
My app.js file:
const express = require('express');
const config = require('./utils/config');
const app = express();
app.listen(3000, function () {
console.log('Server running at port 3000')
})
app.set('view engine', 'ejs')
app.get('/', function (req, res) {
return res.render('index')
})
app.get('/login', function (req, res) {
return res.render('login')
})
app.get('/getCustomerName', function (req, res) {
const query = 'SELECT firstname FROM customer WHERE :b = 1'
const result = config.init(query)
//console.log(typeof result)
return res.send(result)
})
module.exports = app
When I request http://localhost:3000/getCustomerName it returns empty json file and terminal throws this error: NJS-047: poolAlias "default" not found in the connection pool cache
The createPool() call should be run once during app initialization, eg around the time you call express(). From the createPool() doc:
This method creates a pool of connections with the specified user name, password and connection string. A pool is typically created once during application initialization.
init() shouldn't call doStuff(). Once the pool is created, then your web listener handlers can call dostuff().
Look at the basic example webapp.js.
Also see the Oracle Magazine series Build REST APIs for Node.js which has source code here.

node-mssql "connection is closed" when running Mocha test, but runs fine in app

I have a node.js data processing app that pulls some data from mssql. It runs fine and produces the expected results. However, the integration tests aren't working and I would like them to.
Below is the connection management and a test query function. I can see from output and running in the debugger that the test has run and failed before the database has connected. So it seems like my Mocha async setup isn't working, but it looks like everything I've seen in documentation.
node -v
v10.15.0
chai: "^4.2.0",
mocha: "^5.2.0"
mssql: "^4.3.0",
const config = require('./config')
const _ = require('underscore')
const sql = require('mssql')
sql.on('error', err => {
console.error('SQL Error', err)
})
let api = {}
api.connect = async dbConfig => {
return new sql.ConnectionPool(dbConfig).connect(
err => {
if (err)
console.error('Connection error', err)
else
console.log('connected')
})
}
var connecting = api.connect(config.sql)
api.simple = async () => {
let pool = await connecting
let result = await pool.request().query('select 1 as number')
return result.recordset[0].number
}
module.exports = api
Here is my mocha test for it that fails
const { expect } = require('chai')
const data = require('../src/data')
describe('data access', function () {
it('is simple', async function () {
const yo = await data.simple()
expect(yo).to.exist
expect(yo).to.equal(1)
})
})
I've also tried the older style of async mocha tests using done callbacks ala
it('is simple oldschool', function (done) {
data.simple()
.then(function(yo){
expect(yo).to.exist
expect(yo).to.equal(1)
done()
})
})
That times out no matter how long I set Mocha's timeout for (I tried as high as 60 seconds)
I'm at my wits end here, anyone see anything wrong?
api.connect can return before the connection is actually done. Rewriting it like this will make sure ConnectionPool.connect can finish before the api.connect promise resolves.
api.connect = dbConfig =>
new Promise((resolve, reject) => {
const pool = new sql.ConnectionPool(dbConfig);
pool.connect(err => {
if (err) {
console.error("Connection error", err);
return reject(err);
}
return resolve(pool);
});
});
Beyond that, I'm confused about let pool = await c3; there's no symbol c3 in the code you've pasted...
I think you are having a race condition with the database connection.
I do this in the before()
before((done) => {
server.on("serverStarted", function() {
done();
});
});
Then in my server (I'm using node), I emit when when I am connected:
var port = process.env.PORT || 3030;
var server = http.listen(port, function(){
console.log('listening on port: ' + port);
db.connect().then(() => {
console.log("Connect to database successful");
server.emit("serverStarted") // HERE IT IS
}).catch(err => {
console.error(err);
console.log("Cannot connect to database");
process.exit(1);
});
});
Hope this helps. I've pulled out some hair on this one.

MongoDB unable to wait result

I cannot make MongoClient.connect to await for the results before going on.
I am trying to pass db from the server.js, where I connect my mongoclient, to my routes/api.js where I do my post requests. But it does not work, I always get:
TypeError: Cannot read property 'collection' of undefined
Here is my routes/api.js:
var db = require("../server");
router.post('/video_url', async (req, res) => {
const cursor = db.collection('movie').findOne({ link: req.body.videoURL }, function (findErr, result) {
if (findErr) throw findErr;
console.log(cursor)
});
server.js:
var db = async function () {
return await MongoClient.connect(MONGODB_URI, function(err, client) {
try {
if(err) throw err;
db = client.db('sub-project');
// Start the application after the database connection is ready
app.listen(PORT, () => console.log(`Server listening on port ${PORT}`));
return db;
}
catch(ex) {
console.log(ex)
}
});
}
module.exports = db;
EDIT:
var dbObject = (async function() {
var connection = await new Promise(function(resolve, reject) {
MongoClient.connect(MONGODB_URI, { useNewUrlParser: true }, function(err, client) {
try {
if (err) throw err;
db = client.db('sub-project');
// Start the application after the database connection is ready
app.listen(PORT, () => console.log(`Server listening on port ${PORT}`));
resolve(db);
} catch (ex) {
console.log(ex)
reject(ex);
}
});
});
return connection;
})();
console.log("TYPEOF DB IN", typeof(dbObject))
console.log("TYPEOF DB.COLLECTION IN", typeof(dbObject.collection))
The both console.log() are undefined... is that normal?
Use this code for your server.js. Your code was not working because your function was not getting called when you are requiring it.
var dbObject;
(function() {
MongoClient.connect(MONGODB_URI, { useNewUrlParser: true }, function(err, client) {
try {
if (err) throw err;
db = client.db('sub-project');
// Start the application after the database connection is ready
app.listen(PORT, () => console.log(`Server listening on port ${PORT}`));
dbObject = db;
} catch (ex) {
console.log(ex);
}
});
})();
setTimeout(function() {
console.log("TYPEOF DB IN", typeof(dbObject))
console.log("TYPEOF DB.COLLECTION IN", typeof(dbObject.collection))
}, 2000);
module.exports = dbObject;

Resources