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

[React-Native] DynamoDB broken? #1614

Closed
hassankhan opened this issue Jul 5, 2017 · 6 comments
Closed

[React-Native] DynamoDB broken? #1614

hassankhan opened this issue Jul 5, 2017 · 6 comments
Labels
guidance Question that needs advice or information.

Comments

@hassankhan
Copy link

hassankhan commented Jul 5, 2017

Hi, we're trying to use DynamoDB from the React-Native SDK and experiencing rather unusual problems in that some requests work, others never seem to complete.

For example, calling DynamoDB.listTables() works as expected, and returns a response every time. However calling DynamoDB.getItem never completes.

We're also using Typescript, so I tried various combinations of import/require-ing the SDK with no change in behaviour.

To enable request logging from the DevTools, we then added the following line:

GLOBAL.XMLHttpRequest = GLOBAL.originalXMLHttpRequest || GLOBAL.XMLHttpRequest

Which unexpectedly started allowing the requests to start working, although intermittently (would fail 2/10 times). I tried using the code @chrisradek posted here

Component.tsx
/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 * @flow
 */
import { AppRegistry, StyleSheet, Text, View } from 'react-native';
import React from 'react';
export interface Props { }
export interface State {
  item: {
    [name: string]: string;
  }
}

import AWSSDK from 'aws-sdk/dist/aws-sdk-react-native';

const awsConfig = new AWSSDK.Config({
  accessKeyId : '',
  secretAccessKey : '',
  region : 'us-east-1'
});

const styles: any = StyleSheet.create({
 container: {
  flex: 1,
  justifyContent: 'center',
  alignItems: 'center',
  backgroundColor: '#F5FCFF'
 },
 welcome: {
  fontSize: 20,
  textAlign: 'center',
  margin: 10
 },
 instructions: {
  textAlign: 'center',
  color: '#333333',
  marginBottom: 5
 }
})

const dynamoDB = new AWSSDK.DynamoDB(awsConfig);

export default class Todo extends React.Component<Props, State> {
  constructor(props) {
    super(props);
    this.state = {
      item : {},
    };
  }
 componentWillMount() {

    dynamoDB.listTables().promise()
      .then((tables) => {
        console.log(tables);
    });


    dynamoDB.getItem({
    Key : {
      name: {
       S: 'a_key'
      },
    },
    TableName : 'a_table'
   }).promise()
    .then((tables) => {
      console.log(tables);
    })
    .catch((error) => {
     console.log(error);
    });
 }
 render() {
  return (
    <View style={styles.container}>
     <Text>hello!! {JSON.stringify(this.state.item, null, 2)}</Text>
     <Text style={styles.instructions}>
      Press Cmd+R to reload,{'\n'}
      Cmd+D or shake for dev menu
     </Text>
    </View>
  );
 }
}
AppRegistry.registerComponent('Todo', () => Todo);
@chrisradek
Copy link
Contributor

@hassankhan
Can you share which version of React Native you're using, and if you're seeing the error in Android or iOS?

I am seeing an issue, but not quite the same as you are. When I try to do a scan, I get a CRC32CheckFailed error. This occurs when the CRC32 checksum the SDK calculates on the response body is different than the value sent back by the service. When this issue is encountered, the SDK will automatically retry the request, up to 10 times (with exponential back-off between tries). With 10 retries, it is possible that the operation would take ~24 seconds to respond, are you sure that's not the case here? You can reduce the number of retries as well.

I think the way the SDK is calculating the checksum for DynamoDB responses may be buggy in React Native, so I'll look into that. As a workaround, you can disable calculating the checksum on the SDK side.

const awsConfig = new AWSSDK.Config({
  accessKeyId : '',
  secretAccessKey : '',
  region : 'us-east-1',
  maxRetries: 2, // reduce number of retries from 10 to 2
  dynamoDbCrc32: false // disable SDK-side crc32 check
});

@hassankhan
Copy link
Author

hassankhan commented Jul 5, 2017

Thanks for the reply @chrisradek! I did also get a CRC32CheckFailed error once, actually. This was for iOS on the Simulator.

"dependencies": {
  "aws-sdk": "^2.78.0",
  "react": "^16.0.0-alpha.12",
  "react-native": "^0.45.1"
},

As you mentioned, it may be possible that it takes a long time but if I override the global XmlHttpRequest I can see the responses returned fine. It's only when I disable it that it seems to not work at all. I'll give it another go with checksumming/retries disabled and report back.

@chrisradek
Copy link
Contributor

@hassankhan
The main reason you see a difference between originalXMLHttpRequest and XMLHttpRequest is that the latter does not enforce CORS in a React Native context. There is an x-amz-crc32 header returned by DynamoDB that when present, the SDK will use to compare its own crc32 checksum of the response against.

In browser environments that support CORS (most/all browsers), this header isn't accessible in the JavaScript runtime because the service doesn't explicitly expose it. For this reason, the CRC32 check isn't performed in browsers.

In React Native, CORS is not enforced, so the JavaScript environment does have access to all headers, including x-amz-crc32. That explains why the check is occurring in a React Native environment and why you wouldn't see this error in a browser.

There is one more gotcha. DynamoDB will gzip the response payload if its size exceeds some threshold (I'm not 100% sure what size that is). According to this comment, DynamoDB calculates the crc32 checksum after the payload is gzipped. By the time it reaches the JavaScript runtime, it is no longer gzipped so the CRC32 checksum the SDK calculates won't match. It's this behavior that causes some checksums to pass and some to fail, correlating to the size of the response body.

We could try disabling gzip (assuming React Native's XMLHttpRequest implementation doesn't overwrite the Accept-Encoding header), but this will cause more data to be transferred over the wire. That might be useful to add as a configuration option for when payload sizes don't matter. In the meantime, disabling the CRC32 check should unblock you for now.

@hassankhan
Copy link
Author

Hi @chrisradek, sorry for the late response, disabling the CRC32 checks works for me 😄

@srchase
Copy link
Contributor

srchase commented Aug 28, 2018

Looks like @chrisradek explanation was suitable to get things working for React-Native.

Closing out this issue.

@srchase srchase closed this as completed Aug 28, 2018
@srchase srchase added guidance Question that needs advice or information. work-in-progress and removed Question labels Jan 4, 2019
@lock
Copy link

lock bot commented Sep 28, 2019

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs and link to relevant comments in this thread.

@lock lock bot locked as resolved and limited conversation to collaborators Sep 28, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
guidance Question that needs advice or information.
Projects
None yet
Development

No branches or pull requests

3 participants