Asp.net signalR onclose is getting called only once - javascript

I'm using asp.net signalr in my application. I'm doing manual reconnect. It's reconnecting first time when it's disconnected. I'm using onclose method to reconnect. But the onclose event is not getting called second time.
Below is my code.
const connection = new signalR.HubConnectionBuilder()
.withUrl("/connectHub")
.configureLogging(signalR.LogLevel.Information)
.build();
async function start() {
try {
await connection.start();
console.log("connected");
} catch (err) {
console.log(err);
setTimeout(() => start(), 5000);
}
};
connection.onclose(async () => {
await start();
});
The method "onclose" is calling when it's disconnected first time. When it disconnects second time it's not coming to "onclose" method, so reconnect also not happening.
Thanks

Related

fetch().then().catch(); doesn't catch `Uncaught (in promise) DOMException: The user aborted a request.`

I have an interface on an ESP32.
I am trying to have a Connected variable show up in an interface to signal the user if he is connected to said interface or not.
I am using the following method to constantly GET the configuration from the server in order update the interface.
// get json
async function get_json(api_path, options = {}) {
// const url = api_path;
// console.log(ROOT_URL);
// console.log(api_path);
const { timeout = 8000 } = options;
const controller = new AbortController();
const timeoutID = setTimeout(() => controller.abort(), timeout);
const response = await fetch(api_path, {
...options,
signal: controller.signal,
});
clearTimeout(timeoutID);
return response.json();
}
async function getSettings() {
get_json("/api/settings/get", {
timeout: 5000,
}).then((json_data) => {
// do something with the data
connected = true;
}).catch(function (error) {
// request timeout
console.log(error);
connected = false;
console.log(error.name === "AbortError");
});
}
Everything works dandy except the catch part.
Let's say the user changes the IP of the ESP. The ESP restarts and reconfigures to use the newly IP address. But the user stayed on the same page because connected is still set to true. In the console I get Uncaught (in promise) DOMException: The user aborted a request. for each request to getSettings() because I can't write a proper catch.
Basically, after the IP is changed, getSettings() tries to GET from a wrong address, so it's normal to throw some sort of error which I should catch and change the Connected variable to false and update it in the interface so that the user can go/move/navigate to the IP Address they have just inputted.
Edit:
This is how I update connected in the interface:
// check if connected to ESP
function connectedStatus() {
let conn = document.getElementById("connected");
conn.innerHTML = connected ? "Yes" : "No";
}
setInterval(connectedStatus, 500);
"Doesn't get_json() return a PROMISE?" - All async function does return promise, But your getSettings function doesn't wait for get_json to become resolved.
let delay = ms => new Promise(ok => setTimeout(ok, ms));
async function asyncFn() {
delay(2000).then(() => {
console.log("wait! 2 secs...")
});
console.log("thanks for waiting")
}
asyncFn()
As you can see "thanks for waiting" print first,
So our guess is that, getSettings indeed modify connected state but not immediately but later, But your getSettings resolve immediately, and you didn't wait for state (connected) change.
So you need to wait for any changes,
let delay = ms => new Promise(ok => setTimeout(ok, ms));
let state;
async function asyncFn() {
await delay(2000).then(() => {
state = true
console.log("wait! 2 secs...")
});
console.log("thanks for waiting")
}
asyncFn().then(() => {
console.log("state:", state)
})

Introducing delay between messages

I use Node.js. I have an MQTT message event handler
index.js
client.on('message', function (topic, message) {
// calls another function
my_function(topic,message);
})
which calls another function my_function on receiving messages.
async function my_function(topic,message) {
const value = await dataFromPLC();
///processes the value together with message
}
The function dataFromPLC exported from another file using exports.dataFromPLC = dataFromPLC and imported into my main function looks like this
PLCfunctions.js
let client = new S7Client(plcSettings);
client.on('error', console.error);
async function dataFromPLC (){
try {
await client.connect();
} catch (err){
console.error(err);
}
try {
// Read DB
const res = await client.readDB(dbNr, dbVars);
return res;
} catch (err) {
console.error(err);
} finally {
client.disconnect();
}
}
There is no issue when I receive a single MQTT message or there is sufficient delay between messages. However when I receive two MQTT messages, both of them calls my_function and subsequently dataFromPLC without much delay in between. I receive an error as there is not sufficient time for the PLC connection to close before the second message tries to use the connection again. I have looked at different options and am not quite sure about how to solve the problem. Can I get some help please?
You'll have to set up a queue of messages, so that onMessage only places the input in the queue and defers its processing until later on. For example, you could make the queue a Promise with then as enqueue operation. This way it's guaranteed that no processing starts until all previous ones are completed.
Here's a small demo, a click on the button simulates an incoming message:
let QUEUE = Promise.resolve()
function onMessage(msg) {
console.log('GOT MESSAGE', msg)
QUEUE = QUEUE.then(() => process(msg))
}
let pause = n => new Promise(r => setTimeout(r, n));
async function process(msg) {
console.log('BEGIN', msg)
await pause(200); console.log('busy', msg)
await pause(200); console.log('busy', msg)
await pause(200); console.log('busy', msg)
await pause(200); console.log('busy', msg)
await pause(200); console.log('busy', msg)
console.log('END', msg)
}
msg = 0
document.querySelector('button').addEventListener('click', () => onMessage(++msg))
<button>message</button>

