Amplify-js: PubSub reconnect

Created on 5 Oct 2018  路  12Comments  路  Source: aws-amplify/amplify-js

Is your feature request related to a problem? Please describe.
When used in React Native on iOS having the app go into background ends the websocket connection. Trying to detect the AppState and then resubscribe does not reconnect the connection

Describe the solution you'd like
Ability to use the paho-mqtt reconnect flag

There does not seem to be a way to keep the MQTT connection alive when in the background on iOS. This is not a problem on Android unless the network connection was lost.

PubSub feature-request

All 12 comments

Hi @rogueturnip I tried this to do reconnection on app state change and it works for me

export default class App extends Component<Props> {

  state = {
    appState: AppState.currentState
  }

  componentDidMount() {
    AppState.addEventListener('change', this._handleAppStateChange);
  }

  componentWillUnmount() {
    AppState.removeEventListener('change', this._handleAppStateChange);
  }

  subscribe = (retrying = 0) => {
    console.warn('subscribing in...', retrying)
    setTimeout(() => {

      const observable = API.graphql(
        graphqlOperation(SubscribeToEventComments, { eventId: eventid })
      );
      subscription = observable.subscribe({
        next: (eventData) => {
          retrying = 0;
          console.warn(eventData)
        },
        error: (data) => {
          const { errors } = data;
          if (errors && errors.find(error => error.message === 'Network Error')) {
            if (retrying === 0) {
              retrying = 50
            }
            this.subscribe(retrying * 2)
          }
          console.warn('something happen', data);
        },
        complete: (data) => console.warn('completed', data)
      });
    }, retrying)
  };

  disconnect = () => {
    console.warn('disconnect', subscription);
    if (subscription && typeof subscription.unsubscribe === 'function') {
      subscription.unsubscribe()
    }
  }

  connect = () => {
    this.disconnect();
    this.subscribe(0);
  }

  _handleAppStateChange = (nextAppState) => {
    // console.warn('App has come to the..!')
    if (this.state.appState.match(/inactive|background/) && nextAppState === 'active') {
      console.warn('App has come to the foreground!')
      this.connect();
    }
    this.setState({appState: nextAppState});
  }


  render() {
    return (
      <View style={styles.container}>
        <Text style={styles.welcome}>Welcome to React Native!</Text>
        <Text style={styles.instructions}>Too get started, edit App.js</Text>
        <Text style={styles.instructions}>{instructions}</Text>
        <Button onPress={this.connect} title="connect"></Button>
        <Button onPress={this.disconnect} title="disconnnect"></Button>
      </View>
    );
  }
}

@elorzafe Thanks so much! I'll give this a try.

So I gave it a try with much simpler function (no retry timeout) and I'm not getting the flow into the error so it can't do the retry. I confirm it's doing the Next cause I see the output.

The error I'm getting that I"m trying to recover from is:
Error: AMQJS0011E Invalid state not connected.

```javascript
genericSub(topic, method) {
return {
topic,
sub: PubSub.subscribe(topic).subscribe({
next: data => {
console.log('MQTT_NEXT');
method(data);
},
error: error => {
console.log('MQTT_CLIENT_ERROR:', error)
this.genericSub(topic,method);
},
close: () => console.log('MQTT_CLIENT: Unsubscribed from', topic)
})
};
}

So I think I figured it out. The addPluggable is where the websocket connection is made (client.connect) so I've put that into the sample spot where I check for active. This then creates a new connection and things seem to start working.

@rogueturnip - is it possible to share you fix for this as I'm still trying to find a way to do this myself with pubsub. Thanks!

It's not elegant and I"m not sure if there are going to be issues constantly recreating the addPluggable when the app goes active but it does seem to reactivate the websocket and resubscribe.
``javascript resubscribe(next) { if (next === 'active') { console.log('MQTT_CLIENT: unsubscribing to all'); Object.keys(this.subscriptions).forEach(topic => { if(isFunction(this.subscriptions[topic].unsubscribe)) { this.subscriptions[topic].unsubscribe(); } }); this.subscriptions = {}; Amplify.addPluggable( new AWSIoTProvider({ aws_pubsub_region: config.cognito.REGION, aws_pubsub_endpoint: config.mqtt.iot }) ); const { userId, selectedHouse } = this.props.local; this.subscriptions = { messages: this.genericSub( alana/${userId}/messages, this.handleMessages(userId) ), house: this.genericSub( alana/${selectedHouse}/devices, this.handleDevices ), modes: this.genericSub( alana/${selectedHouse}/modes`,
this.handleActiveMode(selectedHouse)
),
}
}
}

@rogueturnip - so I finally had chance to look at this again. Using a similar method to you, on disconnect I unsubscribe from all topics, then resubscribe/reconnect by using addPluggable. I start getting messages through, but seem to end up with two client ids (one which is the old client id) and then end up receiving duplicate messages from both clients.

I ended up dumping the amplify library for Mqtt and instead used react_native_mqtt.

Same issue here, if you need to reconnect to a topic it fails, and adding plugabble creates a new clientID, that means everytime we reconnect or change topics we need to execute addPlugabble and this will end up with memory issues.

A method like removePlugabble must be included to fix and have the ability to unsubscribe and start over again.

Still no way of automatically removing the connection or restarting it then?

@kirkryan no that I know.

I ended up dumping the amplify library for Mqtt and instead used react_native_mqtt.

I think we鈥檒l have to do this as well - it鈥檚 incredible that the amplify IOT implementation does not provide reconnect functionality.

@rogueturnip - did you manage to connect using Cognito credentials?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

guanzo picture guanzo  路  3Comments

karlmosenbacher picture karlmosenbacher  路  3Comments

shinnapatthesix picture shinnapatthesix  路  3Comments

epicfaace picture epicfaace  路  3Comments

TheRealRed7 picture TheRealRed7  路  3Comments