Closed midhunevolvier closed 1 year ago
Hi @midhunchandran97,
Could you check the following:
Meteor.user()
defined?Meteor.ddp.socket
)Hi @TheRealNate,
Thanks for the quick response, We have checked all three items, all are working fine. We are calling a method call just after resuming the app. There was no response from the server. After sometime DDP connected and working fine except for the first method call. No response to the first method call.
What could be the problem?
I'm wondering if this could be the issue: https://github.com/TheRealNate/meteor-react-native/blob/85924c2e32793198c4d5d1601ff726f187460ec3/lib/queue.js#L21-L25
Basically, the way the methods queue was designed, if the socket is connected the method is called and the next one is processed. I'm wondering if when the app gets resumed, if the socket was disconnected when Meteor.call
was called, it does not retry it.
To test this theory, can you try another method call a bit after the first one? That should cause the queue to restart, and you original method should return as well.
Thanks!
Hey @midhunchandran97, any updates on this?
@TheRealNate ,
Sorry for the late reply, I have tried all steps as you told me. But there is no response from the first method call after resuming the app from a minimized state. After a successful DDP connection, I called a method and I got a response. But no response for the first method call even after the successful DDP connection. Whats next ? :(
@TheRealNate , Any updates?
@FaridSafi @spencercarli @sandeepjain @TheRealNate Can anyone help me?
Hey @midhunchandran97. Sorry about the delayed reply, notifications seem to be running a little weird lately.
Could you try wrapping your method call in waitDdpConnected
? E.g.:
Meteor.waitDdpConnected(() => {
Meteor.call(...);
});
Hi @TheRealNate, this didn't work for me.
the meteor connection status is 'connected' while resuming the app. So I think Meteor.waitDdpConnected() has no use here.
Can we have any time out for a method call? Waiting for your reply. Thanks
Hey @midhunchandran97,
For a method call timeout I could add a add-on package (we try not to deviate from the meteor web spec on the core package), but I'd like to see if I can fix your issue.
So from what I understand, after reconnecting you've tried this:
- make a method call (Call 1)
- make another method call (Call 2)
- Call 2 gets a response
- Call 1 never gets a response
Is that right?
Sorry for the double replies. I've noticed that the current ddp implementation doesn't handle websocket errors. Could you try doing this:
Meteor.getData().ddp.socket.rawSocket.onerror = e => console.error(e);
And see if it is logging any errors
Hey @midhunchandran97,
For a method call timeout I could add a add-on package (we try not to deviate from the meteor web spec on the core package), but I'd like to see if I can fix your issue.
So from what I understand, after reconnecting you've tried this:
- make a method call (Call 1) - make another method call (Call 2) - Call 2 gets a response - Call 1 never gets a response
Is that right?
Yes, but there is a change
- make a method call (Call 1)-just after resuming the app from minimized state.
- make another method call (Call 2)- after 4-5 sec resuming the app from minimized state. (meteor will reconnect automatically)
- Call 2 gets a response
- Call 1 never gets a response
Hey @midhunchandran97,
I see you marked this issue as closed. Were you able to fix this issue?
Thanks
Hi @TheRealNate,
Sorry, I accidentally closed the issue
@midhunchandran97 I see, no problem.
Were you able to try this:
Meteor.getData().ddp.socket.rawSocket.onerror = e => console.error(e);
@midhunchandran97 I see, no problem.
Were you able to try this:
Meteor.getData().ddp.socket.rawSocket.onerror = e => console.error(e);
I have tried this, but nothing is consoled.
Hey @midhunchandran97,
Sorry for the delayed reply. I think there may be a flaw in the way the package is handling reconnecting. I'm going to do some more digging into it.
Meanwhile, could you try looking at:
Meteor.getData().ddp.status
At the exact moment of your first method call. In fact if you can get a log of the whole Meteor.getData().ddp
object and post it that would be helpful.
Thanks
Hi @TheRealNate
Sorry for the delayed reply. I have checked the code
Hey @midhunchandran97, is this right before or right after running Meteor.call.
It looks like the socket is definitely open. Could you check on the server if the first method call reached the server or not? It's possible that the first method call is reaching the server but the response isn't making it back. This could help us narrow down the issue.
Also, are you using localhost? It should work, but are you experiencing the same issue with production (or any server not on your lan)?
Hi @TheRealNate
@TheRealNate Is there any way to solve this issue?
Hi @midhunchandran97, sorry about the delay in replying.
Is the method call being triggered by an automatic process as soon as the app returns from background, or is it triggered by a button press a little bit after (is there enough time for the connection to be reestablished).
Could you also try seeing if the socket is opening and closing:
Meteor.getData().ddp.socket.addListener("open", () => console.log("open"));
Meteor.getData().ddp.socket.addListener("close", () => console.log("close"));
Hi @TheRealNate ,
Hi @midhunchandran97,
Thanks for the info. I think we're getting closer to a fix. Could you try running your Meteor call after "open" is called?
Hi @TheRealNate
I tried running the Meteor call after "open" is called, Meteor call worked successfully.
Great!
For a fix, looks like all that needs to be done is:
I'll start on a fix for this. I'll keep this issue open till it is released.
Updates:
So it looks like when the socket is closed, all pending messages are dropped. This could be the root cause of your issue (the method was coming in before the close event was fired), however before I change this I want to check the Meteor spec and see how Meteor handles ddp connection drops. I believe if you start a meteor call while the connection is offline, it will execute once connection is restored, but I wan't to confirm the behavior.
In the meantime, here's a somewhat simple workaround (please excuse any typos as I whipped this up quickly):
let isOpen = true, onOpen = [];
Meteor.getData().ddp.socket.addListener("close", () => {
isOpen = false;
});
Meteor.getData().ddp.socket.addListener("open", () => {
isOpen = true;
onOpen.forEach(f => f());
});
const whenConnected = func => {
if(isOpen) {
func();
}
else {
onOpen.push(func);
}
}
Basically, monitoring the websocket status, and queueing any calls if the socket is closed. Usage:
whenConnected(() => {
Meteor.call("abc", ...);
});
Let me know if there are any issues with the workaround.
@TheRealNate Sorry for the delayed reply,
When I made a normal method call,
Meteor.getData().ddp.socket.addListener("open", () => { isOpen = true; onOpen.forEach(f => f()); }) executed Then 'whenConnected' called and method call successfully executed.
I made a method call just after resuming the app from minimized state.
At that time isOpen variable is true, so 'whenConnected' is executed. After this the following code has executed. Meteor.getData().ddp.socket.addListener("close", () => { isOpen = false; });
This solution is not worked for me.
Hey @midhunevolvier, so you're saying the close event is firing a short time after the app resumes, but not immediately; which is causing your call which executes immediately to run before the close event is fired. Is that right?
Hey @midhunevolvier, so you're saying the close event is firing a short time after the app resumes, but not immediately; which is causing your call which executes immediately to run before the close event is fired. Is that right?
Yes
@TheRealNate Is there any solution? We are stuck.
Hi @midhunevolvier,
I'm looking into a built in solution for this package, but for now a quick fix for you may be to use the AppState API to detect a resume from background and wait before sending the call.
@TheRealNate Ok. But how can I understand whether the Meteor is connected or not? Then only I can wait before sending the call. When I resume from background meteor connection status is 'CONNECTED'.
Hey @midhunevolvier, sorry again for the delayed reply. I don't know why GitHub doesn't seem to be sending me notifications for this issue.
Could you try directly reading the socket object's status (Meteor.getData().ddp.socket
) and let me know if the socket displays as closed upon resume (even if Meteor's connection status hasn't been updated)? If not, I'll need to see why react native has a delay in flagging the socket as closed.
@TheRealNate I have checked the status after resuming the application and attaching the screenshots for your reference. I can't find any difference in the result of application on 'NORMAL' and 'RESUMING' stages
Result of 'Meteor.getData().ddp' (NORMAL)
Result of 'Meteor.getData().ddp' (RESUMING)
Result of 'Meteor.getData().ddp.socket (NORMAL)
Result of 'Meteor.getData().ddp.socket (RESUMING)
'
Hi @midhunevolvier,
Could you try Meteor.getData().ddp.socket.rawSocket
as this should be the socket implementation at the React Native level? If you're not seeing any change here then we may have to look at other options for a fix.
Thanks!
@TheRealNate I have checked 'Meteor.getData().ddp.socket.rawSocket', I can't find any differences.I think the same issue will be there even if we keep the application idle for some time without minimizing it.
@TheRealNate Is there any solution? We are stuck.
@midhunevolvier do you possibly have a minimal reproduction that shows this issue that I could clone and explore the issue?
@copleykj Sorry for the delayed reply. I am busy with my project release. I will upload a sample project as soon as possible.
@midhunevolvier no apology necessary. Delays are in the nature of our work. When ever you get around to it just let me know and I'll see about digging into this. If I'm not responsive here, feel free to get in touch on the Meteor Community Slack.
I will tackle this, once the PR #83 is merged, which is close to completion (currently User, Accounts and Meteor files remain to be tested).
Any update?
@mmelk do you have a minimal code example that I can use to work on / use as test for a potential solution?
Yes, I have. This problem is only for iOS side.
In my case, I received notification (with @react-native-firebase/messaging
and react-native-push-notification
), in background, and I have 2 situations:
Meteor.status()
and Meteor.ddp.status
before Meteor call and it returns true.Example:
import PushNotificationIOS from '@react-native-community/push-notification-ios';
import PushNotification from 'react-native-push-notification';
import { getRequestDetails } from '../../store/drs/actions/drsActions';
import Meteor from '@meteorrn/core';
export const configurePushNotification = (AppState) => {
PushNotification.configure({
onNotification: function (notification) {
const drId = notification?.data?.id || '';
if (drId) {
console.log('Notification_issue Meteor.status()', Meteor.status());
console.log('Notification_issue Meteor ddp status', Meteor.ddp.status);
if (Meteor.userId()) {
// this is my Meteor call, also Meteor.userId() is true
getRequestDetails(drId, (err, data) => {
if (!err) {
// do some stuff
}
}, notification?.data?.section === 'chat');
} else {
// navigate to login screen
}
notification.finish(PushNotificationIOS.FetchResult.NoData);
}
},
permissions: {
alert: true,
badge: true,
sound: true,
},
popInitialNotification: true,
requestPermissions: true,
});
}
And my function where I perform Meteor call
export const getRequestDetails = async (id, callback, isDisabledNewDrUpdate?) => {
Meteor.waitDdpConnected(async () => {
await Meteor.call('clinicians-drs.getOne', { id }, (err, val) => {
if (err) {
// crashlytics
return callback(err.reason, null);
}
return callback(null, val);
});
})
};
@jankapunkt have you any update on this?
@mmelk I have no firebase account nor do we use firebase in any of our projects so I can only test the Meteor.waitDdpConnected
part. Is there a way I can make your issue reproducible without firebase?
@jankapunkt Can you test on the other notification support library? OneSignal maybe? The issue reproduced when I came from background, tapping on the notification from the Notification Center on iOS device. I do meteor call, and in callback I navigate user to corresponding screen, but meteor call is not working, no any response, and the call not reached the server.
Which concerns Meteor.waitDdpConnected
, I logged Meteor.status()
and Meteor.ddp.status
before Meteor call. It says that Meteor is connected successfully.
@mmelk if played a few options here. First, please check your Meteor.connect
in your code and make sure it looks similar to this one:
Meteor.enableVerbose() // more logs in dev mode
Meteor.connect(serverurl, {
AsyncStorage: AsyncStorage,
autoConnect: true,
autoReconnect: true,
reconnectInterval: 500, // try a short value here, the default is 10 Seconds!
})
Then please try the following change to your getRequestDetails
:
export const getRequestDetails = (id, callback) => {
const onError = err => {
cleanup()
return callback(err)
}
const onConnected = () => {
Meteor.call('dead-request', () => {
Meteor.call('clinicians-drs.getOne', { id }, (err, val) => {
cleanup()
if (err) {
// crashlytics here?
return callback(err)
}
return callback(null, val)
});
})
}
const onDisconnected = () => {
console.debug('still disconnected...')
Meteor.reconnect() // force reconnect
}
const cleanup = () => {
// make sure we have no mem-leaks
Meteor.ddp.off('error', onError)
Meteor.ddp.off('connected', onConnected)
Meteor.ddp.off('disconnected', onDisconnected)
}
// finally listen to the events
Meteor.ddp.on('error', onError)
Meteor.ddp.on('connected', onConnected)
Meteor.ddp.on('disconnected', onDisconnected)
}
Now have in your server a Meteor Method named dead-request
that simply does nothing but return null
or something:
Meteor.methods({
'dead-request': function () {
return null
}
})
Here is my observation: as already mentioned in this topic the call is not cached and we have no quick fix for that right now (as I have other PRs in the pipeline but after that I will take a look at this) and the chance is high, that with the default reconnect intervals there will be the first request be missed even if we are reconnected (that's at least my impression from the above conversation).
We therefore need to
I know this might be not 100% accurate, especially for production but maybe it helps to get closer to a solution in the meantime
Describe the bug
Unable to do a method call after resuming from the background after 10-15 mins. Meteor connection status(meteor.status()=true) is true. But no responsce from server. Can anyone help me?
To Reproduce
Steps to reproduce the behavior:
Expected behavior
Should be able to call the methods and get the results from the server even after resuming the app from the background.