-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
Datastore unable to stop / clear when logging out #12865
Comments
Hello, @mks11 👋. Sorry to hear you're experiencing this blocker. We're looking into this right now, but this could possibly be related to #12359 as well. That issue was experiencing similar problems when attempting to clear while an Auth event is happening. Can you see if this comment from that issue (which also references 2 comments) helps at all? It details some steps to ensure that the |
@mks11, can you also help clarify where the |
Hi @cwomack, 👋 thank you so much for looking into it, this is the root layout for our NextJS application. removed some of the code. If you check the bottom of the file, there is the function Page() {
const orgID = getOrgId(useUser()); // added snippet below
const [reports, setReports] = useState<Report[]>([]);
const router = useRouter();
useEffect(() => {
const sub = DataStore.observeQuery(
Report,
(r) => r.organizationID.eq(orgID),
{
sort: (s) => s.createdAt(SortDirection.DESCENDING),
}
).subscribe(({ items }) => {
setReports(items);
});
return () => sub.unsubscribe();
}, [orgID]);
return <div> (code removed) </div>
} Amplify.configure(amplifyconfig, {
ssr: true,
});
DataStore.configure({
errorHandler: (err) => {
console.warn("Datastore err", err);
},
authModeStrategyType: AuthModeStrategyType.DEFAULT,
conflictHandler: async (data: SyncConflict) => {
console.log("@@@ conflict @@@ data", data);
return DISCARD;
},
maxRecordsToSync: 50000,
});
function RootLayout({ children }: { children: React.ReactNode }) {
const [isDSReady, setDSReady] = useState(false);
Hub.listen("auth", async (data) => {
switch (data.payload.event) {
case "signedIn":
console.log("user signed in");
break;
case "signedOut":
setDSReady(false);
await DataStore.stop();
await DataStore.clear();
console.log("user signed out");
break;
}
});
Hub.listen("datastore", async (data) => {
console.log(data.payload.event, data.payload.data);
if (data.payload.event === "ready") {
setDSReady(true);
}
});
return (
<html>
<body>
<IsDSReadyProvider isDSReady={isDSReady}>
<Authenticator hideSignUp>
{({ user, signOut }) => {
return (
<PostSignIn user={user} signOut={signOut}>
{children}
</PostSignIn>
);
}}
</Authenticator>
</IsDSReadyProvider>
</body>
</html>
);
}
function PostSignIn({
user,
children,
signOut,
}: {
user: AuthUser | undefined;
children: ReactNode;
signOut: any;
}) {
const segment = useSelectedLayoutSegment() || "";
const [attrs, setAttrs] = useState<FetchUserAttributesOutput>();
const [loading, setLoading] = useState(false);
const [err, setErr] = useState<unknown>();
const isDSReady = useContext(IsDSReady);
useEffect(() => {
fetchUser();
(async () => {
await DataStore.start();
})();
}, [user?.userId]);
async function fetchUser() {
try {
setErr(undefined);
setLoading(true);
const attrs = await fetchUserAttributes();
setAttrs(attrs);
} catch (err) {
setErr(err);
} finally {
setLoading(false);
}
}
console.log("isDSReady", isDSReady);
if (loading) {
return (
// code removed
);
}
if (!attrs?.name || !attrs?.email) {
return;
}
if (!user || err) {
console.log(err);
return;
}
const _user = {
userId: user.userId,
name: attrs.name!,
email: attrs.email,
preferred_username: attrs.preferred_username,
};
return (
<UserProvider user={_user}>
<LoadingBar color="#6B83FF" progress={!isDSReady ? 30 : 100} />
<aside>
<button className="inline-flex" onClick={signOut}>
<LogoutIcon fill={"#7E879C"} />
</button>
</aside>
<div>
{children}
</div>
</UserProvider>
);
}
// context IsDSReady
export const IsDSReady = createContext<boolean>(false);
export function IsDSReadyProvider(props: {
isDSReady: boolean;
children: ReactNode;
}) {
return (
<IsDSReady.Provider value={props.isDSReady}>
{props.children}
</IsDSReady.Provider>
);
}
// context UserProvider
export function UserProvider({
user,
children,
}) {
<UserContext.Provider value={user}>
<DispatchContext.Provider value={() => {}}>
{children}
</DispatchContext.Provider>
</UserContext.Provider>
}
// here is another file where we are subscribing as our first view
function Page() {
const orgID = getOrgId(useUser()); // added snippet below
const [reports, setReports] = useState<Report[]>([]);
const router = useRouter();
useEffect(() => {
const sub = DataStore.observeQuery(
Report,
(r) => r.organizationID.eq(orgID),
{
sort: (s) => s.createdAt(SortDirection.DESCENDING),
}
).subscribe(({ items }) => {
setReports(items);
});
return () => sub.unsubscribe();
}, [orgID]);
return <div> </div> // renders the view (code removed)
}
export function useUser() {
const user = useContext(UserContext);
return user!;
}
export const getOrgId = (user) => user.preferred_username; |
Thank you for the detail about how your application uses DataStore. I tried to pull together a sample app that would use this code and encountered missing pieces. Would it be possible to share an application the is having this error as a public repo or share a private repo explicitely with @cwomack or myself? Looking over this code, I have a couple questions:
Answering questions is helpful, but more than anything getting this error reproduced will help us to provide guidance and fix any underlying issues more directly. Thanks, |
@stocaaro Thank you Aaron for looking into it. Let me get back to you about sharing the repo. But let me quickly answer some of the questions
Regardless we are unsubscribing as soon as the component unmounts after logging out. please let me know if something isn't clear above, and let me get back to you about the share. |
Hello @mks11 , Thanks for the additional input. In my experience Have you been able to log/follow event sequencing to ensure that they are occurring in the order you expect? I would really like to see this error happen in my environment, but I'm missing details about how your app renders components. Things I run into trying to repro: Thanks, |
Hi @stocaaro, I just shared a Todo version of the app with you, please let me know if you'd need anything from me (not sure if I need to create a user account for you). |
Thank you @stocaaro, that's strange because I am seeing it even inside a single tab. But I'd like to add that this happens more consistently when you have another tab open, maybe you could try keeping a tab open (logged in), and login/logout in the current tab inside the same window? Thanks again! |
That did it. Using multiple tabs, I was able to reproduce the issue you describe. Reproduction steps:
Observe that the tab you logged out and then back in on hangs. To un-hang this tab, you can close the other tab and refresh. This happens because the This is one of a couple datastore issues happen when multiple tabs are accessing the same local IndexDB instance at the same time. Related: #7371 Better support for multi-tab/window is on our backlog. I can't find another case that better documents this issue with clear/stop, so I'm going to leave this open marked as a feature request. The issue isn't specifically related to your observeQuery or query calls, having two windows with DataStore started and running means that a clear call in one of them will await until the other window is closed. I've asked around a bit, but don't have a work around recommendation at this time. |
Labeling this as a feature request, as we don't support cross tab signaling out of the box at this point. |
Before opening, please confirm:
JavaScript Framework
Next.js
Amplify APIs
DataStore
Amplify Version
v6 "aws-amplify": "^6.0.9", from package.json
Amplify Categories
auth, api
Backend
Amplify CLI
Environment information
Describe the bug
DataStore fails to clear or stop after logging out. This is the screenshot of the error
This is the snippet from a top level layout
Component A
And this the snippet of the code that should kick off DataStore in a component that is rendered after the user has signed up successfully
Component B
fetchUser
is just fetchUserAttributes() from Amplify v6.Expected behavior
The DataStore should clear after user has signout without throwing the error.
Reproduction steps
Code Snippet
Component A
Component B
Log output
aws-exports.js
No response
Manual configuration
No response
Additional configuration
No response
Mobile Device
No response
Mobile Operating System
No response
Mobile Browser
No response
Mobile Browser Version
No response
Additional information and screenshots
No response
The text was updated successfully, but these errors were encountered: