Socket.io - Wrong client socket event being called on server emit - node.js

I am creating a load test application for my socket.io application. Very strange results are happening when there is an DB error on the server side. Upon DB deadlock, the server emits the correct event, but on the client side the wrong event is being called.
Server code:
(I even got rid of all DB code and just output what the DB would output so
I know it's nothing to do with the DB)
function AddUser(gObj, cb) {
if (gObj.UKEY==2)
cb({err: 901, errm: "deadlock baby"});
else if (gObj.UKEY==3)
cb(null, [3,0,0,1,0]);
else
cb(null, [1,1,0,1,0]);
}
var io=require('socket.io')(8080);
var iowm = io.of('/mpp');
iowm.on('connection', function(socket) {
console.log('in MPP connection');
socket.on('nu', function(data) {
console.log('APP: in AddUser');
AddUser(data, function(err, result) {
console.log('RC: ',data);
if (err) {
console.log(err);
iowm.emit('error', {ERRM: err.errm});
console.log('ERROR: emitted');
} else {
console.log('done: ',result);
iowm.emit('done', result);
}
});
});
});
io.httpServer.on('listening', function() {
console.log('listening on port ',io.httpServer.address().port);
});
console.log('Done...');
Client code:
(I wrap the socket events in a wrapper function (which is probably where my error is) in order to pass the right parameters to the socket events in this tight loop)
for(var i=0; i<args[4]; i++) {
age = (Math.floor(Math.random()*args[3]) + 1) * 4;
console.log('ukey: '+args[2],' age: ',age);
socket = io.connect('http://localhost:8080/mpp');
if (socket) {
var OrigSocketOn = socket.on;
socket.on = function(event, data, cb2) {
return OrigSocketOn.call(socket, event, function(res) {
console.log('ESock: ', event,' data: ',data);
switch(data.ENT) {
case 2: // connect
cb2(data);
break;
case 3: // error
cb2({data: data, result: res});
break;
default:
cb2(res);
break;
}
});
};
socket.on('connect', {ENT: 2, GKEY: args[1], UKEY: args[2], AGE: age}, function(data) {
socket.emit('nu', {GKEY: data.GKEY, UKEY: data.UKEY, AGE: data.AGE});
});
socket.on('done', {ENT: 4, UKEY: args[2], AGE: age}, function(data) {
++cnt;
console.log('SOCKET: NewUser Done cnt: ',cnt);
console.log(data);
socket.close();
if (cnt == args[4] || data[4]>0)
cb();
});
socket.on('error', {ENT: 3, GKEY: args[1], UKEY: args[2], AGE: age}, function(data) {
console.log('SOCKET: NewUser Err');
console.log(data);
if (data.result.ERRM.indexOf('deadlock') > -1) { // deadlock - try again
socket.emit('nu', {GKEY: data.GKEY, UKEY: data.UKEY, AGE: data.AGE});
} else {
socket.close();
if (++cnt == args[4])
cb();
}
});
...
Server Output:
(All looks good. UKEY 1 and 3 come back fine and it emits the 'done' event. But UKEY==2 is the deadlocked entry so it emits the 'error' event.
in MPP connection
in MPP connection
in MPP connection
APP: in AddUser
RC: { GKEY: 1, UKEY: 3, AGE: 32 }
done: [ 3, 0, 0, 1, 0 ]
APP: in AddUser
RC: { GKEY: 1, UKEY: 1, AGE: 40 }
done: [ 1, 1, 0, 1, 0 ]
APP: in AddUser
RC: { GKEY: 1, UKEY: 2, AGE: 40 }
{ err: 901, errm: 'deadlock baby' }
ERROR: emitted
Client Output: (this is the problem)
ukey: 1 age: 40
ukey: 2 age: 40
ukey: 3 age: 32
ESock: connect data: { ENT: 2, GKEY: 1, UKEY: 1, AGE: 40 }
ESock: connect data: { ENT: 2, GKEY: 1, UKEY: 2, AGE: 40 }
ESock: connect data: { ENT: 2, GKEY: 1, UKEY: 3, AGE: 32 }
ESock: done data: { ENT: 4, UKEY: 1, AGE: 40 }
SOCKET: NewUser Done cnt: 1
[ 3, 0, 0, 1, 0 ]
ESock: done data: { ENT: 4, UKEY: 2, AGE: 40 }
SOCKET: NewUser Done cnt: 2
[ 3, 0, 0, 1, 0 ]
ESock: done data: { ENT: 4, UKEY: 1, AGE: 40 }
SOCKET: NewUser Done cnt: 3
[ 1, 1, 0, 1, 0 ]
So 3 problems:
1) the client 'done' event is seemingly called 3 times, when it should only be 2 times and the 'error' event should be called once.
2) the data of the 1st and 3rd 'done' events is the same (UKEY: 1), where it should be (UKEY: 1) and (UKEY: 3)
3) (UKEY: 3) output data is not there at all.

It looks to me like on your server, where you to iowm.emit(...), you should be doing socket.emit(...).
Your client is apparently making multiple connections to the server as there's an io.connect() inside of a for(var i=0; i<args[4]; i++) loop. So, when you do iowm.emit(...) on the server, it sends to ALL the connections the client has, not just the one that the error occurred on.
1) the client 'done' event is seemingly called 3 times, when it should only be 2 times and the 'error' event should be called once.
Because you're broadcasting the error to all client connections, not just to the one socket that the error occured on.

