asticode/go-astilectron

Question about amount of event listeners

bogdanfinn opened this issue · 2 comments

This is a general question and i think this is not an issue in go-astilectron.

I have my go application and with go-astilectron a React Application for the UI.

For the go part i created an eventHandler which receives all the JS Events and then distributes them to the corresponding implementations. Simplified this looks like this:

window.OnMessage(func(m *astilectron.EventMessage) interface{} {
		event := events.GuiEvent{}
		_ := m.Unmarshal(&event)

		output, _ := dispatcher.dispatch(ctx, logger, event) // here is a handler function invoked based on the event identifier

		outputEvent := events.NewBackendEvent(event.Name, output)
		jsonOutput, _ := json.Marshal(outputEvent)

		_ = window.SendMessage(string(jsonOutput))

		return nil
	})

Next to that the go application is able to directly send events to javascript.

On the JavaScript side i implemented an EventListener where i register callbacks for given event identifiers.
Simplyfied this looks like this:

public registerEventListener = (eventKey: string, callback: ListenerCallback): string => {
    const uuid = uuidv4()

    if (!this.listeners[eventKey]) this.listeners[eventKey] = {}
    this.listeners[eventKey][uuid] = callback

    return uuid
  }

  public removeEventListener = (eventKey: string, uuid: string) => {
    delete this.listeners[eventKey][uuid]
  }

  public triggerListener = (eventKey: string, data: any) => {
    if (!this.listeners.hasOwnProperty(eventKey)) {
      return
    }

    const callbacks = Object.keys(this.listeners[eventKey]).map((key) => this.listeners[eventKey][key])
    
    callbacks.map((callback) => callback(data))
  }

Everytime my JS Code receives an event it looks in this EventListener for the callbacks registered for the event and invokes them:

astilectron.onMessage(function (message: string) {
    let event: BackendEvent = JSON.parse(message)
    eventManager.triggerListener(event.name, event.data)
  })

Everything works fine. But imagine an application where you can start worker processes in the UI and each one of them is running in a separate go routine in the go application sending status information to the JS application.

When i for example start 50 or more of those processes the whole application has hickups, sometimes freezes and other ui events are not fired anymore (for example i want to start another one via button click). It seems like those X go routines in the go application are flooding the JS application with events and the application is not able to handle this properly.

So my actual question is, is this "issue" a design issue of my own implementation and my bottleneck is somewhere in my own code? Or is go-astilection just not designed to be used for such use cases. Maybe there is a best practice for my use case together with go-astilectron?

When you're experiencing freezes, do you know whether this is JS or GO that is blocking? (I guess this is JS but better sure than sorry)

In all honesty, I don't see anything wrong in the code you've shared. FYI the JS astilectron.onMessage function is declared here. I'm not aware of an ipcRenderer limitation message-wise.

Yeah it is actually the UI that freezes somehow. but it is not a total freeze. Some elements do update, sometimes a click on a button might succeed. It just looks like there are so many events emitted in the go app and send to the frontend that the frontend is not able to evaluate and re-render fast enough.
In Numbers we for example talking about 30 go routines sending a status event every 1-2 seconds - depends how long a working step takes).

If i open the chrome dev tools while running and log every event which is received in astilectron.onMessage i see every event being logged. also the go app does not freeze because it produces events over and over.

My current assumption is that the bottleneck might be my React Application and the triggered re-renders when the state changes. Will look more into that direction.

In all honesty, I don't see anything wrong in the code you've shared.

Thanks for that :-)

And thank you very much for the Code Reference :-)

In all honesty, thank you for your awesome repository :-)