giray
giray8mo ago

Chat App Bandwidth Problem

Hi, I am building a chat based multiplayer game. As you might guess, there can be many players and chat is being used a lot in the game. To get the chat I use the below query:
export const getAllForGame = query({
args: {
gameId: v.id("games"),
},
handler: async (ctx, args) => {
const chat = await ctx.db
.query("chat")
.withIndex("by_gameId", (q) => q.eq("gameId", args.gameId))
.order("desc")
.take(50);
return chat.reverse();
},
});
export const getAllForGame = query({
args: {
gameId: v.id("games"),
},
handler: async (ctx, args) => {
const chat = await ctx.db
.query("chat")
.withIndex("by_gameId", (q) => q.eq("gameId", args.gameId))
.order("desc")
.take(50);
return chat.reverse();
},
});
The problem is that the game consumes a lot of bandwidth because of the chat and the problem is, a new action (new message or a reaction to any message) triggers a fetch, and I believe all clients who uses the above query, re-fetch the most recent 50 chat messages. Normally, I want to fetch all chat messages, I limited it to 50 because of this bandwidth problem. I believe there should be a better way to fetch the chat messages for me. I have checked the paginated queries, however I could not figure out how to implement it for this problem. Mainly, I want to fetch all chat messages for a game, but I do not want it to re-fetch everything when a new message comes. (I believe Convex does not only send the changes but sends the result of the query as a whole). Convex caches the result of the query but the problem is not the cache, it is the bandwidth. I had to start a premium account even in the development stage and if I can not solve this problem, the game will not scale well. For example, if I can paginate somehow and it seperates the whole chat into bundles of different queries than it will only consume bandwidth for small bundle changes. Any suggestions?
4 Replies
Michal Srb
Michal Srb8mo ago
Yes, paginated queries are the answer. You can call loadMore() from your UI to load more and more messages, enough to fill the screen, and more again when the user scrolls to see more messages.
Michal Srb
Michal Srb8mo ago
Here's an example of the React code for implementing infinite scrolling list: https://github.com/get-convex/convex-nextjs-app-router-demo/blob/main/app/(common)/PostsScrollView.tsx
GitHub
convex-nextjs-app-router-demo/app/(common)/PostsScrollView.tsx at m...
Demo showing a Next.js App Router app powered by Convex backend - get-convex/convex-nextjs-app-router-demo
giray
girayOP8mo ago
Hi Michal, thanks for the response. I have a feeling that my problem is a little different. Let me clarify a little bit more: In my chat game, every player start with an empty chat and they get messages as other players write to the chat. So in theory they do get all the messages from the beginning so there is no need for "load more". Because they start with an empty chat and it is getting filled. The problem is about the bandwidth, so at every new message a lot of "already seen" messages also getting fetched. I think one solution is to separate the whole chat into chunks like the image, so that when a chunk is filled, a new query listens the next chunk and starts to fill it up. So I am thinking about this solution may be:
export function App() {
const { results, status, loadMore } = usePaginatedQuery(
api.chat.getAllForGame,
{gameId},
{ initialNumItems: 5 },
);

useEffect(() => {
if(status.canLoadMore) loadMore()
}, [status])

return (
// display chat
);
}
export function App() {
const { results, status, loadMore } = usePaginatedQuery(
api.chat.getAllForGame,
{gameId},
{ initialNumItems: 5 },
);

useEffect(() => {
if(status.canLoadMore) loadMore()
}, [status])

return (
// display chat
);
}
Would this do what I expect it to do? So that after 5 messages, it loads 5 more and does not re-fetch the first 5 items (if not changed). Will this help with my bandwidth problem? Also I saw another post here that mentions the cached results does not count towards the bandwidth, is it right? If so, I am trying to figure out why I have almost 1GB bandwidth consumed for about 10-15 games.
No description
giray
girayOP8mo ago
I am also very inclined to do this as well , I am just not sure, because I do not understand the bandwidth consumtion very clearly.
export function App() {
const { results, status, loadMore } = usePaginatedQuery(
api.chat.getAllForGame,
{gameId},
{ initialNumItems: 1 },
);

useEffect(() => {
if(status.canLoadMore) loadMore()
}, [status])

return (
// display chat
);
}
export function App() {
const { results, status, loadMore } = usePaginatedQuery(
api.chat.getAllForGame,
{gameId},
{ initialNumItems: 1 },
);

useEffect(() => {
if(status.canLoadMore) loadMore()
}, [status])

return (
// display chat
);
}