Skip to content

Problems with setTimeout() #76

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

Open
xchwarze opened this issue Apr 23, 2025 · 0 comments
Open

Problems with setTimeout() #76

xchwarze opened this issue Apr 23, 2025 · 0 comments

Comments

@xchwarze
Copy link

xchwarze commented Apr 23, 2025

I think it is related to #70

My problem was the following: I have an app that has a chatgpt type chat, with an textinput and buttons for predefined questions.
The input and the predefined questions use the same hook to send themselves, which is basically this:

/**
 * Create a chat message via SSE.
 * @param {object} params
 * @param {string} params.query - User message.
 * @param {string} params.token - API key.
 * @param {object} params.eventRef - Ref to store EventSource.
 * @param {Function} params.setMessages - Function to update messages state.
 * @param {Function} params.setLoadingMessageState - Function to update loading state.
 * @returns {void}
 */
const createChatMessage = ({ query, token, eventRef, setMessages, setLoadingMessageState }) => {
    const eventSource = new EventSource(getAiChat(query), {
        headers: { Authorization: `Bearer ${token}` },
        debug: APP_TEST_BUILD,
        timeoutBeforeConnection: 250,
        autoStartPolling: false,
    });

    eventRef.current = eventSource;

    const updatePendingMessage = ({ newContent, isLoading = false, finalUpdate = false }) => {
        setMessages((prevMessages) => {
          // boring code here
        });
    };

    eventSource.addEventListener('open', () => {
        setLoadingMessageState(true);
        updatePendingMessage({ isLoading: true });
    });

    eventSource.addEventListener('close', () => {
        setLoadingMessageState(false);
    });

    eventSource.addEventListener('error', () => {
        // boring code here
    });

    eventSource.addEventListener('message', (event) => {
        // boring code here
    });

    // este metodo es no oficial agregado por mi
    eventSource.startPolling();
};

const useSendMessage = () => {
    const eventSourceRef = useRef(null);
    const apiKey = useSelector(({ user }) => user.apiKey);
    const setMessages = useSetAtom(chatMessagesAtom);
    const setLoadingMessageState = useSetAtom(isLoadingMessageAtom);
    const setIsShowWelcome = useSetAtom(isShowWelcomeAtom);

    const closeEventSource = () => eventSourceRef.current?.close();

    useEffect(() => {
        return () => {
            closeEventSource();
        };
    }, []);

    return useMutation(
        async ({ message }) => {
            return await abstractApiControl(() =>
                createChatMessage({
                    query: message,
                    token: apiKey,
                    eventRef: eventSourceRef,
                    setMessages: setMessages,
                    setLoadingMessageState: setLoadingMessageState,
                }),
            );
        },
        {
            onMutate: async ({ message }) => {
                setIsShowWelcome(false);
                setMessages(...);
            },

            // esto es para apagar los reintengtos y que sea inmediato
            retry: false,
            networkMode: 'always',
        },
    );
};

export default useSendMessage;

But the following started to happen... in some cases the buttons with defined questions did not generate any sse event. But if I used them from other scenarios they did. And if I used the input box it always generated them....
Everything used the same hook so it was very strange.

After debugging for a while I noticed that what was happening was that in those specific scenarios what was failing was that the setTimeout() of the constructor was not executed (the one called in _pollAgain).
So I made these changes and executed it manually and it didn't fail anymore........!

react-native-sse+1.2.1.patch

diff --git a/node_modules/react-native-sse/src/EventSource.js b/node_modules/react-native-sse/src/EventSource.js
index 6a7b146..a02897e 100644
--- a/node_modules/react-native-sse/src/EventSource.js
+++ b/node_modules/react-native-sse/src/EventSource.js
@@ -36,6 +36,7 @@ class EventSource {
     this.debug = options.debug || false;
     this.interval = options.pollingInterval ?? 5000;
     this.lineEndingCharacter = options.lineEndingCharacter || null;
+    this.autoStartPolling = options.autoStartPolling !== false;
 
     this._xhr = null;
     this._pollTimer = null;
@@ -51,7 +52,13 @@ class EventSource {
       this.url = url;
     }
 
-    this._pollAgain(this.timeoutBeforeConnection, true);
+    if (this.autoStartPolling) {
+      this._pollAgain(this.timeoutBeforeConnection, true);
+    }
+  }
+
+  startPolling() {
+    this._pollAgain(this.timeoutBeforeConnection, true)
   }
 
   _pollAgain(time, allowZero) {

If someone has problems you can use my patch with patch-package and leave a comment in this ticket to know if it is useful to add the functionality to the library.
In case you don't understand the idea is to disable the autostart and do it manually by calling the new method.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant