6

I'm developing a chat application and so far i'm polling my server for messages every two seconds. To make the chat more instant i'd like to implement long polling. I'm trying to implement this JS.info Guide for it but i keep not hitting the goal i intend to hit. Can anyone point this out for my case?

I have a custom hook for this in react which is basic polling for now.

FYI: I'm a beginner and wont use WS or Socket.io now. It's too much for me at this point.

Thanks in advance!

export default function useGetChatMessages(_id) {
  const [chatMessages, setChatMessages] = React.useState([]);

  React.useEffect(() => {
    const interval = setInterval(() => {
      getChatMessages(_id).then(fetchedChatMessages => {
        setChatMessages(fetchedChatMessages);
      });
    }, 2000);
    return () => clearInterval(interval);
  }, [_id]);

  return chatMessages;
}

This is my server function with express. I guess it should be implemented here rather than in my hook

router.get('/:id/messages', async (request, response) => {
  try {
    const chat = await Chat.findById(request.params.id);
    response.json(chat.messages);
  } catch (error) {
    console.log(error);
    response.status(500).json({ message: error.message });
  }
});
Sascha Rissling
  • 253
  • 5
  • 15
  • 2
    Personally, I think WS or Socket.IO is easier to implement than polling by magnitudes – yqlim Jan 08 '20 at 15:57

2 Answers2

9

Long polling is basically a way to keep an HTTP connection open, so you would need to implement this on the server side, your front end cannot control what the server does with the request.

As a side note, long polling is generally much more taxing on the server than websockets, and honestly your time would be better spent implementing a websocket connection, setting up a basic ws server is not that difficult if you use a library such as socket.io

Edit: Just as a semantic note, Long polling is an event driven way for the server to send back responses to the client without the client sending a specific request asking for that data, whereas regular polling is just sending requests at a specific interval (It sounds like you already know this because you mentioned wanting to make your polling more instant).

If you are interested in improving your regular polling setup take a look at the other answer.

Travis James
  • 1,879
  • 9
  • 22
  • 1
    you were absolutely right travis. i have now implemented first socket.io code into my app and it's cool to learn something so powerful. Have a great weekend – Sascha Rissling Jan 10 '20 at 23:07
1

Long polling requires changes in the backend as well. So assuming you cannot change the server-side code, you can still implement a more comprehensive basic http polling.
To perform a basic http polling, you must call your API after the last successful call, so you make sure that only one API call is being queued.

I also added a rough Exponential Backoff to better handle errors. That will prevent your frontend hammering your server if you have backend issues (e.g. outage).

An adaptation of your code would look like this:

export default function useGetChatMessages(_id) {
  const [chatMessages, setChatMessages] = React.useState([]);

  React.useEffect(() => {
    let delay = 1000;
    let timeout = null;

    const updateChat = () => {
      getChatMessages(_id).then(fetchedChatMessages => {
        // you must also consider passing a timestamp to the API call
        // so you only fetch the latest messages, instead of all of them every time
        // your state update would look like this:
        // setChatMessages((messages) => [...messages, fetchedChatMessages]);
        setChatMessages(fetchedChatMessages);
        // reset the delay in case an error has happened and changed it.
        delay = 1000;
        // now call the API again after 1 second
        timeout = setTimeout(updateChat, delay);
      }).catch(error => {
        // exponential backoff here.
        // 1 - the first error will call the API after 2sec
        // 2 - the second error will call the API after 4 sec
        // 3 - the third error will call the API after 8 sec
        // and so on
        console.error("Could not update chat. waiting a bit...", error);
        delay = delay * 2;
        timeout = setTimeout(updateChat, delay);
      });
    }

    return () => timeout && clearTimeout(timeout)

  }, [_id]);

  return chatMessages;
}
Bruno Paulino
  • 5,611
  • 1
  • 41
  • 40
  • 1
    Just as a semantic note, this is not long polling, it is just regular polling at a set interval. Long polling is an event driven way for the server to send back responses to the client without the client sending a specific request – Travis James Jan 08 '20 at 15:55
  • 1
    You are absolutely right. This is just a regular http polling. edited my answer to include that. – Bruno Paulino Jan 08 '20 at 15:59
  • 1
    Hey Bruno, thanks for answering with such an effort! :-) Unfortunately this did not fetch my messages and i got a linter message that updateChat is not called anywhere. I tried implementing it but it did not work. I think i will go ahead and spend a couple of hours to learn websockets as i would absolutely have to do this to scale this chat application. – Sascha Rissling Jan 08 '20 at 16:17
  • Maybe it would be a better idea to implement this in my server route which i've posted in my original post? – Sascha Rissling Jan 08 '20 at 16:19