Search code examples
javascriptnode.jsvscode-extensionseventemitter

Node EventEmitter event.on() fires twice after only a single emit issued


I have a VSCode extension (no browser involved) where I need to manage the allocations of session. I have this code snippet in my SessionManager class:

private event = new EventEmitter();
private sessionArray = [];
public async getSession(sessionName: string) {
    let index: number;
    index = this.sessionArray.findIndex((a) => a.sessionName === sessionName && a.inUse === false);
    if (index === -1) {
      // no session available
      await new Promise((resolve) => this.event.on("available", resolve));
      index = this.sessionArray.findIndex((a) => a.sessionName === sessionName && a.inUse === false);
    }
    this.sessionArray[index].inUse = true;
    return { session: this.sessionArray[index], id: index };
  }
  /**
   * set the session status back to available and emit the event
   */
  public async freeSession(id: number) {
    this.sessionArray[id].inUse = false;
    this.event.emit("available");
    return;
  }

My session array has a single entry When I step through the code with debugger first time through I fnd the emtpy slot in sessionArray, i use that slot and set to inUse. A second request comes in for a session, doesn't find one that is available so triggers the await on the promise waiting for the emit event to fire. A third request comes in and does the same thing and queues a Promise on the emit event Finally the 1st request completes and issues the freeSession which sets the slot to available and emits the event. Immediately the event triggers and resolves the promise and triggers finding the now available slot - all good so far.

But...immedately, the event.on triggers again and causes an error as there is no available slot and so index returns with a -1

I am missing something obvious but I cannot see why the event triggers twice in rapid succession after only a single emit was issued.

Any help would be appreciated.


Solution

  • Probably this.event is the same event all the time. So triggering this event will fire all listeners waiting for the event at that moment.

    Also by the way you never remove the old listener (or set it to once) so you have a memory leak and also uselessly call resolve on already-resolved promises.