Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue with Delay in continuous background refresh workflow #1039

Closed
AlexisChevalier opened this issue Jun 27, 2017 · 2 comments
Closed

Issue with Delay in continuous background refresh workflow #1039

AlexisChevalier opened this issue Jun 27, 2017 · 2 comments

Comments

@AlexisChevalier
Copy link

Hello,
First of all thanks for your work on this great library !

I am currently using redux-saga in a react-native project in order to handle the background refresh of my app, my issue is that the background refresh is only executed once then it looks like it is stuck on a delay (see explication below).

The workflow uses two principal sagas (main and backgroundRefresh) :

Main Saga

  1. In a while loop, Take the START_BACKGROUND_REFRESH action
  2. Fork the backgroundRefresh task
  3. Start a while loop
  4. Start a Race between the REFRESH_NOW and the STOP_BACKGROUND_REFRESH actions
  5. Depending on the action that won the race:
    a. If the action was REFRESH_NOW then cancel the backgroundRefresh task and re-fork it
    b. If the action was STOP_BACKGROUND_REFRESH then cancel the backgroundRefresh task and restart at 1

BackgroundRefesh Saga

  1. Put the REFRESH_STARTED action
  2. Call a function (returns a set of credentials)
  3. Call multiple subSagas using yield all() (the sagas are fetching the API and dispatching the corresponding actions)
  4. Put the REFRESH_COMPLETED action
  5. Wait a delay of 30 seconds then if not cancelled restart at 1

The goal is to allow a continuous background refresh once the START_BACKGROUND_REFRESH has been put and as long as the STOP_BACKGROUND_REFRESH has not been put but also to allow an instant refresh with the REFRESH_NOW action.

My issue is with the delay of 30 seconds in the BackgroundRefresh Saga, the saga is just stuck on this delay, it never ends (it ends only when the time is much smaller, like 1 second, in that case it works correctly).

I have tried to run only the BackgroundRefresh saga without the Main one, in that case it works correctly but I need the ability to stop, start and instantly start the refresh process.

Here is a slightly simplified version of the code :

import { take, put, call, fork, cancel, cancelled, all, select, race } from 'redux-saga/effects';
import {delay} from 'redux-saga';
import * as types from "../../constants/actionTypes";

function* mainSaga() {

    while (yield take(types.START_BACKGROUND_REFRESH) ) {

        let bgSyncTask = yield fork(backgroundRefresh);

        while(true) {
            const {refreshNow, stopNow} = yield race({
                refreshNow: take(types.REFRESH_NOW),
                stopNow: take(types.STOP_BACKGROUND_REFRESH)
            });
            
            yield cancel(bgSyncTask);

            if (refreshNow) {
                bgSyncTask = yield fork(backgroundRefresh);
            } else if (stopNow) {
                break;
            }
        }
    }
}

function* backgroundRefresh() {
    try {
        while (true) {
            yield put({ type: types.REFRESH_STARTED});
            let credentials = yield call(getCredentials);

			yield all([
                call(updateData, credentials)
                //Other similar calls
			]);
            yield put({ type: types.REFRESH_COMPLETED});

            yield call(delay, 30000);
        }
    } finally {
        if (yield cancelled()) {
            console.log("CANCELED BY SAGA");
		} else {
            console.error("CANCELED UNEXPECTEDLY");
        }
    }
}

async function getCredentials() {
    return await secureStore.getCredentials();
}

function* updateData(credentials) {
    let data = yield call(fetchData, credentials);
    if (data.response && !data.error) {
        yield put({ type: types.UPDATE_BALANCE, balance: data.response});
    }
}

async function fetchData(credentials) {
    try {
        let response = await apiClient.getData(credentials);
        return {response};
    } catch (error) {
        return {error};
    }
}

export default function* appSagas() {
	yield all([mainSaga()]);
}

Do you have any idea of what could cause such an issue ?
I am new to redux-saga so I guess I made a mistake somewhere in the workflow or overcomplicated the problem.

Thanks !

@Andarist
Copy link
Member

Im thinking it might be some react-native issue, are there any known timer bugs? I think Ive heard about some, but aint sure as im not into react native programming atm.

In general delay is just promisifying setTimeout, its a really thin wrapper - so it doesnt matter if u use 10 or 1000000 as its argument. Its just a setTimeout under the hood.

Could you maybe try to plug in with sagaMonitor to ur middleware and log ur effects? It would help diagnosing the problem. I would only ask you to comment out unrelated sagas to keep the log clean.

@AlexisChevalier
Copy link
Author

AlexisChevalier commented Jun 29, 2017

You are right, the issue is related to facebook/react-native#9436. I just tried without the remote debugger and the saga works perfectly. Sorry for the unrelated issue.

I have also tried to plug in sagaMonitor, unfortunately my attempt was unsuccessful, I encountered the issue mentioned here redux-saga/redux-saga-devtools#13 and another one due to the use of the race effect, I will open another issue on the corresponding repository with more details.

Thanks for your help !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants