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

GraphQL subscription with AppSync custom domain fails; stream failed after AWS is configured with message "Exception from WebSocketService". #3028

Closed
2 of 13 tasks
NajAkkad opened this issue May 11, 2023 · 12 comments · Fixed by #3148
Assignees
Labels
bug Something is not working; the issue has reproducible steps and has been reproduced GraphQL API Issues related to the API (GraphQL) Category pending-release Issues that have been addressed in main but have not been released

Comments

@NajAkkad
Copy link

Description

After running the application and configuring AmplifyAPI plugin, when subscribe method is called it fails and returns this exception:

ERROR | WebSocketBloc | Shutting down with exception: AmplifyException {
     "message": "Exception from WebSocketService.",
     "underlyingException": "WebSocketChannelException: WebSocketChannelException: WebSocketException: Connection to 
     '...'

Categories

  • Analytics
  • API (REST)
  • API (GraphQL)
  • Auth
  • Authenticator
  • DataStore
  • Storage

Steps to Reproduce

Mentioned in description

Screenshots

No response

Platforms

  • iOS
  • Android
  • Web
  • macOS
  • Windows
  • Linux

Flutter Version

3.7.11

Amplify Flutter Version

1.0.1

Deployment Method

Amplify CLI

Schema

No response

@fjnoyp
Copy link
Contributor

fjnoyp commented May 11, 2023

Hi @NajAkkad can you please provide more information explaining what you've done so we can reproduce?

  1. Your amplifyconfiguration.dart file with sensitive keys removed
  2. Your graphql.schema file.
  3. The code that causes the exception as well as relevant code before and after
  4. What data is already stored online that you are trying to sync
  5. Do you get this error on iOS as well?

@fjnoyp fjnoyp added GraphQL API Issues related to the API (GraphQL) Category pending-triage This issue is in the backlog of issues to triage pending-community-response Pending response from the issue opener or other community members labels May 11, 2023
@NajAkkad
Copy link
Author

NajAkkad commented May 11, 2023

Hi @NajAkkad can you please provide more information explaining what you've done so we can reproduce?

  1. Your amplifyconfiguration.dart file with sensitive keys removed
  2. Your graphql.schema file.
  3. The code that causes the exception as well as relevant code before and after
  4. What data is already stored online that you are trying to sync
  5. Do you get this error on iOS as well?

Thanks for replying!

  1. This is the setup method used to configure amplify plugins:
Future<void> setupAmplify({
  required AmplifyEnvironment environment,
}) async {
  if (Amplify.isConfigured) {
    return;
  }
  await Amplify.addPlugins([
    AmplifyAPI(),
    AmplifyAuthCognito(),
  ]);
  await Amplify.configure(environment.configuration);
}

and this is the configuration file used:

const amplifyConfigStaging = ''' {
    "UserAgent": "aws-amplify-cli/2.0",
    "Version": "1.0",
    "api": {
        "plugins": {
            "awsAPIPlugin": {
                "graphql-...-backend": {
                    "endpointType": "GraphQL",
                    "endpoint": "https://....com/graphql",
                    "region": "eu-central-1",
                    "authorizationType": "AMAZON_COGNITO_USER_POOLS"
                },
                "api-...-backend": {
                    "endpointType": "REST",
                    "endpoint": "https://....com/v1staging",
                    "region": "eu-central-1",
                    "authorizationType": "AMAZON_COGNITO_USER_POOLS"
                },
                "api-...-kinetic": {
                    "endpointType": "REST",
                    "endpoint": "https://....com/stagingKinetic",
                    "region": "eu-central-1",
                    "authorizationType": "AMAZON_COGNITO_USER_POOLS"
                },
                "api-...-diagnostic": {
                    "endpointType": "REST",
                    "endpoint": "https://....com/stageDiagnostic",
                    "region": "eu-central-1",
                    "authorizationType": "AMAZON_COGNITO_USER_POOLS"
                },
                "api-...-profile": {
                    "endpointType": "REST",
                    "endpoint": "https://....com/profile",
                    "region": "eu-central-1",
                    "authorizationType": "AMAZON_COGNITO_USER_POOLS"
                },
                "api-...-user-subscription": {
                    "endpointType": "REST",
                    "endpoint": "https://....com/stageSubscriptions",
                    "region": "eu-central-1",
                    "authorizationType": "AMAZON_COGNITO_USER_POOLS"
                }
            }
        }
    },
    "auth": {
        "plugins": {
            "awsCognitoAuthPlugin": {
                "UserAgent": "aws-amplify-cli/0.1.0",
                "Version": "0.1.0",
                "IdentityManager": {
                    "Default": {}
                },
                "CognitoUserPool": {
                    "Default": {
                        "PoolId": "",
                        "AppClientId": "",
                        "Region": "eu-central-1"
                    }
                },
                "Auth": {
                    "Default": {
                        "authenticationFlowType": "USER_SRP_AUTH",
                        "socialProviders": [],
                        "usernameAttributes": [
                            "EMAIL"
                        ],
                        "signupAttributes": [
                            "GIVEN_NAME",
                            "BIRTHDATE"
                        ],
                        "passwordProtectionSettings": {
                            "passwordPolicyMinLength": 8,
                            "passwordPolicyCharacters": [
                                "REQUIRES_LOWERCASE",
                                "REQUIRES_UPPERCASE",
                                "REQUIRES_NUMBERS"
                            ]
                        },
                        "mfaConfiguration": "OFF",
                        "mfaTypes": [],
                        "verificationMechanisms": [
                            "EMAIL"
                        ]
                    }
                },
                "AppSync": {
                    "Default": {
                        "ApiUrl": "https://....com/graphql",
                        "Region": "eu-central-1",
                        "AuthMode": "AMAZON_COGNITO_USER_POOLS",
                        "ClientDatabasePrefix": "graphql-...-backend_AMAZON_COGNITO_USER_POOLS"
                    },
                    "graphql-...-backend_AWS_IAM": {
                        "ApiUrl": "https://....com/graphql",
                        "Region": "eu-central-1",
                        "AuthMode": "AWS_IAM",
                        "ClientDatabasePrefix": "graphql-...-backend_AWS_IAM"
                    }
                }
            }
        }
    }
}''';
  1. I can't upload such file, but here's the subscription part of it
type Subscription {
  recordedEvents(userId: String!): EventsRecord @aws_subscribe(mutations : ["publishEvent"])
}
  1. This is the function that is causing the issue.
Stream<AppSyncResult<T>> subscribe<T>(AppSyncRequest<T> subscription) {
    assert(subscription.method == AppSyncMethod.subscribe,
        "Subscribe function required subscribe method");

    final request = GraphQLRequest<String>(
      apiName: AmplifyApiPlugin.appSync,
      document: subscription.document,
      variables: subscription.variables,
    );

    final StreamTransformer<GraphQLResponse<String>, AppSyncResult<T>>
        transformer =
        StreamTransformer.fromHandlers(handleData: (response, sink) async {
      final result = await _handleAction(action: () async {
        final result = subscription.parseResponse(response.data ?? "");

        return Result.success(result);
      });
      sink.add(result);
    });

    final Stream<GraphQLResponse<String>> operation = _api.subscribe(
      request,
    );

    return operation.transform(transformer);
  }
  1. Could you explain more what do you mean by what data?

  2. Not tested on iOS yet.

@Equartey
Copy link
Member

Equartey commented May 12, 2023

Hey @NajAkkad, thanks for over those details. Could you also provide:

  1. The full error message, specifically the underlyingException key
  2. The GraphQL document you're passing to the request

@NajAkkad
Copy link
Author

NajAkkad commented May 14, 2023

Sure.

  1. This is the full error message:
ERROR | WebSocketBloc | Shutting down with exception: AmplifyException {
     "message": "Exception from WebSocketService.",
     "underlyingException": "WebSocketChannelException: WebSocketChannelException: WebSocketException: Connection to '...' was not upgraded to websocket"
}

Note: # is appended to the url, something similar to the discussion here.

subscription RecordedEvents(\$userId: String!) {  
  recordedEvents(userId: \$userId) {
    userId
    source
    events {
      itemId
      type
      name
      createdDate
      payload
    }
  }
}

@cwomack cwomack added Investigating and removed pending-triage This issue is in the backlog of issues to triage labels May 18, 2023
@ragingsquirrel3
Copy link
Contributor

@NajAkkad The only way I was able reproduce this error was by forcing Amplify to try to subscribe to a non-AppSync URL (like API gateway). I was wondering if some configuration you are using caused the wrong URL to be used at runtime. I had a few more questions:

  • Are you able to establish this subscription without error in the AWS console (AppSync console)? If so, is the URL in your Amplify Flutter error message (redacted from your last reply) the same as the AppSync endpoint that the console uses?
  • How was this backend created? Was it made with Amplify CLI or manually some other way? You would still be able to use a non-Amplify backend but I'm just asking this to get more background info that might be helpful.
  • What is the purpose of AmplifyApiPlugin.appSync passed to apiName? It looked like there was only one GraphQL api in your config so it did not seem necessary to provide an argument for apiName but I might be missing something.

@NajdatAlAkkad
Copy link

Thanks @ragingsquirrel3 !

1- Subscription is working well from the same URL, also one note is that this is working fine when I am working on amplify version 0.6.3 but when on version 1.0.1 it's not working.
2- Back-end was created manually using serverless plugin for AppSync before.
3- Yeah, you're right, it was made for future plans.

To iterate more on point one, app was working fine using amplify 0.6.3 but we decided to switch to the latest version, of course different changes was needed to achieve this, after all the changes were made and the app was ready to run again, this exception started popping on subscribe method.

@Jordan-Nelson Jordan-Nelson removed the pending-community-response Pending response from the issue opener or other community members label May 22, 2023
@ragingsquirrel3 ragingsquirrel3 added the to-be-reproduced Issues that have not been reproduced yet, but have reproduction steps provided label May 22, 2023
@NajdatAlAkkad
Copy link

After checking more and more I would like to state one thing.

The reason this was happening is that we are using our own custom domain, which directly link to AppSync, that's why it was failing, but keep in mind that even like this it was working on older versions. (Our custom url provided was ending with :0 for some reason after .com when thrown in exception)

Now we changed url to the direct AppSync one, so it worked.

@Equartey Equartey removed the to-be-reproduced Issues that have not been reproduced yet, but have reproduction steps provided label May 30, 2023
@Stivenmore
Copy link

I have this same problem, we tried to change the url as mentioned by the partner and still it continues without connecting.

Is there any other solution?

@Equartey Equartey assigned ragingsquirrel3 and unassigned Equartey Jun 2, 2023
@ragingsquirrel3
Copy link
Contributor

ragingsquirrel3 commented Jun 2, 2023

@NajdatAlAkkad and @Stivenmore I think this might be making sense but I wanted to get some more info to confirm my understanding.

When you say "custom domain," you mean you have configured appsync custom domain like https://docs.aws.amazon.com/appsync/latest/devguide/custom-domain-name.html? If so, I suspect this is a bug with an easy fix in amplify-flutter because Android handles this use case in a way Flutter does not (see Android code). Before putting out a fix, I wanted to get more info to confirm this issue and recommend workarounds.

That would explain why changing to direct AppSync fixed this. @Stivenmore when you say you "changed the URL" did you change to direct AppSync (which should work) or otherwise change the URL? If you changed to direct and it still didn't work, that is still unexplained. However, if it's a custom domain then tweaking a few characters won't work because the URL must have "/realtime" appended (at runtime) at the end to work. I think the bug is that Android is correctly making this modification at runtime so it's not necessary in the config and amplify-flutter simply doesn't handle this case.

edit: Nevermind, this won't work As another test/confirmation, are you able to manually append "/realtime" to the end of the custom domain URL in the amplifyconfiguration.dart file and subscribe to the custom domain? If so, that would confirm this is the bug I suspect and we can work on a fix on our end. In the meantime, you would have another workaround which is that you could manually add another entry to the config file with the "/realtime" appended URL and refer to it by apiName when running a subscription.

Thanks again for the info and for bringing this issue to our attention.

@ragingsquirrel3
Copy link
Contributor

I was able to reproduce this bug with a custom domain so I will mark this a bug and change the title. I also noticed that changing config file to append "/realtime" will not work (counter to what I said in last message) bc the plugin sets the path to /graphql ignoring the path in config. I will work on getting a fix. In the meantime, I think the only workaround is to use the direct appsync URL.

@ragingsquirrel3 ragingsquirrel3 added the bug Something is not working; the issue has reproducible steps and has been reproduced label Jun 5, 2023
@ragingsquirrel3 ragingsquirrel3 changed the title GraphQL subscription stream failed after AWS is configured with message "Exception from WebSocketService". GraphQL subscription with AppSync custom domain fails; stream failed after AWS is configured with message "Exception from WebSocketService". Jun 5, 2023
@ragingsquirrel3 ragingsquirrel3 added the pending-release Issues that have been addressed in main but have not been released label Jun 8, 2023
@Stivenmore
Copy link

@ragingsquirrel3 Thanks for the help with this case, as you mention I will wait for the release of the version with it solved and I will try.

@dnys1
Copy link
Contributor

dnys1 commented Jun 21, 2023

The fix for this has been released.

@dnys1 dnys1 closed this as completed Jun 21, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something is not working; the issue has reproducible steps and has been reproduced GraphQL API Issues related to the API (GraphQL) Category pending-release Issues that have been addressed in main but have not been released
Projects
None yet
Development

Successfully merging a pull request may close this issue.

9 participants