Related

Google Document AI - Inconsistent Long Running Operation's metadata JSON representation

While checking the status of Document AI - Long Running Operation (Form processor), the JSON representation of decodedOperation.metadata seems to vary during the execution.
I suspect that operation response does not resolve straight away despite using then() on checkBatchProcessDocumentsProgress(operation.name).
This behaviour does not happen using similar code for Google Speech's LROs.
Context:
At console.log line #24 of implemented code (below), as expected, decodedOperation.metadata resolves to
{
"state":"RUNNING",
"createTime":{
"seconds":"1669278029",
"nanos":500249000
},
"updateTime":{
"seconds":"1669278029",
"nanos":500249000
}
}
Current behaviour:
At console.log line #27, decodedOperation.metadata.state returns 2 (!?)
Expected behaviour:
decodedOperation.metadata.state should return RUNNING.
More details of output in the code below.
Reproduction details:
Environment:
node.js 12.02
Package.json:
{
"dependencies": {
"#google-cloud/documentai": "latest",
}
}
Code:
function run() {
const documentai = require('#google-cloud/documentai').v1;
// Create a promise on object
let options = {
credentials: {
client_email: ** ** ** ,
private_key: ** ** * ,
},
projectId: ** ** *
};
return async (async callback => {
const client = new documentai.DocumentProcessorServiceClient(options);
client.checkBatchProcessDocumentsProgress(properties.operation)
.then(
(decodedOperation) => {
console.log("METADATA " + JSON.stringify(decodedOperation.metadata));
/* logs to console:
{
"state":"RUNNING",
"createTime":{
"seconds":"1669278029",
"nanos":500249000
},
"updateTime":{
"seconds":"1669278029",
"nanos":500249000
}
}
/// then
{
"state":"SUCCEEDED",
"createTime":{
"seconds":"1669278029",
"nanos":500249000
},
"updateTime":{
"seconds":"1669278048",
"nanos":758825000
},
"individualProcessStatuses":[
{
"inputGcsSource":"gs://bucket/intake-form.pdf",
"status":{
},
"outputGcsDestination":"gs://bucket/ocr/7371120297544371692/0",
"humanReviewStatus":{
"state":"SKIPPED",
"stateMessage":"HumanReviewConfig is DISABLED, skipping human review."
}
}
]
}
*/
console.log("STATE " + JSON.stringify(decodedOperation.metadata.state));
/* log to console: 2
when above is "RUNNING" */
/* log to console: 3
when above is "SUCCEEDED" */
if (decodedOperation.metadata.state == "SUCCEEDED") { // Never triggers as decodedOperation.metadata.state evaluates to an integer at this line
};
let response = {
"operationStatus": decodedOperation.metadata.state
};
callback(undefined, response);
})
.catch(
(err) => {
callback(err);
});
})
}
Update on investigation
util.inspect(decodedOperation.metadata, { showHidden: false }) returns:
BatchProcessMetadata {
{
"individualProcessStatuses":[
"IndividualProcessStatus"{
"inputGcsSource":"gs://bucketxxx/intake-form.pdf",
"status":[
"Status"
],
"outputGcsDestination":"gs://bucketxxx/ocr/7999521463088838887/0",
"humanReviewStatus":[
"HumanReviewStatus"
]
}
],
"state":3,
"createTime":"Timestamp"{
"seconds":"Long"{
"low":1670011754,
"high":0,
"unsigned":false
},
"nanos":105214000
},
"updateTime":"Timestamp"{
"seconds":"Long"{
"low":1670011773,
"high":0,
"unsigned":false
},
"nanos":489028000
}
}
util.inspect(decodedOperation.metadata, { showHidden: true }) returns (section of interest only):
[...] [root]: [Getter], [fullName]: [Getter] }, State: { STATE_UNSPECIFIED: 0, WAITING: 1, RUNNING: 2, SUCCEEDED: 3, CANCELLING: 4, CANCELLED: 5, FAILED: 6, '0': 'STATE_UNSPECIFIED', '1': 'WAITING', '2': 'RUNNING', '3': 'SUCCEEDED', '4': 'CANCELLING', '5': 'CANCELLED', '6': 'FAILED' }, encode: <ref *5> [Function: BatchProcessMetadata$encode] [...]
To fix this issue, you can access the string representation of the state enum value by using the documentai.v1.BatchProcessMetadata.State object. For example:
console.log("STATE " + documentai.v1.BatchProcessMetadata.State[decodedOperation.metadata.state]);
instead of
console.log("STATE " + JSON.stringify(decodedOperation.metadata.state));
Read more about it.
https://cloud.google.com/php/docs/reference/cloud-document-ai/latest/V1.BatchProcessMetadata.State

