asticode/go-astilectron

Question about sending and receiving messages

Joe-Improbable opened this issue · 5 comments

I have a question about whether I can make any assumptions about the order of messages received in Go.

If I have a Go listener that looks like this:

w.OnMessage(func(m *astilectron.EventMessage) interface{} {
        // Unmarshal
        var s string
        m.Unmarshal(&s)
        fmt.Println(s)
        return nil
})

and some JS code that looks like this:

    for (let i = 0; i < 100; i++) {
      astilectron.sendMessage(i);
    }

Can I always expect 0..100 to be printed in order or is it possible for the messages to arrive out of order?

Unfortunately, even though messages are sent through a websocket (which keeps the order), this goroutine kills any assumption regarding order.

The solution to keep the order would be to use this special Chan that allows adding functions to a slice without blocking, and still executing them in order.

Unfortunately I won't have time to work on this, but I'm welcoming PRs.

Unfortunately, even though messages are sent through a websocket (which keeps the order), this goroutine kills any assumption regarding order.

The solution to keep the order would be to use this special Chan that allows adding functions to a slice without blocking, and still executing them in order.

Unfortunately I won't have time to work on this, but I'm welcoming PRs.

Hey @asticode, I'm happy to raise a PR for this, but it seems like this is quite a substantial interface change. If I understand correctly after this change any Go event listeners will be made blocking. Is that correct?

After this change:

  • the interface of dispatcher will not change
  • dispatching an event won't block
  • but listeners will be executed sequentially therefore if one listener blocks forever, it will block next listeners as well

I don't believe this is a substantial change:

  • add a Chan to the dispatcher
  • add a start method to the dispatcher that will be called when starting astilectron and that will start the Chan with astilectron context so that it stops when astilectron stops
  • in dispatch remove the goroutine and instead of calling l(e) directly, call Chan.Add(func() { if l(e) { ... } })

And I think that's pretty much it.

  • but listeners will be executed sequentially therefore if one listener blocks forever, it will block next listeners as well

This is the bit I believe is a breaking change, we have some listeners that are quite long running, so we wouldn't be able to send multiple messages at once, which would break our use-case. I know the fix is to simply create a goroutine for any long running event handler, but I would be a bit surprised at this behaviour if I was updating my astilectron version to a new minor version and was unaware of this thread.

Maybe I'm misunderstanding something

You're definitely right