facebook / react-native

A framework for building native applications using React
https://reactnative.dev
MIT License
118.84k stars 24.29k forks source link

Add support for AlarmManager in Timing to allow proper handling of long timers #12981

Closed astreet closed 5 years ago

astreet commented 7 years ago

Setting timers for multiple minutes isn't handled properly in React Native on Android: it keeps the Timing module awake instead of relying on the system waking us up when the timer should go off.

We should explore setting a cut off at which we delegate to AlarmManager and Handler.postDelayed instead of handling the timers using framecallbacks.

ptomasroos commented 7 years ago

Great improvement!

chirag04 commented 7 years ago

this would help with socket.io which keeps a timer of 85000ms by default. On RN master the threshold is 60000ms.

skv-headless commented 7 years ago

And Firebase which is also using long timers.

imyagnesh commented 7 years ago

I am getting following warning while using firebase library

Setting a timer for a long period of time, i.e. multiple minutes, is a performance and correctness issue on Android as it keeps the timer module awake, and timers can only be called when the app is in the foreground. See https://github.com/facebook/react-native/issues/12981 for more info. (Saw setTimeout with duration 111862ms)

How to get rid of this warning...

oky1 commented 7 years ago

I am getting following warning while using firebase library too. Somebody know how to solve this problem?

VickyKoblinski commented 7 years ago

I am also getting this warning with firebase.

"firebase": "^3.9.0",
"react-native": "0.44.0"
imamatory commented 7 years ago

Same issue (85000ms) but without firebase. My list of packages:

  "dependencies": {
    "apisauce": "0.11.0",
    "format-json": "1.0.3",
    "lodash": "4.17.4",
    "markdown-it": "^8.3.1",
    "native-base": "^2.1.3",
    "normalizr": "^3.2.2",
    "prop-types": "^15.5.10",
    "querystringify": "1.0.0",
    "ramda": "0.23.0",
    "react": "16.0.0-alpha.6",
    "react-markdown": "^2.5.0",
    "react-native": "0.44.0",
    "react-native-animatable": "1.2.0",
    "react-native-config": "0.4.2",
    "react-native-device-info": "0.10.2",
    "react-native-drawer": "2.3.0",
    "react-native-htmlview": "0.9.0",
    "react-native-i18n": "1.0.0",
    "react-native-linear-gradient": "^2.0.0",
    "react-native-photo-view": "^1.2.0",
    "react-native-router-flux": "3.39.1",
    "react-native-scrollable-tab-view": "*",
    "react-native-share": "^1.0.20",
    "react-native-vector-icons": "4.1.1",
    "react-navigation": "^1.0.0-beta.9",
    "react-redux": "5.0.4",
    "redux": "3.6.0",
    "redux-persist": "4.6.0",
    "redux-saga": "0.15.3",
    "reduxsauce": "0.4.1",
    "seamless-immutable": "7.1.2"
  },
  "devDependencies": {
    "ava": "^0.18.2",
    "babel-eslint": "^7.1.1",
    "babel-preset-es2015": "^6.18.0",
    "enzyme": "^2.6.0",
    "husky": "^0.13.1",
    "ignite-animatable": "^0.3.1",
    "ignite-dev-screens": "^2.0.0-beta.9",
    "ignite-i18n": "^0.1.1",
    "ignite-ir-boilerplate-2016": "^0.2.2",
    "ignite-vector-icons": "^0.2.1",
    "mockery": "^2.0.0",
    "nyc": "^10.1.2",
    "react-addons-test-utils": "^15.3.1",
    "react-dom": "^15.4.0",
    "react-native-mock": "^0.3.1",
    "reactotron-apisauce": "^1.7.0",
    "reactotron-react-native": "^1.7.0",
    "reactotron-redux": "^1.7.0",
    "reactotron-redux-saga": "^1.7.0",
    "snazzy": "^6.0.0",
    "standard": "^8.6.0"
  }
zibs commented 7 years ago

I'm experiencing a similar issue using 0.44.0 on Android. I am also not using firebase:

Setting a timer for a long period of time, i.e. multiple minutes, is a performance and correctness issue on Android as it keeps the timer module awake, and timers can only be called when the app is in the foreground. See https://github.com/facebook/react-native/issues/12981 for more info. (Saw setTimeout with duration 85000ms)

deejaygeroso commented 7 years ago

Hi there guys.. was wondering Is there any quick work around for this. I'm using:

react-native 0.44 react 16.0.0-alpha.6 feathers-socketio 1.6.0

Its very annoying popping out while I'm developing.. is there anyway I can hide the warning for now??

aleinnocenzi commented 7 years ago

Same issue here with firebase 3.9.0

