How do I wait for successful connection using DDP in meteor (server -> server) - meteor

Continuing the discussion from DDP: how do I wait for a connection?:
Based on the thread above, we an leverage Tracker.autorun to wait and confirm for a successful connection between a client and meteor server.
I would like to do the same on a server : server connection
Basically, I have a meteor server (server1), that will need to “test” and see if another meteor server (server2) is available.
Each time I run DDP.connect(remoteUrl).status() within server1’s meteor method, it always says “connection”. I know it connects in the next second or two, but I’m unable to wait for checking the connection success flag.
How do i do this on the server?
Thanks

The idea of reactivity doesn't exist in this form on the server, so something like the Tracker is not an option. Fortunately though there is the onReconnect callback you can use. You can steal the required logic from my meteor-serversync package:
const connection = DDP.connect(URL);
connection.onReconnect = function() {
console.log("(re)connected");
if (!initialized) {
options.onConnect && options.onConnect();
}
};

Related

How to use RedisPool to manage several Redis connections with Swoole websocket

I have a Swoole websocket server and I would like to use a RedisPool to manage several Redis connections to pick one for each query when I get a message. When I try to get a connection from my RedisPool, Swoole outputs an error "Error: Uncaught Swoole\Error: API must be called in the coroutine in #swoole-src/library/core/ConnectionPool.php:69", so I tried to encapsulate my query with Co\Run :
Co\run(function() use ($key, $pool) {
go(function () use ($key, $pool) {
$redis = $pool->get();
$result = $redis->get($key);
$pool->put($redis);
});
});
Then I get "Warning: Swoole\Coroutine\Scheduler::start(): eventLoop has already been created. unable to start Swoole\Coroutine\Scheduler"
I suppose the eventLoop has already been started by my websocket server. Is there a way to access the server eventLoop or another method to run a Coroutine ?

Firestore Timeout [duplicate]

We are building a real-time chat app using Firestore. We need to handle a situation when Internet connection is absent. Basic message sending code looks like this
let newMsgRef = database.document(“/users/\(userId)/messages/\(docId)“)
newMsgRef.setData(payload) { err in
if let error = err {
// handle error
} else {
// handle OK
}
}
When device is connected, everything is working OK. When device is not connected, the callback is not called, and we don't get the error status.
When device goes back online, the record appears in the database and callback triggers, however this solution is not acceptable for us, because in the meantime application could have been terminated and then we will never get the callback and be able to set the status of the message as sent.
We thought that disabling offline persistence (which is on by default) would make it trigger the failure callback immediately, but unexpectedly - it does not.
We also tried to add a timeout after which the send operation would be considered failed, but there is no way to cancel message delivery when the device is back online, as Firestore uses its queue, and that causes more confusion because message is delivered on receiver’s side, while I can’t handle that on sender’s side.
If we could decrease the timeout - it could be a good solution - we would quickly get a success/failure state, but Firebase doesn’t provide such a setting.
A built-in offline cache could be another option, I could treat all writes as successful and rely on Firestore sync mechanism, but if the application was terminated during the offline, message is not delivered.
Ultimately we need a consistent feedback mechanism which would trigger a callback, or provide a way to monitor the message in the queue etc. - so we know for sure that the message has or has not been sent, and when that happened.
The completion callbacks for Firestore are only called when the data has been written (or rejected) on the server. There is no callback for when there is no network connection, as this is considered a normal condition for the Firestore SDK.
Your best option is to detect whether there is a network connection in another way, and then update your UI accordingly. Some relevant search results:
Check for internet connection with Swift
How to check for an active Internet connection on iOS or macOS?
Check for internet connection availability in Swift
As an alternatively, you can check use Firestore's built-in metadata to determine whether messages have been delivered. As shown in the documentation on events for local changes:
Retrieved documents have a metadata.hasPendingWrites property that indicates whether the document has local changes that haven't been written to the backend yet. You can use this property to determine the source of events received by your snapshot listener:
db.collection("cities").document("SF")
.addSnapshotListener { documentSnapshot, error in
guard let document = documentSnapshot else {
print("Error fetching document: \(error!)")
return
}
let source = document.metadata.hasPendingWrites ? "Local" : "Server"
print("\(source) data: \(document.data() ?? [:])")
}
With this you can also show the message correctly in the UI

gRPC Java Client - hasNext during onNext?

I have a server-side streaming gRPC service that may have messages coming in very rapidly. A nice to have client feature would be to know there are more updates already queued by the time this onNext execution is ready to display in the UI, as I would simply display the next one instead.
StreamObserver< Info > streamObserver = new StreamObserver< info >( )
{
#Override
public void onNext( Info info )
{
doStuffForALittleWhile();
if( !someHasNextFunction() )
render();
}
}
Is there some has next function or method of detection I'm unaware of?
There's no API to determine if additional messages have been received, but not yet delivered to the application.
The client-side stub API (e.g., StreamObserver) is implemented using the more advanced ClientCall/ClientCall.Listener API. It does not provide any received-but-not-delivered hint.
Internally, gRPC processes messages lazily. gRPC waits until the application is ready for more messages (typically by returning from StreamObserver.onNext()) to try to decode another message. If it decodes another message then it will immediately begin delivering that message.
One way would be to have a small, buffer with messages from onNext. That would let you should the current message, and then check to see if another has arrived in the mean time.

