Skip to content

Is it possible to allow SSE::Client to control the underlying thread? #72

Closed

Description

@pekopekopekopayo

Hello, sorry for creating issues repeatedly.

Would it be possible to expose control of the underlying thread from SSE::Client?

Here is the relevant code:

module SSE
  class Client
    def initialize(...)
      ....
      @thread = Thread.new { run_stream }
      @thread.name = THREAD_NAME
    end

    def thread
      @thread
    end
  end
end

sse_client = SSE::Client(...)
sse_client.thread.public_send(:kill..join...etc)
...

Adding a method like this would be useful for other users as well, and it could make the client more broadly applicable.

Sorry for the inconvenience, and thank you for your help.

Activity

  1. pekopekopekopayo commented on Dec 12, 2025

    @pekopekopekopayo
    Author

    @jsonbailey I’m sorry, but I’ve come up with a different approach. Could you please take a look at it one more time? 🙇

  2. jsonbailey commented on Dec 12, 2025

    @jsonbailey
    Contributor

    We have decided not to expose the thread in the past as it is an implementation detail that can be easily misused (see #54 (comment)). Can you share more about what you are trying to accomplish with the thread and we can see if there is another way?

  3. pekopekopekopayo commented on Dec 15, 2025

    @pekopekopekopayo
    Author

    I’m trying to organize the synchronization flow between the client and the server.
    As mentioned earlier, if the server sends a message like data: done, I could simply terminate synchronization at that point.
    However, we can’t assume that every server will send such an explicit completion message.

    Instead, I want to terminate synchronization when the connection between the server and the client is closed.
    Handling all of this logic inside on_event feels a bit cumbersome.

    Without directly controlling threads, I could technically poll the connection state, like:

    sleep(1) until sse_client.closed?
    

    But I would much prefer having a callback like on_close, which would make the cleanup logic far clearer.

    So my questions are:
    1. Does the current implementation provide an on_close callback or anything similar?
    2. If not, what is the recommended pattern for implementing this behavior?

    For example, I’m hoping for something like this:

    queue = Queue.new
    sse_client = SSE::Client.new(...) do |client|
      client.on_event do |event|
        ...
      end
    
      client.on_error do |error|
        ...
      end
    
      client.on_close do
        ...
        queue << :done
      end
    end
    
    queue.pop
    

    For now, since there’s no on_close support, I’m considering adding this functionality myself.

  4. jsonbailey commented on Dec 15, 2025

    @jsonbailey
    Contributor

    It is usually up to the client to determine when to close the connection (checking for the data: done). If the server disconnects, the expected behavior is to reconnect and maintain a connection until the client terminates the connection. This helps in case the server was interrupted for the client to pick up where it left off rather than give up.

    The exception to this in the spec is if the server responds with 204 No Content which indicates the client should stop reconnecting. We currently treat this as an error which you can detect with the on_error handler and then close the connection from the client side. This may be the simplest solution for your specific needs as it would give you a callback that you can detect.

    I plan to discuss the 204 response with the team to see if we want to change the behavior of the eventsource when it receives this response. This change would impact our different eventsource implementations so it is unlikely to happen soon.

  5. pekopekopekopayo commented on Dec 16, 2025

    @pekopekopekopayo
    Author

    Got it, thanks for the clarification.
    Given the current behavior and constraints, we’ll probably use a different library for now. Appreciate the explanation!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions