Github node action http errors always fails job - github-actions

I have a github action that looks something like this:
const http = require('http');
const core = require('#actions/core');
const options = {
hostname: 'mydomain.com',
port: 80,
path: '/webhook',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
}
};
const postData = {
foo: 'bar'
}
try {
const strPostData = querystring.stringify(postData);
options.headers['Content-Length'] = Buffer.byteLength(strPostData);
const req = http.request(options)
req.write(strPostData)
req.end()
} catch (error) {
core.info(error.message);
}
if mydomain.com/webhook is offline, my job fails on this action, logging:
events.js:187
throw er; // Unhandled 'error' event
^
Error: connect ECONNREFUSED xxx.xxx.xxx.xxx:80
at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1129:14)
Emitted 'error' event on ClientRequest instance at:
at Socket.socketErrorListener (_http_client.js:406:9)
at Socket.emit (events.js:210:5)
at emitErrorNT (internal/streams/destroy.js:92:8)
at emitErrorAndCloseNT (internal/streams/destroy.js:60:3)
at processTicksAndRejections (internal/process/task_queues.js:80:21) ***
errno: 'ECONNREFUSED',
code: 'ECONNREFUSED',
syscall: 'connect',
address: 'xxx.xxx.xxx.xxx',
port: 80
***
Why does it fail, why doesn't the try catch catch this?
I don't want the entire job to fail if this action fails, so how do I trap this failure and hide it from the GitHub runner?

You will need to listen to the 'error' event to catch this
const strPostData = querystring.stringify(postData);
options.headers['Content-Length'] = Buffer.byteLength(strPostData);
const req = http.request(options)
req.on('error', (err) => {/*Error Caught*/})
req.write(strPostData)
req.end()

Related

Getting ConnectionRefusedError [SequelizeConnectionRefusedError]: connect ECONNREFUSED 127.0.0.1:3306 when running a React.js app

Im creating a web3 app that uses React.js and when I try to run the program with yarn/npm I get this error message:
ConnectionRefusedError [SequelizeConnectionRefusedError]: connect ECONNREFUSED 127.0.0.1:3306
at /Users/jendala/Documents/Current NFT/Website/React/copy/node_modules/sequelize/lib/dialects/mysql/connection-manager.js:123:19
at tryCatcher (/Users/jendala/Documents/Current NFT/Website/React/copy/node_modules/bluebird/js/release/util.js:16:23)
at Promise._settlePromiseFromHandler (/Users/jendala/Documents/Current NFT/Website/React/copy/node_modules/bluebird/js/release/promise.js:547:31)
at Promise._settlePromise (/Users/jendala/Documents/Current NFT/Website/React/copy/node_modules/bluebird/js/release/promise.js:604:18)
at Promise._settlePromise0 (/Users/jendala/Documents/Current NFT/Website/React/copy/node_modules/bluebird/js/release/promise.js:649:10)
at Promise._settlePromises (/Users/jendala/Documents/Current NFT/Website/React/copy/node_modules/bluebird/js/release/promise.js:725:18)
at _drainQueueStep (/Users/jendala/Documents/Current NFT/Website/React/copy/node_modules/bluebird/js/release/async.js:93:12)
at _drainQueue (/Users/jendala/Documents/Current NFT/Website/React/copy/node_modules/bluebird/js/release/async.js:86:9)
at Async._drainQueues (/Users/jendala/Documents/Current NFT/Website/React/copy/node_modules/bluebird/js/release/async.js:102:5)
at Immediate.Async.drainQueues [as _onImmediate] (/Users/jendala/Documents/Current NFT/Website/React/copy/node_modules/bluebird/js/release/async.js:15:14)
at processImmediate (internal/timers.js:462:21) {
parent: Error: connect ECONNREFUSED 127.0.0.1:3306
at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1146:16) {
errno: -61,
code: 'ECONNREFUSED',
syscall: 'connect',
address: '127.0.0.1',
port: 3306,
fatal: true
},
original: Error: connect ECONNREFUSED 127.0.0.1:3306
at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1146:16) {
errno: -61,
code: 'ECONNREFUSED',
syscall: 'connect',
address: '127.0.0.1',
port: 3306,
fatal: true
}
}
Here is the SQL connection file:
const AbstractConnectionManager = require('../abstract/connection-manager');
const SequelizeErrors = require('../../errors');
const Promise = require('../../promise');
const { logger } = require('../../utils/logger');
const DataTypes = require('../../data-types').mysql;
const momentTz = require('moment-timezone');
const debug = logger.debugContext('connection:mysql');
const parserStore = require('../parserStore')('mysql');
/**
* MySQL Connection Manager
*
* Get connections, validate and disconnect them.
* AbstractConnectionManager pooling use it to handle MySQL specific connections
* Use https://github.com/sidorares/node-mysql2 to connect with MySQL server
*
* #extends AbstractConnectionManager
* #returns Class<ConnectionManager>
* #private
*/
class ConnectionManager extends AbstractConnectionManager {
constructor(dialect, sequelize) {
sequelize.config.port = sequelize.config.port || 3306;
super(dialect, sequelize);
this.lib = this._loadDialectModule('mysql2');
this.refreshTypeParser(DataTypes);
}
_refreshTypeParser(dataType) {
parserStore.refresh(dataType);
}
_clearTypeParser() {
parserStore.clear();
}
static _typecast(field, next) {
if (parserStore.get(field.type)) {
return parserStore.get(field.type)(field, this.sequelize.options, next);
}
return next();
}
/**
* Connect with MySQL database based on config, Handle any errors in connection
* Set the pool handlers on connection.error
* Also set proper timezone once connection is connected.
*
* #param {Object} config
* #returns {Promise<Connection>}
* #private
*/
connect(config) {
const connectionConfig = Object.assign({
host: config.host,
port: config.port,
user: config.username,
flags: '-FOUND_ROWS',
password: config.password,
database: config.database,
timezone: this.sequelize.options.timezone,
typeCast: ConnectionManager._typecast.bind(this),
bigNumberStrings: false,
supportBigNumbers: true
}, config.dialectOptions);
return new Promise((resolve, reject) => {
const connection = this.lib.createConnection(connectionConfig);
const errorHandler = e => {
// clean up connect & error event if there is error
connection.removeListener('connect', connectHandler);
connection.removeListener('error', connectHandler);
reject(e);
};
const connectHandler = () => {
// clean up error event if connected
connection.removeListener('error', errorHandler);
resolve(connection);
};
// don't use connection.once for error event handling here
// mysql2 emit error two times in case handshake was failed
// first error is protocol_lost and second is timeout
// if we will use `once.error` node process will crash on 2nd error emit
connection.on('error', errorHandler);
connection.once('connect', connectHandler);
})
.tap(() => { debug('connection acquired'); })
.then(connection => {
connection.on('error', error => {
switch (error.code) {
case 'ESOCKET':
case 'ECONNRESET':
case 'EPIPE':
case 'PROTOCOL_CONNECTION_LOST':
this.pool.destroy(connection);
}
});
return new Promise((resolve, reject) => {
if (!this.sequelize.config.keepDefaultTimezone) {
// set timezone for this connection
// but named timezone are not directly supported in mysql, so get its offset first
let tzOffset = this.sequelize.options.timezone;
tzOffset = /\//.test(tzOffset) ? momentTz.tz(tzOffset).format('Z') : tzOffset;
return connection.query(`SET time_zone = '${tzOffset}'`, err => {
if (err) { reject(err); } else { resolve(connection); }
});
}
// return connection without executing SET time_zone query
resolve(connection);
});
})
.catch(err => {
switch (err.code) {
case 'ECONNREFUSED':
throw new SequelizeErrors.ConnectionRefusedError(err);
case 'ER_ACCESS_DENIED_ERROR':
throw new SequelizeErrors.AccessDeniedError(err);
case 'ENOTFOUND':
throw new SequelizeErrors.HostNotFoundError(err);
case 'EHOSTUNREACH':
throw new SequelizeErrors.HostNotReachableError(err);
case 'EINVAL':
throw new SequelizeErrors.InvalidConnectionError(err);
default:
throw new SequelizeErrors.ConnectionError(err);
}
});
}
disconnect(connection) {
// Don't disconnect connections with CLOSED state
if (connection._closing) {
debug('connection tried to disconnect but was already at CLOSED state');
return Promise.resolve();
}
return Promise.fromCallback(callback => connection.end(callback));
}
validate(connection) {
return connection
&& !connection._fatalError
&& !connection._protocolError
&& !connection._closing
&& !connection.stream.destroyed;
}
}
module.exports = ConnectionManager;
module.exports.ConnectionManager = ConnectionManager;
module.exports.default = ConnectionManager;```
I've been reading that it could be something to do with the SQL connection but am unsure if that is truly the case here.
Thanks in advance.

Facing issue with mysql database with node js

i have created express app with mysql database.
when i call mysql query it works fine and then i call my view. loading view take few minute(2-3 min) and app crashed with bellow error.
events.js:287
throw er; // Unhandled 'error' event
^
Error: read ECONNRESET
at TCP.onStreamRead (internal/stream_base_commons.js:205:27)
Emitted 'error' event on Connection instance at:
at Connection._handleProtocolError (C:\Users\AMW\Desktop\dishmize\dishmize\node_modules\mysql\lib\Connection.js:423:8)
at Protocol.emit (events.js:310:20)
at Protocol.EventEmitter.emit (domain.js:482:12)
at Protocol._delegateError (C:\Users\AMW\Desktop\dishmize\dishmize\node_modules\mysql\lib\protocol\Protocol.js:398:10)
at Protocol.handleNetworkError (C:\Users\AMW\Desktop\dishmize\dishmize\node_modules\mysql\lib\protocol\Protocol.js:371:10)
at Connection._handleNetworkError (C:\Users\AMW\Desktop\dishmize\dishmize\node_modules\mysql\lib\Connection.js:418:18)
at Socket.emit (events.js:310:20)
at Socket.EventEmitter.emit (domain.js:482:12)
at emitErrorNT (internal/streams/destroy.js:92:8)
at emitErrorAndCloseNT (internal/streams/destroy.js:60:3) {
errno: 'ECONNRESET',
code: 'ECONNRESET',
syscall: 'read',
fatal: true
}
[nodemon] app crashed - waiting for file changes before starting...
i already spend 8- 10 hours.
please help me to resolve this issue.
thanks
Update:
const options = {
user: config.get('MYSQL_USER'),
password: config.get('MYSQL_PASSWORD'),
database:config.get('DATABASE'),
host: config.get('HOST'),
port: 3306
}
const connection = mysql.createConnection(options);
connection.connect( function (err) {
if (err) {
console.log("!!! Cannot connect !!! Error:"); throw err;
} else {
console.log("Connection established.");
}
});
use below
const options = { connectionLimit :10, user:config.get('MYSQL_USER'), password: config.get('MYSQL_PASSWORD'), database:config.get('DATABASE'), host: config.get('HOST'), port: 3306 }
const connection_pool = mysql.createPool(options);
connection_pool.query('SELECT 1 + 1 AS solution', function (error, results, fields) {
if (error) throw error;
console.log('The solution is: ', results[0].solution);
});
provide connectionLimit according to you use this is pool size of connection

Error: Packets out of order. Got: 1 Expected: 0

All the Solutions I found for this Problem don't work for me.
I'm just loading one Dataset and after approximate 150 Request I get this Error:
Error: Packets out of order. Got: 1 Expected: 0
at Parser._tryReadPacketHeader (C:\dev\node\webkoll\node_modules\mysql\lib\protocol\Parser.js:470:15)
at Parser.write (C:\dev\node\webkoll\node_modules\mysql\lib\protocol\Parser.js:33:29)
at Protocol.write (C:\dev\node\webkoll\node_modules\mysql\lib\protocol\Protocol.js:38:16)
at Socket.<anonymous> (C:\dev\node\webkoll\node_modules\mysql\lib\Connection.js:88:28)
at Socket.<anonymous> (C:\dev\node\webkoll\node_modules\mysql\lib\Connection.js:526:10)
at Socket.emit (events.js:223:5)
at addChunk (_stream_readable.js:309:12)
at readableAddChunk (_stream_readable.js:290:11)
at Socket.Readable.push (_stream_readable.js:224:10)
at TCP.onStreamRead (internal/stream_base_commons.js:181:23)
--------------------
at Protocol._enqueue (C:\dev\node\webkoll\node_modules\mysql\lib\protocol\Protocol.js:144:48)
at Protocol.handshake (C:\dev\node\webkoll\node_modules\mysql\lib\protocol\Protocol.js:51:23)
at PoolConnection.connect (C:\dev\node\webkoll\node_modules\mysql\lib\Connection.js:116:18)
at Pool.getConnection (C:\dev\node\webkoll\node_modules\mysql\lib\Pool.js:48:16)
at C:\dev\node\webkoll\dbHelper.js:35:22
at new Promise (<anonymous>)
at dbHelper.execQueryWithParams (C:\dev\node\webkoll\dbHelper.js:34:16)
at dbHelper.loadFinishedResultFlag (C:\dev\node\webkoll\dbHelper.js:68:21)
at C:\dev\node\webkoll\index.js:321:30
at Layer.handle [as handle_request] (C:\dev\node\webkoll\node_modules\express\lib\router\layer.js:95:5) { code: PROTOCOL_PACKETS_OUT_OF_ORDER', fatal: true}
I'm using node v12.14.1 and the npm package mysql v2.18.1.
I also set the max_allowed_packet to 1G but it did not help.
Here the Code i use to get the data:
class dbHelper {
constructor() {
const { host, user, password, database, connectionLimit } = config.db;
this.con = mysql.createPool({
connectionLimit,
host,
user,
password,
database
});
}
async execQueryWithParams(query, params) {
return new Promise((resolve, reject) => {
this.con.getConnection((err, connect) => {
if (err) {
console.log(err);
return reject(err)
}
connect.query(query, [params], (err, result) => {
if (err) {
return reject(err);
}
resolve(result);
})
})
});
}
I found the Problem.
After using the npm package mysql2 I got the error message: "Too many connections".
I dumbly initialized my class way to often, so after using just one instance everything worked fine.
Try to increase the MAX_Packet_Allowed Memory - it works in my case
It can be - your pool connection is lost. Try checking wether it is still up.
You are doing some minor mistake for define variable and function definition on proper ways..
const mysql = require('mysql');
const con = mysql.createConnection({
host : process.env.RDS_HOSTNAME,
user : process.env.RDS_USERNAME,
password : process.env.RDS_PASSWORD,
port : process.env.RDS_PORT,
database : process.env.RDS_DATABASE
});
exports.handler = (event, context, callback) => {
// allows for using callbacks as finish/error-handlers
context.callbackWaitsForEmptyEventLoop = false;
const sql = "select * from user_status";
con.query(sql, function (err, result) {
if (err) throw err;
console.log(result);
callback(null, result)
});
};
I am using the above code and now I m getting data from my RDS.🙂🙂
Note: you need to define your mysql credentials for host,user,password,port,database.

Error when trying to make request to API using require request

Trying to make request to Google.com using code from npm require website:
var request = require('request');
request('http://www.google.com', function (error, response, body) {
console.log('error:', error); // Print the error if one occurred
console.log('statusCode:', response && response.statusCode); // Print the response status code if a response was received
console.log('body:', body); // Print the HTML for the Google homepage.
}); , but receiving this error:
error: { Error: getaddrinfo ENOTFOUND www.google.com www.google.com:80
at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:56:26)
errno: 'ENOTFOUND',
code: 'ENOTFOUND',
syscall: 'getaddrinfo',
hostname: 'www.google.com',
host: 'www.google.com',
port: 80 }
statusCode: undefined
body: undefined.
I've installed request. How can I fix this?

Lambda function "Error: connect ETIMEDOUT" when receive too many requests for MySQL query

I am trying to do testing on my AWS lambda function which makes a query to RDS MySQL (t2.medium).
However, if I request the API a large number of times, although I can get query successfully with correct data, it sometimes results "Error: connect ETIMEDOUT".
Is there anything wrong in my code or setting?
I read some suggestions to set some parameters:
MySQL:
wait_timeout 1
max_connections 16000
interactive_timeout 6000
max_allowed_packet 1073741824
Lamdba:
Timeout 60 sec place the Lambda function in the same VPC as your RDS
Added VPC execution policy AWSLambdaVPCAccessExecutionRole
assign a security group to the lambda function
In the security attached to the RDS instance, added an inbound rule
for mysql
Confirm that Lambda function has access to the same VPC RDS database
Lambda Error Log
2019-03-28T18:51:47.353Z ab4fbbaf-1ea2-458b-a5b5-781cdfdd80df { Error:
connect ETIMEDOUT
at Connection._handleConnectTimeout
(/var/task/node_modules/mysql/lib/Connection.js:411:13)
at Object.onceWrapper (events.js:313:30)
at emitNone (events.js:106:13)
at Socket.emit (events.js:208:7)
at Socket._onTimeout (net.js:420:8)
at ontimeout (timers.js:482:11)
at tryOnTimeout (timers.js:317:5)
at Timer.listOnTimeout (timers.js:277:5)
at Protocol._enqueue
(/var/task/node_modules/mysql/lib/protocol/Protocol.js:144:48)
at Protocol.handshake
(/var/task/node_modules/mysql/lib/protocol/Protocol.js:51:23)
at Connection.connect
(/var/task/node_modules/mysql/lib/Connection.js:118:18)
at Connection._implyConnect
(/var/task/node_modules/mysql/lib/Connection.js:453:10)
at Connection.query
(/var/task/node_modules/mysql/lib/Connection.js:198:8)
at Promise (/var/task/db.js:62:9)
at new Promise ()
at Object.retrieve (/var/task/db.js:55:10)
at exports.getAlerts (/var/task/index.js:59:24)
errorno: 'ETIMEDOUT',
code: 'ETIMEDOUT',
syscall: 'connect',
fatal: true }
RDS Error Log
2019-03-28T18:18:49.378320Z 9500 [Note] Aborted connection 9500 to db:
'db' user: 'user' host: '123.123.123.123' (Got timeout reading
communication packets)
2019-03-28T18:18:49.392514Z 9498 [Note] Aborted connection 9498 to db:
'db' user: 'user' host: '123.123.123.123' (Got timeout reading
communication packets)
2019-03-28T18:18:49.470617Z 9499 [Note] Aborted connection 9499 to db:
'db' user: 'user' host: '123.123.123.123' (Got timeout reading
communication packets)
2019-03-28T18:18:49.636775Z 9501 [Note] Aborted connection 9501 to db:
'db' user: 'user' host: '123.123.123.123' (Got timeout reading
communication packets)
2019-03-28T18:18:49.694669Z 9502 [Note] Aborted connection 9502 to db:
'db' user: 'user' host: '123.123.123.123' (Got timeout reading
communication packets)
2019-03-28T18:18:49.803457Z 9503 [Note] Aborted connection 9503 to db:
'db' user: 'user' host: '123.123.123.123' (Got timeout reading
communication packets)
2019-03-28T18:18:49.824250Z 9504 [Note] Aborted connection 9504 to db:
'db' user: 'user' host: '123.123.123.123' (Got timeout reading
communication packets)
My db.js query on lambda
const mysql = require('mysql')
let retrieve = (sql, objectArr, entityName) => {
return new Promise((resolve, reject) => {
let con = mysql.createConnection(dbParams)
con.query(sql, objectArr, (err2, results) => {
con.end()
if (err2) {
console.log(err2)
return reject(new apiError.DatabaseError('An error occurred in retrieve'))
}
console.log('Data retrieve successfully')
return resolve(results)
})
})
}
My test.js script
const request = require('request')
let errorCount = 0
let success = 0
for (let i = 0; i < 4000; i++) {
console.log('Send')
request.get('https://myapi/users', {
headers: {
'client_id': 'app',
'Content-Type': 'application/json'
}
}, (error, response, body) => {
if (error) {
console.log('some error')
errorCount++
} else {
let jsonBody = JSON.parse(body)
if (jsonBody.code === 0) {
success++
} else {
errorCount++
}
}
console.log('Success: ', success)
console.log('Error: ', errorCount)
})
}
Edit:
I also tried to change the i < 1 in test script, then it always gives me "Error: connect ETIMEDOUT. But with i < 900, it works successfully sometime
index.js
const db = require('./db.js')
exports.getUsers = async (event, context) => {
context.callbackWaitsForEmptyEventLoop = false
try {
let sql = 'SELECT * FROM User'
let abc = await db.retrieve(sql, [], 'user')
let response = {
statusCode: 200,
abc: abc,
code: 0
}
return response
} catch (err) {
console.log(err)
errorHandler(err)
}
}
db.js with Pool
const mysql = require('mysql')
const constants = require('./constants.js')
let dbParams = {
host: constants.SQL_CONNECTION_HOST,
user: constants.SQL_CONNECTION_USER,
password: constants.SQL_CONNECTION_PASSWORD,
database: constants.SQL_CONNECTION_DATABASE,
multipleStatements: true,
maxConnections: 4
}
const pool = mysql.createPool(dbParams)
let retrieve = (sql, objectArr, entityName) => {
return new Promise((resolve, reject) => {
pool.getConnection((err1, con) => {
if (err1) {
console.log(err1)
return reject(new apiError.DatabaseError('An error occurred in retrieve pool'))
}
console.log('Pool connect successfully')
con.query(sql, objectArr, (err2, results) => {
con.end()
if (err2) {
console.log(err2)
return reject(new apiError.DatabaseError('An error occurred in retrieve'))
}
console.log('Data retrieve successfully')
return resolve(results)
})
})
})
}
Error Log after used pool
2019-03-28T23:35:24.144Z 91b0fc78-e4d1-4fd9-bdf7-923715b165c0 { Error:
Handshake inactivity timeout
at Handshake.
(/var/task/node_modules/mysql/lib/protocol/Protocol.js:163:17)
at emitNone (events.js:106:13)
at Handshake.emit (events.js:208:7)
at Handshake._onTimeout
(/var/task/node_modules/mysql/lib/protocol/sequences/Sequence.js:124:8)
at Timer._onTimeout
(/var/task/node_modules/mysql/lib/protocol/Timer.js:32:23)
at ontimeout (timers.js:482:11)
at tryOnTimeout (timers.js:317:5)
at Timer.listOnTimeout (timers.js:277:5)
at Protocol._enqueue
(/var/task/node_modules/mysql/lib/protocol/Protocol.js:144:48)
at Protocol.handshake
(/var/task/node_modules/mysql/lib/protocol/Protocol.js:51:23)
at PoolConnection.connect
(/var/task/node_modules/mysql/lib/Connection.js:118:18)
at Pool.getConnection (/var/task/node_modules/mysql/lib/Pool.js:48:16)
at Promise (/var/task/db.js:72:10)
at new Promise ()
at Object.retrieve (/var/task/db.js:67:10)
at exports.getAlerts (/var/task/index.js:59:24)
code: 'PROTOCOL_SEQUENCE_TIMEOUT',
fatal: true,
timeout: 10000 }
Set with Pool now and test it with request loop:
i < 100 result => Success: 866 and Error: 134 requests.
i < 10 result => Success: 8 and Error: 2 requests.
Error with Handshake inactivity timeout
db.js with con.createConnection outside
const mysql = require('mysql')
// initialize dbParams
let con = mysql.createConnection(dbParams)
let retrieve = (sql, objectArr, entityName) => {
return new Promise((resolve, reject) => {
con.query(sql, objectArr, (err2, results) => {
//con.end() commet out connection end here
if (err2) {
console.log(err2)
return reject(new apiError.DatabaseError('An error occurred in retrieve'))
}
console.log('Data retrieve successfully')
return resolve(results)
})
})
}
It is not explained in the question how does the retrieve function is being called inside your lambda function.
Even though, it strongly seems that it will be executed for each iteration inside your test, which creates a very large number of connections and may explain the behavior you see.
I suggest creating the connection at lambda initialization time (aka 'coldstart'), by moving the code line let con = mysql.createConnection(dbParams) outside of any function (so that only a single connection will take place).
Another good option is to use connection pooling.