In Meteor Methods this.connection is always undefined

I am trying to implement some methods for a DDP API, for use with a C# remote client.
Now, I want to be able to track the connection to implement some type of persistent session, to this end, id hope to be able to use the session id given by DDP on connection, example:
{
"msg": "connected",
"session": "CmnXKZ34aqSnEqscR"
}
After reading the documentation, I see that inside meteor methods, I can access the current connection using "this.connection", however, I always get an undefined "this.connection".
Was it removed? If so, how can i access it now?
PS: I dont want to login as a user and access this.userId, since the app I want to create should not login, but actually just get a document id and do work associated with that, including changes to other collections, but all, regarding ONLY this id, and I dont want to have to include this id every time I call a function, since, this could possibly lead security problems if anyone can just send any id. The app would ideally do a simple login, then associate token details with his "session".
Changing from:
() => { this.connection; }
to:
function() { this.connection; }
solves the problem from me. Based on a comment in the accepted answer.
The C# client on github has a few bugs with it as it doesn't follow the DDP spec exactly. When you send commands to it to connect and run a call, it usually sends the '.call' too soon.
The method does work if you do it this way with this.connection on the server side Meteor method.
You need to make sure you send the method calls after you know that you are actually connected. This is what works at least with Meteor 0.8.2
I was using a file named ".next.js" to force meteor to use the newest unsupported javascript spec using a package.
Somehow this messed it up. Changed back to default javascript and it now works.
Thank you :)
init.coffee
Meteor.startup ->
# client init
if Meteor.isClient
Meteor.call "init"
methods.coffee
Meteor.methods
init: ->
console.log #connection.httpHeaders.host
it's that easy...

How to check if Meteor.call() fails when server connection is down?

When the Meteor server connection is lost, how can I verify that Meteor.call() failed? Meteor.call() doesn't return any value. Basically Ctrl+Z in the Meteor shell when your app is running, then do something in the app that triggers a Meteor.call i.e. adding a new blog post:
Meteor.call('createPhrase', phrase, function(error) {
console.log("This NEVER gets called if server is down.");
if (error) {
throwError(error.reason);
}
});
I tried using Session vars, but the reactivity screws it up, i.e. the code below will trigger an error in my template handler (that get's flashed to the browser quickly) and as soon as isMyError is set to true, then when the Meteor.call is successful the error goes away as per isMyError = false, but this looks really sloppy.
Session.set("isMyError", true);
Meteor.call('createPhrase', phrase, function(error) {
console.log("This NEVER gets called if server is down.");
Session.set("isMyError", false);
if (error) {
throwError(error.reason);
}
});
Template.index.isMeteorStatus = function () {
myClientStatus = Meteor.status();
if ( (myClientStatus.connected === false) || (Session.get("isMyError") === true) ) {
return false;
} else {
return true;
}
};
Meteor's calls are generally entered into a queue that are sent to the server in the order that they are called. If there is no connection they stay in the queue until the server is connected once more.
This is the reason nothing is returned because Meteor hopes that it can reconnect then send the call and when it does it does eventually return a result then.
If you want to validate whether the server is connected at the point of the call it's best to check Meteor.status().connected (which is reactive) and only run Meteor.call if it is else throw an error
if(Meteor.status().connected)
Meteor.call(....
else throwError("Error - not connected");
You could also use navigator.onLine to check whether the network is connected.
The reason you would experience a 60 second delay with Meteor.status().connected on the true status of whether meteor is connected or not is there isn't really a way for a browser to check if its connected or not.
Meteor sends a periodic heartbeat, a 'h' on the websocket/long polling wire to check it is connected. Once it realizes it didn't get a heartbeat on the other end it marks the connection disconnected.
However, it also marks it as disconnected if a Meteor.call or some data is sent through and the socket isn't able to send any data. If you use a Meteor.call beforehand to Meteor.status().connected it would realize much sooner that it is disconnected. I'm not sure it would realize it immediately that you can use them one line after the next, but you could use a Meteor.setTimeout after a second or two to fire the call.
Attempt to succeed:
Meteor is designed very well to attempt to succeed. Instead of 'attempting to fail' with an error stating the network is not available its better to try and queue everything up until the connection is back.
The best thing to do would be to avoid telling the user the network is down because usually they would know this. The queued tasks ensure the userflow would be unchanged as soon as the connection is back.
So it would be better to work with the queues that are built into the reconnection process rather than to avoid them.

Resources