Open matthiaszyx opened 4 years ago
I'm having the same issue as well. Also happens on 4.0.1
.
Any plans on addressing this bug?
I also have this issue. The sync behaves fine as long as you don't specify a subscriptionQuery. I played around with the browsers offline mode (Firefox) and found out that even 3.0.1 seems to have an issue with re-connects.
Suppose that there is no subscriptionQuery defined the deltaQuery gets active whenever the browser is back online again - just as expected. When there is subscriptionQuery the sync function breaks when switching the browser to offline mode. The console output just states that the websocket-connection was interrupted.
According to the docs I would expect that the client re-subscribes (https://docs.amplify.aws/lib/graphqlapi/advanced-workflows/q/platform/js#delta-sync): "However, when the device transitions from offline to online, to account for high velocity writes the client will execute the resubscription along with synchronization and message processing "
I did some investigation and found that there is a promise that never gets resolved. When creating a subscription it waits for a control message confirming that the connection has been established.
await new Promise(resolve => {
if (subscriptionQuery && subscriptionQuery.query) {
const { query, variables } = subscriptionQuery;
subscription = client.subscribe<FetchResult, any>({
query: query,
variables: {
...variables,
[SKIP_RETRY_KEY]: true,
[CONTROL_EVENTS_KEY]: true,
},
}).filter(data => {
const { extensions: { controlMsgType = undefined, controlMsgInfo = undefined } = {} } = data;
const isControlMsg = typeof controlMsgType !== 'undefined';
if (controlMsgType) {
subsControlLogger(controlMsgType, controlMsgInfo);
if (controlMsgType === 'CONNECTED') {
resolve();
}
}
return !isControlMsg;
}).subscribe({
// ...
});
} else {
resolve();
}
});
Here the expected control message gets created. However there is a filter that ignores the control message because of the undefined controlEvents flag.
When creating the subscription the flag CONTROL_EVENTS_KEY is passed with the variables property. But it is not correctly evaluated when reading the operation's context.
request(operation: Operation) {
const { query, variables } = operation;
const {
controlMessages: { [CONTROL_EVENTS_KEY]: controlEvents } = {
[CONTROL_EVENTS_KEY]: undefined
},
headers
} = operation.getContext();
return new Observable<FetchResult>(observer => {
// ...
}).filter(data => {
const { extensions: { controlMsgType = undefined } = {} } = data;
const isControlMsg = typeof controlMsgType !== "undefined";
return controlEvents === true || !isControlMsg;
});
}
Would be great if you could provide a solution for this. Thx!
About 14 months later, I found this works for setting the control flag. Have to pass in a context
object as part of the subscription options (Apollo 3 client):
const { error } = useSubscription(
gql`
subscription Events {
onEvent {
id
time
eventName
}
}
`,
{
variables: {},
context: {
controlMessages: {
[CONTROL_EVENTS_KEY]: true,
},
},
onSubscriptionData: (data) => {
console.log('raw data from subscription', data);
const ext = (
data.subscriptionData as {
extensions?: { controlMsgType?: string; controlMsgInfo?: unknown };
}
).extensions;
console.log('extension data', ext);
},
}
);
Doesn't work when passing that flag in via variables
since it's destructured from the result of getContext()
on the operation object.
Do you want to request a feature or report a bug? Bug
What is the current behavior? Delta sync works up to aws-appsync version 3.0.1 but does not work (nothing happens, no result, no error) for version 3.0.2 or greater when a subscriptionQuery is set. Without subscriptionQuery it always works in all versions.
If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem. I took the server code from the official delta sync example https://docs.aws.amazon.com/appsync/latest/devguide/tutorial-delta-sync.html and the client code from here https://docs.amplify.aws/lib/graphqlapi/advanced-workflows/q/platform/js#react-example
Steps to reproduce:
export const createPostMutation = gql(
mutation createPost($input:CreatePostInput!) { createPost(input:$input) { id author title content } }
);export const syncPostsQuery = gql(
query syncPosts { syncPosts { items { id author title content } startedAt nextToken } }
);export const onCreatePostSubscription = gql(
subscription onCreatePost { onCreatePost { id author title content } }
);import React from 'react'; import './App.css'; import AWSAppSyncClient, {AUTH_TYPE} from 'aws-appsync'; import { syncPostsQuery, onCreatePostSubscription, createPostMutation } from "./queries";`
const client = new AWSAppSyncClient({ url: "",
region: "us-west-2",
auth: {
type: AUTH_TYPE.API_KEY,
apiKey: ""
}
});
client.sync({ baseQuery: { query: syncPostsQuery, update: (cache, data) => { console.log("syncPosts baseQuery", data); } }, deltaQuery: { query: syncPostsQuery, update: (cache, data) => { console.log("syncPosts deltaQuery", data); } }, subscriptionQuery: { query: onCreatePostSubscription, update: (cache, data) => { console.log("syncPosts subscriptionQuery", data); } } });
const createPost = () => { client.mutate({ mutation: createPostMutation, variables: { input: { author: "Author", title: "Title", content: "Content" } }, update: (cache, data) => { console.log("createPost", data); } }); }
function App() { return (
); }
export default App;