Socket.io connection refused

I'm currently working on a simple game using WebSockets (first time!). However, my console is filled with net::ERR_CONNECTION_REFUSED errors, and I can't get anything to work.
I've been trying to fix the errors for hours and have seen a few other questions online with similar problems, but nothing has worked for me so far.
Here is my code:
server.js:
const { createGameState, gameLoop } = require("./game")
const { FRAME_RATE } = require("./constants")
const io = require("socket.io")(httpServer, {
cors: {
origin: "http://localhost:3000",
methods: ["GET", "POST"]
}
});
io.on("connection", client => {
const state = createGameState()
startGameInterval(client, state)
});
function startGameInterval(client, state) {
const intervalId = setInterval(() => {
const winner = gameLoop(state);
console.log("interval");
if(!winner) {
client.emit("gameOver");
clearInterval(intervalId);
} else {
client.emit("gameover");
clearInterval(intervalId);
}
}, 1000 / FRAME_RATE); // 1000
}
io.listen(3000);
index.js (top part):
const backgroundColor = "#1c1315";
const snakeColor = "#7d7778";
const foodColor = "#f55872";
const socket = io("http://localhost:3000")
socket.on("init", handleInit());
// socket.on("gamestate", handleGameState());
const gameScreen = document.getElementById("gameScreen");
let canvas, ctx;
const gameState = {
player: {
pos: {
x: 3,
y: 10,
},
vel: {
x: 1,
y: 0,
},
snake: [
{x: 1, y: 10},
{x: 2, y: 10},
{x: 3, y: 10},
]
},
food: {
x: 7,
y: 7,
},
gridsize: 20,
};
Here is the error that I'm getting; it gets printed in the console every 5 seconds or so.
polling-xhr.js:206 GET http://localhost:3000/socket.io/?EIO=4&transport=polling&t=NW6GI07 net::ERR_CONNECTION_REFUSED
I'm very new to socket.io/websockets in general, so I don't know what this error means or what I could do to fix the issue. Any help would be massively appreciated!

