aws-mobile-appsync-sdk-js icon indicating copy to clipboard operation
aws-mobile-appsync-sdk-js copied to clipboard

Subscription network error

Open wimvdb opened this issue 4 years ago • 17 comments

I use OPENID_CONNECT to authenticate and create a subscription which works fine until after a while the accessToken expires and I get a network error.

How should I configure my subscriptions to automatically refresh the token?

My configuration:

appSyncConfig: {
        auth: {
            type: 'OPENID_CONNECT',
            jwtToken: async () => {
                const result = await getToken();
                if (result) {
                    return result.accessToken;
                }
                return undefined;

            },
        },
}

The subscription:

export const CardSubscriptionGraphQL = gql`
    subscription cardSubscription($ownerId: String!) {
        onCard(ownerId: $ownerId) {
            ...card
        }
    }
    ${card}
`;

The subscription invocation:

export default graphql(CardSubscriptionGraphQL,
        () => {
            return {
                options: (props) => {
                    return {
                        variables: {ownerId: props.ownerId},
                    };
                },
            };
        }
    )(Cards);

wimvdb avatar Dec 19 '19 17:12 wimvdb

It might be unrelated to the token. The error I'm getting is "errorMessage": "AMQJS0007E Socket error:undefined." similar as in issue #286

But I don't have ws as a dependency in my package.json:


"dependencies": {
    "@react-native-community/datetimepicker": "^1.0.0",
    "@react-native-community/netinfo": "^4.6.1",
    "AsyncStorage": "^0.1.5",
    "apollo-cache-inmemory": "^1.6.3",
    "apollo-link": "^1.2.13",
    "apollo-link-context": "^1.0.19",
    "apollo-link-error": "^1.1.12",
    "apollo-link-state": "^0.4.2",
    "apollo-utilities": "^1.3.2",
    "array.prototype.flatmap": "^1.2.2",
    "aws-appsync": "^2.0.2",
    "aws-appsync-react": "^2.0.2",
    "buffer": "^5.4.3",
    "email-validator": "^2.0.4",
    "graphql": "^14.5.8",
    "graphql-tag": "^2.10.1",
    "i18n-js": "^3.5.0",
    "jest-extended": "^0.11.2",
    "jest-mock-console": "^1.0.0",
    "json-server": "^0.15.1",
    "libphonenumber-js": "^1.7.29",
    "mitt": "^1.2.0",
    "nanoid": "^2.1.7",
    "react": "^16.12.0",
    "react-apollo": "^2.5.8",
    "react-fast-compare": "^2.0.4",
    "react-native": "0.60.4",
    "react-native-app-auth": "^4.4.0",
    "react-native-app-settings": "^2.0.1",
    "react-native-contacts": "^5.0.4",
    "react-native-device-info": "^2.3.2",
    "react-native-elements": "^1.2.7",
    "react-native-exception-handler": "^2.10.8",
    "react-native-gesture-handler": "^1.5.2",
    "react-native-iap": "^4.3.0",
    "react-native-image-picker": "^1.1.0",
    "react-native-mixpanel": "^1.1.10",
    "react-native-mock-render": "^0.1.7",
    "react-native-permissions": "^2.0.6",
    "react-native-phone-input": "^0.2.4",
    "react-native-picker-select": "^6.3.3",
    "react-native-simple-toast": "^0.1.1",
    "react-native-splash-screen": "^3.2.0",
    "react-native-swipeout": "^2.3.6",
    "react-native-vector-icons": "^6.6.0",
    "react-native-version": "^3.2.0",
    "react-navigation": "^3.13.0",
    "redux": "^4.0.4",
    "redux-persist": "^4.10.2",
    "rn-fetch-blob": "^0.10.16",
    "sinon": "^7.5.0"
  }

npm ls ws

├─┬ [email protected]
│ └─┬ [email protected]
│   └─┬ [email protected]
│     └── [email protected] 
└─┬ [email protected]
  ├─┬ @react-native-community/[email protected]
  │ ├─┬ [email protected]
  │ │ ├─┬ [email protected]
  │ │ │ └── [email protected] 
  │ │ └── [email protected] 
  │ └── [email protected] 
  └─┬ [email protected]
    └── [email protected] 

wimvdb avatar Dec 21 '19 16:12 wimvdb

I was able to work around the network error by upgrading to aws-appsync 3.0.2 but I'm still have troubles establishing a stable subscription my updated code now looks like this:

export function Cards(props) {

    React.useEffect(() => {
        Cards.unsubscribeNetWorkChanges = subscribeToNetWorkChanges(subscribeToCardUpdatesFunction);
        return () => {
            if (Cards.unsubscribeCardUpdates) {
                Cards.unsubscribeCardUpdates();
            }
            if (Cards.unsubscribeNetWorkChanges) {
                Cards.unsubscribeNetWorkChanges();
            }
        }
    }, []);


    const subscribeToCardUpdatesFunction = () => {
        if (props.accountId) {
            if (Cards.unsubscribeCardUpdates) {
                Cards.unsubscribeCardUpdates()
            }
            Cards.unsubscribeCardUpdates = props.subscribeToMore({
                document: CardSubscriptionGraphQL,
                variables: {
                    ownerId: props.accountId,
                },
                onError: (error) => {
                    console.log(error)
                    trackEvent('Subscription error', error);
                }
            });
        } else {
            trackEvent('accountId not set');
        }
    }

    return (
        <CardsPage cards={props.cards} />
    );
}


export const mapCardsProps = (props) => {
    return {
        cards: props.data?.cards?.items,
        accountId: props.data?.account?.id,
        subscribeToMore: props.data.subscribeToMore,
    };
};


export default graphql(AccountAndCardsGraphQL, selectConfig(mapCardsProps))(Cards);
export const subscribeToNetWorkChanges = (functionToExecute) => {
    return NetInfo.addEventListener((netState) => handleSubscribeOnNetworkChange(netState, functionToExecute));
};

const handleSubscribeOnNetworkChange = (netState, functionToExecute) => {
    if (netState.isConnected && netState.isInternetReachable) {
        console.log('netState.isConnected && internet')
        try {
            functionToExecute()
        } catch (error) {
            trackEvent('Error in handleSubscribeOnNetworkChange', error);
        }
    }
};

What i'm trying to do is if the network drops I want to unsubscribe and re-subscribe once the internet connection becomes stable again. This works on the simulator. If I disable the internet and re-enable it again I can see the subscription working again when the internet is back. I was expecting the onError to trigger at some point by that does not seem to happen.

When I try to do the same thing on a real device by enabling "flight mode" and then disabling "flight mode" again the re-subscribe is not working. The subscription is not receiving updates. It usually fails quietly but sometimes I get this error:

Cannot read property 'subscriptionFailedCallback' of undefined

And another time the app crashed with:

undefined is not an object (evaluating 'n.observer')

Does anyone have an example of a working subscription setup?

wimvdb avatar Dec 26 '19 10:12 wimvdb

I can reproduce this error now consistently on a real device by toggling the wifi on/off and unsubscribing/resubscribing.

IMG_5670

wimvdb avatar Dec 28 '19 12:12 wimvdb

We are seeing something very similar (perhaps the same) with v3.0.2 where subscriptions cause a crash on this line. As @wimvdb mentioned, it happens consistently on real devices when resubscribing. I've struggled to get it to happen in the simulator.

Here's our trace, note it's from dSYM mappings so s.error === observer.error.

image

bensie avatar Jan 08 '20 16:01 bensie

Update after bumping some dependencies and attempting to further isolate the problem, I'm seeing the same error as @wimvdb on the same line.

image

And again, it is very straight-forward to reproduce on a real device. Happens within a few seconds of re-launching the app (background to foreground app starts only - does not happen on fresh app starts).

bensie avatar Jan 08 '20 20:01 bensie

@elorzafe Is this something you could help with? Looks like this whole file came along with your work in #484 with the addition of the new real-time native websockets stuff in AppSync (which is awesome btw). Thanks so much for your work on this!

bensie avatar Jan 08 '20 21:01 bensie

I am getting this a lot too using 3.0.2

jonixj avatar Feb 29 '20 08:02 jonixj

I was able to resolve the problem by updating my velocity templates to the latest version from:

"version": "2017-02-28", to "version": "2018-05-29".

After changing this the connection reconnects automatically after the device goes offline and comes back online. It does take a few minutes before it's ready to receive new messages and messages that were sent while the connection was not yet established are lost.

wimvdb avatar Mar 21 '20 14:03 wimvdb

Wow @wimvdb thanks for sharing. I've been struggling with this one.
I actually don't have velocity templates set up for my subscription. Haven't had a need for one.
I haven't seen an example of a subscription resolver that would basically only set the version like you did... can you share yours?..

roni-frantchi avatar Mar 22 '20 16:03 roni-frantchi

@roni-frantchi sure request.vtl: { "version": "2018-05-29", "payload": {} }

response.vtl: #if(${context.identity.sub} != ${context.arguments.ownerId}) $utils.unauthorized() #else null #end

wimvdb avatar Mar 22 '20 19:03 wimvdb

@wimvdb Sadly I can't say the same. We've been on 2018-05-29 from the beginning for all templates and are still unable to work around this constant crash. There are clearly client-side library issues here where native application scenarios - intermittent connections, suspended/backgrounded app processes, etc - were not considered/tested.

bensie avatar Mar 22 '20 20:03 bensie

Thanks @wimvdb .
Using that though, I'm getting:

{"errorType":"MappingTemplate","message":"Value for field '$[operation]' not found."}

roni-frantchi avatar Mar 23 '20 09:03 roni-frantchi

Do any of you use a failover strategy for their subscription (to handle socket timeouts for example) which tries to unsub/resub agressivelly?

If so I think it could be the issue and related to https://github.com/awslabs/aws-mobile-appsync-sdk-js/issues/515

plus- avatar Jun 15 '20 09:06 plus-

I'm also facing this bug. I upgraded my velocity template versions to "2018-05-29", but that didn't help (note that I don't have any subscription resolvers, just Query and Mutation resolvers).

Tried with 3.0.2, 3.0.3, and 3.0.4 and am still getting the error in the screenshot above ("Undefined is not an object evaluating '_a.observer'). Downgrading to aws-appsync and aws-appsync-react to v2.0.2 fixed the issue and my app no longer routinely crashes.

I'm using Expo SDK v36 which uses React 16.9 and react-native 0.61.

bogan27 avatar Jun 27 '20 18:06 bogan27

also using 2018-05-29, also having this issue

veloware avatar Jul 10 '20 20:07 veloware

These PR1 & PR2 have been opened with related fixes.

KvNGCzA avatar Jan 07 '21 00:01 KvNGCzA

Same problem for me

tmjordan avatar Mar 07 '21 13:03 tmjordan