skv-headless commented 7 years ago

If it bothers you just add console.ignoredYellowBox = ['Setting a timer'];

RWOverdijk commented 7 years ago

@skv-headless Opinion incoming. :)

In my opinion that attitude towards problems needs to go away. I've been seeing it pop up more often and it's causing people to ignore warnings. They're warnings. They warn you. Don't ignore them, do something. I've seen apps where all warnings just get ignored, even deprecation notices. Then your app breaks and you're left wondering why.

In this case, you can configure these timeouts and lower them, or setup a different approach of dealing with them. Maybe even poke the maintainers of the libraries and ask them to help come up with a solution.

My advise, is to follow this thread until someone smart comes up with an actual solution, so you can then educate yourself with that answer. And then maybe, in the meantime (if you can't / don't want to teckle the issue) ignore the warnings.

TL;DR;

Yes, you can ignore the warnings temporarily. Just check in every now and then to see what the status is and if there's any action required.

rigobcastro commented 7 years ago

@imamatory I think is by Rectotron

imamatory commented 7 years ago

I think is by Rectotron

If so, this warning can be simply ignored. ...however my android emulator getting slow sometimes, maybe it is one of reasons.

rigobcastro commented 7 years ago

@imamatory I hope the real solution is just as easy

nicolasZZ commented 7 years ago

Hi, I think I found the solution: Firstly you have to find the following file in your project: libraries/Core/Timers/JSTimer;js Open it and you just have to change this const MAX_TIMER_DURATION_MS, to increase above your duration, wrote in the end of warning !

AmroAly commented 7 years ago

@nicolasZZ hi, Thanks for the solution. but Is that a good practice to modify the JSTimer library rather than our own code?

rigobcastro commented 7 years ago

@nicolasZZ @AmroAly In my mind this solution is not a good practice because it is very unstable, the best is ignore the alert while the official solution is released.

console.ignoredYellowBox = [
    'Setting a timer'
]

the @skv-headless's solution is good but in my case only works with "enter" between of the parenthesis

AmroAly commented 7 years ago

@rigobcastro Thanks that hides the annoying alerts.

chirag04 commented 7 years ago

@DZuz14 it would be awesome if you could sent a PR or atleast get the conversation started. Thanks 👍

simpleblack commented 7 years ago

hi~ I used socket.io. nodejs and RN44 or RN 45 I saw warning this timers.

I found this solution reference reactotron PR

personal server nodejs and scoket.io

const express = require('express')
const app = express()
const server = require('http').Server(app)
const io = require('socket.io')(server, {pingTimeout: 30000})

Thanks!

saeedhei commented 7 years ago

I have a simple react native project for android and I'm using firebase auth with react native for Login and Signup, but I got that yellow error, What should I do? Link of my Question in stackoverslow (https://stackoverflow.com/questions/44603362/setting-a-timer-for-a-long-period-of-time-i-e-multiple-minutes )

saeedhei commented 7 years ago

Thank You @DZuz14 I Got This Error When I run react-native run-android

D:\Projects 2016\Web\Android\mohajerkade-android\android\app\src\main\java\com\mohajerkade\AlarmManagerModule.java:40: error: cannot find symbol
       Intent intent = new Intent(context, AlarmReceiver.class);
                                           ^
  symbol:   class AlarmReceiver
  location: class AlarmManagerModule
1 error
:app:compileDebugJavaWithJavac FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:compileDebugJavaWithJavac'.
> Compilation failed; see the compiler error output for details.

I want to use firebase auth with react native for Login and Signup but I got That yellow error, 1: What is This Module Exactly? 2: Why My Project need This Module?

I asked stackoverflow through this link: (https://stackoverflow.com/questions/44603362/setting-a-timer-for-a-long-period-of-time-i-e-multiple-minutes) I Reported to Google Firebase Team through this link: (https://github.com/firebase/firebase-js-sdk/issues/97)

BerndWessels commented 7 years ago

@DZuz14 I got the same question as @saeedhei .

Basically we are using the firebase node module that uses these long period timers.

Adding your module is not enough I guess, we actually have to rewrite the code within the firebase node module to use your Alarms rather than Javascript timers, right?

BerndWessels commented 7 years ago

Thanks @DZuz14

So if you look into the npm package called firebase you will find that it uses setTimeout in quite a lot of places. This is OK since the library was written for websites and node.js servers. react-native is kind of a node.js server but it runs on a phone - and as the warning correctly points out - long running Javascript timers are not good in this environment and might drain the battery and have other unwanted side effects.

So I guess we have to convince the Firebase guys actually to change to your approach and distribute a package made especially for react-native.

DZuz14 commented 7 years ago

@BerndWessels https://www.npmjs.com/package/react-native-firebase Have you looked at this? Says it allows firebase to run on the native thread. Not sure how true that is, but might be worth a look. You might even be using that, I'm not sure.

BerndWessels commented 7 years ago

@DZuz14 Thanks, I'll check that out.

Jazz747 commented 7 years ago

console.ignoredYellowBox = [ 'Setting a timer' ]

@rigobcastro Where can I input or paste this code?

rigobcastro commented 7 years ago

@Jazz747 On the top of your setup file for example app.js, index.android.js or index.ios.js

vzhen commented 7 years ago

console.ignoredYellowBox = [ 'Setting a timer' ] This code only hide the warning inside react native.

How about the warning inside browser console?

SuhairZain commented 7 years ago

Does anyone know if someone from the RN team or the community is working on a solution to this issue?

The warning popup redirects to this issue but I can't find any proper solution here other than to hide the warning, which isn't a solution at all. Any ideas or suggestions?

rigobcastro commented 7 years ago

@SuhairZain Everything seems to indicate that are errors of external libraries to RN

SuhairZain commented 7 years ago

@rigobcastro This warning can be easily reproduced with a setInterval() call with a time long enough (which was 5 minutes in my case). So I'd say this isn't something caused by 3rd party libs.

BTW, I've since found a library here: react-native-background-timer which helps me get the job done.

rigobcastro commented 7 years ago

@SuhairZain yes u right! my problem was with 3rd party lib but the owner fixed the error (I imagine they just changed some setInterval()) and the warning disappeared.

Good recommendation, thanks.

escalepion commented 7 years ago

i have same problem here. And still couldent understand how should i handle with this problem.

rn: 0.45.1 firebase: 4.1.3

saeedhei commented 7 years ago

Dear @escalepion I reported to firebase team: (https://github.com/facebook/react-native/issues/12981#issuecomment-309595327)

SuhairZain commented 7 years ago

@escalepion If your problem is about setting long running timers, please take a look at my comment above and see if it helps you.

escalepion commented 7 years ago

@SuhairZain sorry i couldent understand that how can use setInterval or react-native-background-timer :( where and how will i write the code ? do u have an example?

abeltje1 commented 7 years ago

Does anyone have a tip on how to figure out which library is causing the harm? I recently upgraded RN to 0.46 and suddenly this error appeared. I have quite some libraries in my project and I can only think of investigating them one by one, which obviously isn't ideal.

Cheers!

liketurbo commented 7 years ago

@abeltje1, if you figure out how fix this issue, could you, please, update here

abeltje1 commented 7 years ago

@liketurbo for sure I will

sospedra commented 7 years ago

I'm having this issue alongside with redux-saga to revalidate the API token every 30 minutes.

Hence, in this case, awaiting for this long is actually correct. And I guess that there are others scenarios which long waiting are expected.

Then my question is, why is this a warning? What can break/happen? Am I not supposed to being able to use any LLT (long lived transactions)?

If LLT are ok. What would be the best approach to handle this issue? Expanding AlarmManager time?

Thanks in advance ;)

jordanmkoncz commented 7 years ago

I'm having the same issue as @sospedra. I'm using redux-saga and I have a saga that refreshes some data in the app in the background every 3 minutes, so the saga includes the code yield call(delay, 3 * 60000);. As a result I'm getting this "Setting a timer for a long period of time..." error.

I'm also wondering what the suggested approach is for something like this. What problems will I run into if I just leave my code working this way. The error message implies there could be performance issues, and perhaps that the timer won't actually get fired at the correct time if the app is in the background?

If there are likely to be problems with this code setting a 3 minute timer, what alternative solution would achieve the same functionality and not run into these problems?

shaheerakhlaq commented 7 years ago

still getting same issue.

liketurbo commented 7 years ago

I think, the only solution it's move to Native Android Development

tranhung8382 commented 7 years ago

The issue still cannot solve? Anyone found the solution?

egvrcn commented 7 years ago

I am getting warning while using firebase.

SuhairZain commented 7 years ago

If the issue isn't from a 3rd party library, but from you setting a long timeout yourself, a good solution is to use the react-native-background-timer library. It's README contains a simple example as well.

Unfortunately, if the issue is from a 3rd party library, you probably have no solution other than to find the place where the setTimeout is called and raise an issue / submit a PR to use the aforementioned library instead, please try my possible solution below at https://github.com/facebook/react-native/issues/12981#issuecomment-331074444 and try if it works for you.

allmaxgit commented 7 years ago

Please make great timeout on android too.

heyman333 commented 7 years ago

react-native-background-timer is a good workaround as @SuhairZain said. this can clear warning msg