Not able to Display Data properly in node cli-table

I'm trying to display data that i received from an api on console using cli-table. The api call and everything works fine. I'm just having trouble displaying the output. Here's my code
const
url = require('./url'),
Table = require('cli-table2'),
fs = require('fs'),
inquirer = require('inquirer')
let table = new Table({
head: ['Name', 'Type', 'Language',
'Genres', 'Status', 'Premiered', 'OfficialSite', 'Schedule', 'Rating', 'Streamed On', 'Externals', 'Images', 'summary'
],
colWidths: [10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10]
});
const search = (item) => {
let shows = []
url.wordsearch(item)
.then(result => {
//console.log(result)
result.forEach(element => {
shows.push({ 'name': element.show['name'], 'value': element.show['id'] })
})
//console.log(shows)
inquirer.prompt([{
type: 'checkbox',
message: 'select tvshows you want see',
name: 'tvshow',
pageSize: 25,
choices: shows,
validate: (answer) => {
if (answer.length < 1) {
return "You must choose at least one card";
}
return true;
}
}]).then((answer) => {
//console.log(answer)
printresult(answer)
})
})
.catch(err => console.log(err))
}
const printresult = (answer) => {
answer.tvshow.forEach(show => {
url.idsearch(show)
.then(element => {
clean(element)
table.push([element['name'],
element['type'],
element['language'],
element['genres'],
element['status'],
element['premiered'],
element['officialSite'],
`Time :${element['schedule']['time']} \n Days: ${element['schedule']['days']}`,
element['rating'],
` name:${element['network']['name']}\n Country: ${element['network']['country']}`,
`tvrage:${element['externals']['tvrage']}\n thetvdb:${element['externals']['thetvdb']}\n imdb:${element['externals']['imdb']}`,
`medium:${element['image']['medium']}\n original:${element['image']['original']}`,
element['summary']
])
console.log(table.toString())
})
})
}
What am I doing wrong ? I want the output in a proper table format with no ... or anything. The printresult method does the work of printing to the console. I'm attaching a screenshot of my output.

aws Nodejs sdk:: autoscaling.describeAutoScalingGroups

I need to get the status of the autoscaling group processes (whether they're suspended or resumed). I've written the below script which returns the properties for the given ASG but the SuspendedProcesses: value is "[Object]". How do I expand the object. The ASG I'm querying has the Terminate process suspended, so I'd expect to see this in the output of the script:
var AWS = require('aws-sdk');
var uuid = require('uuid');
AWS.config.update({ region: 'eu-west-1' });
AWS.config.apiVersions = {
autoscaling: '2011-01-01',
};
var autoscaling = new AWS.AutoScaling();
var params = {
AutoScalingGroupNames: ["myAutoScalingGroup"]
};
function status() {
autoscaling.describeAutoScalingGroups(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
});
}
status();
This is the response from the above script:
C:\Node.js\NodeJsSamples\package01>node SuspendProcess.js
{ ResponseMetadata: { RequestId: 'myRequestId' },
AutoScalingGroups:
[ { AutoScalingGroupName: 'myAutoScalingGroupName',
AutoScalingGroupARN: 'arn:aws:autoscaling:eu-west-
1:myAccNumber:autoScalingGroup:myAutoScalingGroupName',
LaunchConfigurationName: 'myLaunchConfigurationName',
MinSize: 1,
MaxSize: 1,
DesiredCapacity: 1,
DefaultCooldown: 300,
AvailabilityZones: [Object],
LoadBalancerNames: [Object],
TargetGroupARNs: [],
HealthCheckType: 'ELB',
HealthCheckGracePeriod: 300,
Instances: [Object],
CreatedTime: 2017-11-02T08:08:31.364Z,
SuspendedProcesses: [Object],
VPCZoneIdentifier: 'subnet-########,subnet-########,subnet-########',
EnabledMetrics: [],
Tags: [Object],
TerminationPolicies: [Object],
NewInstancesProtectedFromScaleIn: false } ] }
How can I expand the [Object] values?
thanks.
Use this snipped. Is native.
console.log('string', require('util').inspect(<variable>, 1, 10, 1));
in your code:
function status() {
autoscaling.describeAutoScalingGroups(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log('output', require('util').inspect(data, 1, 10, 1)); // successful response
});
}
You need to JSON.stringify(data) instead of printing only data in else clause.
If you print console.log(JSON.stringify(data)) in else condition, you will get proper response.
Use JSON.stringify -
var obj = { "name":"John", "age":function () {return 30;}, "city":"New York"};
console.log(JSON.stringify(obj));