Why closing websocket connection in Chrome by javascript is not immediately?

I tried to use rxjs webSocket to connect server. When I use .complete() function, the closingObserver is triggered immediately. But I received CloseEvent is almost 1 minute later.
So, how can I get the CloseEvent immediately?
Here is an example.
class SomeService {
private wsSource$ = webSocket({
url: "ws://xxxxxx.com/api/v1/xxx",
openObserver: this.openObserver,
closingObserver: this.closingObserver,
});
connect() {
this.wsSource$.subscribe({
next: (e) => console.log(e),
error: (err) => console.log(err),
complete: () => console.log("complete!!!")
});
}
disconnect() {
this.wsSource$.complete();
}
}
After connect(), Chrome will log the CloseEvent after almost 1 minute.
It is not logged by observer complete function, it is logged by error function.

Why does socket.io-client not connect inside of an RXJS subscription?

I am trying to initiate a socket.io connection upon receiving a certain event in an rxjs observable. The socket.io connection starts fine inside startEventStream if it's outside of the subscribe, but when placed in the subscribe, even though the event is firing, the callback inside socket is never called.
function startEventStream(
stateLoaded$: Observable<LoginEvent>
): Observable<AoEvent> {
const socket = require('socket.io-client')('http://localhost:8003')
const ret = new Subject<AoEvent>()
const merged = merge(stateLoaded$, ret)
const session = '895e17a0-6c2b-11ea-8d86-45f581e4b250'
const token =
'f3ccdd81c2ece391891cba4f7d4eb8466d3d44675dd70f11e21190ae13dfdf69'
merged.subscribe({
next(val) {
process.nextTick(() => {
if (val.type == 'state-loaded') {
console.log('we should be connecting') // this prints
socket.on('connect', function() {
console.log('connected') // this doesn't print
ret.next({ type: 'socket-connected' })
socket.emit('authentication', {
session,
token
})
})
}
})
}
})
return ret
}
I got it working by passing { autoconnect: false } into the initialization of the socket and doing socket.on() inside of the subscribe. I think the connect event was getting discarded before the subscription function was called, and so the callback was never firing. Starting the connection inside solves the problem.

Node.js "net.createConnection()" error callback not emitting

I want to connect to a Unix Domain Socket server in a Node application. If the connection succeeds and was opened, a loop (that may take some time) shall be executed. If an error occurs during the execution of this loop, it should receive some kind of notification. If a connection to the client is not possible at all, the loop should not be executed in the first place (that seems to work with the Promise). To me this sounds like the most simple thing in the world, but I just can't get it to work... This is what I have until now:
new Promise(function(resolve, reject) {
let connection = net.createConnection('/tmp/socket.s', () => {resolve(connection);})
.on('data', function(data) {
// Do something (during loop execution)
})
.on('error', reject); // If this callback is executed, the while loop should terminate (by receiving some kind of signal within the loop)
}).then(function(connection) {
for(...) {
// Do stuff that takes some time, executes other callbacks, sends data to the socket
}
connection.end();
}, function(error) {
// Error handling
});
What am I missing?
Try to listen to the data event in the resolve section of the promise. The following code should do it:
const net = require('net');
/**
* Client
* --------------------------------------------
*/
new Promise((resolve, reject) => {
let client = net.createConnection({ path: '/tmp/socket.s'}, () => {
console.log('Client: connected ')
resolve(client);
});
// Reject on error
client.on('error', err => reject(err) );
client.on('end', () => {
console.log('Client: disconnected from server #1');
});
}).then( connection => {
connection.on('data', data => {
// Do stuff with the data
console.log(`Client: the server says: ${data.toString()}\n`);
if(data != 'Data recieved'){
// Just to ensure that the following loop runs only once
for (let i = 0; i <= 10; i++) {
setTimeout(() => {
// Send data to the server
connection.write(`Client Data ${i}`);
if (i == 10) {
// Close the connection after everything is done
connection.end();
}
}, i*2000);
}
}
});
}, error => {
console.log('Client: promise rejection error', error );
});
My test server looks like this
const net = require('net');
/**
* Server
* --------------------------------------------
*/
const server = net.createServer( connectionListener => {
console.log(`#${process.pid} Server: client connected`);
connectionListener.on('end', () => {
console.log(`#${process.pid} Server: client disconnected`);
});
connectionListener.write('Hello\r\n');
connectionListener.on('data', data => {
console.log(`#${process.pid} Server: client sends: ${data.toString()}`);
connectionListener.write('Data recieved');
});
});
server.on('error', (err) => {
console.log(err);
server.close();
});
server.listen('/tmp/socket.s', () => {
console.log(`#${process.pid} Server: server bound`);
});
process.on('exit', code => {
console.log(code);
server.close();
});
process.on('SIGTERM', () => server.close() );
process.on('SIGINT', () => server.close() );
In this example the client sends data to server and the server replies each time. The client then closes the connection after having sent data 10 times.
P.S. There is no need to use a Promise unless you do need to return a promise at some point in your code.

Categories