Is there any way to stop polling server in SignalR? I want to stop polling server if error occurs. Polling hubs is started with $.connection.hub.start(), so I assumed that it could be stopped with $.connection.hub.stop() or something like that. But it doesn't seem to work, polling continues even after calling stop(). Is there another way to stop pollling?
<script type="text/javascript">
var chatHub = $.connection.chatHub;
var connection = $.connection.hub;
chatHub.addMessage = function (message) {
$('#messages').append('<li>' + message + '</li>');
};
connection.error(function (error) {
$('#messages').append('<li>' + "error connecting: closing connnection" + '</li>');
connection.stop(); //This doesn't seem to work
});
connection.start();
</script>
If you're using hubs you can stop the hub's connection:
$.connection.hub.stop();
Firstly are you sure that is it necessary? If communication error occurs than obviously you want to retry it.
However, I looked into the source code and I mean that especially in error handler it is not possible call .stop() command. Respectively it has no effect because after handler function is finished than the communication is automatically reinitialized two second after.
See jquery.signalR.js (line 340):
$(instance).trigger("onError", [data]);
window.setTimeout(function () {
poll(instance);
}, 2 * 1000);
I found one workaround: In handler function throw an exception, which cause that poll is not reinitialized:
connection.error(function (error) { //$.connection.hub.error()
$('#messages').append('<li>' + "error connecting: closing connnection" + '</li>');
throw "Close SignalR connection";
});
Related
I have a basic chat app set up like so:
$(function () {
// Set up references for other functions to call
chatConnection = $.connection.chatHub;
// Set up callbacks before starting server connection
chatConnection.client.addNewMessageToPage = function (name, message) {
var prettyMessage = name + ':' + message;
$('#chatHistory').append(prettyMessage);
$("#chatHistory").animate({ scrollTop: $('#chatHistory').prop("scrollHeight") }, 10);
};
// Start up connection to server, set up events
$.connection.hub.start().done(function () {
$('#sendChatButton').click(function () {
// Call the Send method on the hub.
chatConnection.server.sendMessage($('#displayName').val(), $('#chatBox').val());
// Clear text box and reset focus for next comment.
$('#chatBox').val('').focus();
});
});
});
This calls into my ChatHub.cs server side and I am getting and passing back messages as you would expect.
public void SendMessage(string name, string message)
{
Clients.All.addNewMessageToPage(name, message);
}
Now I want to add functionality. I Have a new class almost identical to my ChatHub called "GameHub" and it's job is to process moves instead of processing chat. So far I have something like this:
$(function () {
// Set up references for other functions to call
chatConnection = $.connection.chatHub;
gameConnection = $.connection.gameHub;
// Set up callbacks before starting server connection
chatConnection.client.addNewMessageToPage = function (name, message) {
var prettyMessage = name + ':' + message;
$('#chatHistory').append(prettyMessage);
$("#chatHistory").animate({ scrollTop: $('#chatHistory').prop("scrollHeight") }, 10);
};
gameConnection.client.receiveMove = function (name, move){
alert(name + ' played ' + move);
};
// Start up connection to server, set up events
$.connection.hub.start().done(function () {
$('#sendChatButton').click(function () {
// Call the Send method on the hub.
chatConnection.server.sendMessage($('#displayName').val(), $('#chatBox').val());
// Clear text box and reset focus for next comment.
$('#chatBox').val('').focus();
});
$('#sendMoveButton').click(function () {
gameConnection.server.sendMove(getMove());
});
});
});
but nothing is making it to the server. Is this because I don't have it set up correct? Can signalR even support 2 hubs or should it be a single hub and "spoke" out from there to my 2 different functional areas?
You can but given that there is no performance difference it's simpler to have those functions in one hub. All data will hit all hubs as they all share the same connection.
As documented here.
You can check, since it's not provided, your game hub and method to ensure you have them named and cased properly on the server side. Possible issues...
The problem
We are experiencing some weird problems with our signalR service. The signalR service sometimes works, and sometimes it doesn't. The service connects without issues, but when we try to invoke some of the methods i get the following error:
An unexpected error occurred invoking XXXX on the server.
We have tried enabling detailed logging, but the error message was the same. In the snippet below you can see the error we are getting, and you can furthermore see that the client keeps pinging the server without problems after the error.
SignalR ws image
What we have tried
We have 3 different environments set up with signalR. One of the environments is working but we are experiencing the above mentioned error in our 2 other environments. We tried checking the code on the working environment down on one of those that didn't work, and that didn't fix our signalR problem. What we tried so far:
Restarting the signalR service.
Renaming the hubs.
Cleaning and rebuilding the solution.
The signalR logs doesn't tell us much too. This is the message we are getting out of the logs on Azure:
"message":"Connection aborted. Reason: Connection ping timeout.","type":"ConnectivityLogs","collection":"Connection"
This is the method that fails:
public async Task AddToItemGroupTest(Guid itemId)
{
var securityLogger = await CreateSecurityLoggerForConnectionChanges(itemId);
await Groups.AddToGroupAsync(Context.ConnectionId, GetItemGroupIdentifier(itemId, _applicationSettings.EnvironmentShortName));
securityLogger.LogDataCreate($"connection to itemhub on item with id: {itemId}");
}
Client side:
NotificationService.getItemConnection().invoke("AddToItemGroup" + Constants.environmentShortName, itemId)
.then(() => {
this.addGroupToActiveGroups("item", "AddToItemGroup" + Constants.environmentShortName, itemId);
connectionChangedCallback(connectionStatus.connected);
callback();
})
.catch((error) => {
connectionChangedCallback(connectionStatus.disconnected);
console.log(`Failed adding client to group. Error: ${error}`);
throw Error(`Failed adding client to group. Error: ${error}`);
});
getItemConnection looks like this:
private static getItemConnection() {
if (!this.itemConnection) {
this.itemConnection = new SignalR.HubConnectionBuilder()
.withUrl(Constants.itemHubUrl, {
accessTokenFactory: () => {
return getUserAccesTokenOrForceLogin(this.authService);
}})
.withAutomaticReconnect()
.build();
}
return this.itemConnection;
}
I'm using Signalr 2.2.1 with a successful websocket connection.
Here are the events for different states : ( simplified for brevity)
var hub = $.connection.moveShapeHub;
$.connection.hub.start().done(function ()
{
console.log("hub started successfully");
}).fail(function () { console.log('Could not Connect!'); });
$.connection.hub.disconnected(function ()
{
$.connection.hub.start();
console.log('Connection disconnected')
});
My app is working fine as expected.
But look what happen when I disable the network card ( I access my computer not via localhost but via dynamic dns which goes to the world and then comes back to my computer)
At first you can see websocket connection error (I see it multiple times)
WebSocket connection to
'ws://xxxxxx.ddns.net/signalr/reconnect?transport=webSockets&messageId=d-C68A95E5-g%2C1&clientProtocol=1.5&connectionToken=%2FDJL8eAtVtSA3XKeap4Js3IrbkCm56C%2FWKCQtApGiMroWAgnzNoRHmJ0Y2LpIdWWWL%2BfY3dXvJqYHFfby1XYii0ibPpKM55PQuZyf9aH4k9JHIT79lWoMWBasIpa9Gjk&connectionData=%5B%5D&tid=2'
failed: Error in connection establishment:
net::ERR_INTERNET_DISCONNECTED
And then you see endless calls(!!!) to the negotiate
http://xxxx.ddns.net/signalr/negotiate?clientProtocol=1.5&connectionToken=%2FDJL8eAtVtSA3XKeap4Js3IrbkCm56C%2FWKCQtApGiMroWAgnzNoRHmJ0Y2LpIdWWWL%2BfY3dXvJqYHFfby1XYii0ibPpKM55PQuZyf9aH4k9JHIT79lWoMWBasIpa9Gjk&connectionData=%5B%7B%22name%22%3A%22moveshapehub%22%7D%5D&_=1485811277855
Wait ~15 seconds to see the endless loop :
Question
How can I fix those endless calls ? Or alternatvly - increase delay in those "negotiate calls" -say every 2 seconds ( instead of blazing fast endlessly 0.1 seconds)
Edit
I've changed this code :
$.connection.hub.disconnected(function ()
{
$.connection.hub.start();
console.log('Connection disconnected')
});
to this (remove hub start):
$.connection.hub.disconnected(function ()
{
console.log('Connection disconnected')
});
And now I see only this message :
But now I'm losing all the basic idea of "trying restart connecting" in case of disconnect. So I ask again is there any reasonable solution or at least trying "restart the connection every 2 seconds" ?
negotiate is the first request a SignalR client sends to establish a connection. You are trying to start the connection as soon as it gets disconnected in the disconnected event handler. Because the network is down negotiate fails and the disconnected event is invoked and you try to start the connection again.
The documentation shows how to do it with the timeout:
$.connection.hub.disconnected(function() {
setTimeout(function() {
$.connection.hub.start();
}, 5000); // Restart connection after 5 seconds.
});
The answer to all issues of SR connections is check and persist connection status on each server request. I have created a method that takes the proxy method as a parameter and fires the proxy method after establishing the hub connection is available.
call the method using SR_Connection.execute.
When it has established the connection is commits the execution of the request.
function cancel(){
SR_Connection.execute('SRProxy.server.Cancel', uniqueID);
}
var SR_Connection = (function () {
//Start of the Return Statement
return {
execute: function (method, params) {
if ($.connection.hub && $.connection.hub.state === $.signalR.connectionState.disconnected) {
$.connection.hub.start().done(function () {
SR_Connection.commit(method, params);
});
}
else {
SR_Connection.commit(method, params);
}
},
commit: function (method, params) {
var namespaces = method.split("."),
context;
if (typeof (window) == "undefined") {
context = global;
} else {
context = window;
}
var functionToExecute = namespaces.pop();
for (var i = 0; i < namespaces.length; i++) {
context = context[namespaces[i]];
}
context[functionToExecute](params);
}
};//End of the Return Statement
})();
I've got some devices (think heart rate monitor) that are going to send raw TCP packets to my Meteor server. When it receives data, it'll write to the mongodb & then I'll use Meteor to publish and invalidate that data to the client.
As I understand it, sockJS can't do raw TCP packets, so I set up a net server to receive them. The code works great in pure node, but when I use it with npmRequire I get the following error:
Exception while invoking method 'startNet' TypeError: Object #<Object> has no method 'createServer'
Here's my code:
Meteor.methods({
'startNet': function (port) {
var net = Meteor.npmRequire('net');
net.createServer(function (socket) {
console.log("connected");
socket.on('data', function (data) {
console.log(data.toString());
});
}).listen(port);
}
});
Any ideas why the net variable returns an empty object?
Moving the require out of the method should work:
net = Meteor.npmRequire('net');
Meteor.methods({
'startNet': function (port) {
net.createServer(function (socket) {
console.log("connected");
socket.on('data', function (data) {
console.log(data.toString());
});
}).listen(port);
}
});
I have a meteor app that uses the node module MQTTClient.
This client sends events whenever something is published to a topic that the client subscribes too.
When the event happens I'd like to update an entry in a collection, but when I do this I get assertion failures and the DB gets corrupted.
Assertion failed: (handle->InternalFieldCount() > 0), function Unwrap, file ../src/node_object_wrap.h, line 61.
Exited from signal: SIGABRT
Your application is crashing. Waiting for file change.
This is what I currently have:
...
client.connect(function () {
console.log('connected to MQTT broker');
Fiber(function(){
var allTopics = Topics.find({});
allTopics.forEach(function(topic){
console.log('subscribing to ' + topic.name);
client.subscribe(topic.name);
});
}).run();
});
var onPublish = function(topicName, payload, message_id) {
console.log("New message: " + topicName + ":" + payload);
Topics.insert({name: payload, value: payload});
};
var wrappedOnPublish = Meteor.bindEnvironment(onPublish, function(e){
var message = "Something went wrong! " +
"Everything is broken! " +
"Your life is ruined!";
console.log(message, e.stack);
});
client.on('publish', wrappedOnPublish);
I have also tried to handle the callback by wrapping it in a Fiber(..).run() but the exact same error occur.