Conflict in _local

Occasionally I am getting something along the lines of:
http://myhosted.couchdb.com:5984/userdb-6938/_local/H73d9PBjwCczSUMy4NZ6bA%3D%3D
409 (Conflict)
The header response is: {"error":"conflict","reason":"Document update conflict."}
The request payload is:
{
"_id": "_local/f.kaEuoL4i41KgUTkCHAyg==",
"_rev": "0-10",
"session_id": "735AF8E9-BF62-191F-9A63-760C922E1259",
"history": [{
"last_seq": 77,
"session_id": "735AF8E9-BF62-191F-9A63-760C922E1259"
},
{
"last_seq": 67,
"session_id": "908B46C9-06C4-A60D-9189-CCE33ECEB252"
},
{
"last_seq": 59,
"session_id": "7B7A1737-D6AB-23F2-B3C3-954DFAC3F91A"
},
{
"last_seq": 52,
"session_id": "A7B639E5-CCEF-E1DE-91B2-8E27AB4AFB5B"
},
{
"last_seq": 45,
"session_id": "D8A322C2-5421-D493-91FB-DD85258D2194"
}],
"replicator": "pouchdb",
"version": 1,
"last_seq": 77
}
This is happening when performing some actions using pouchDb i.e This code will sometimes trigger it:
try {
await db.bulkDocs(toBeSaved)
} catch (err) {
errorCallback(err, importObj)
}
I understand local docs are docs that don't get replicated but do I need to worry about the error message that shows? The docs do explain about handling conflicts but this appears to be one I can't do anything about. Also, as this is a bulk operation, which document exactly is causing the conflict?
EDIT
My getLocalDb call (which sorts the connection to pouch / couch):
getLocalDb: function (onSyncCompleteDispatch) {
var localDb = new PouchDb(this.databaseName, {auto_compaction: true})
var liveDb = this.getLiveDb()
var self = this
// Only send a db object once it has sync'd with the remote host.
return new Promise(function (resolve, reject) {
resolve(localDb)
// We're not using continuous sync because the loading bars on the app will go wild
// We don't need to get data without users clicking anything at this point.
localDb.sync(liveDb, {
live: false,
retry: false
}).on('complete', function (info) {
var requiresReload = info.pull.docs_written > 0 || info.pull.docs_read > 0 || info.push.docs_written > 0 || info.push.docs_read > 0
if (requiresReload) {
typeof self.onSyncCompleteCallback === 'function' && self.onSyncCompleteCallback(info)
}
}).on('error', function (err) {
if (err.message === 'getCheckpoint rejected with ') {
// Don't need to resolve anything here as we resolved it above and nothing will have
// changed as no connection is available.
console.log('No live connection available, return local (without sync).')
} else {
typeof self.onSyncErrorCallback === 'function' && self.onSyncErrorCallback(err)
reject(err)
}
})
})
}

Resources