phoenix icon indicating copy to clipboard operation
phoenix copied to clipboard

Channel.push may cause Push's ref be generated twice

Open xh4 opened this issue 3 years ago • 0 comments

Environment

  • Elixir version (elixir -v): 1.12.3
  • Phoenix version (mix deps): 1.6.11
  • Operating system: Windows 11

Expected behavior

A push's ref should not change unless the push was resend.

Actual behavior

When invoke channel.push and when channel.canPush() returns false, the push will be put in channel's pushBuffer,

if(this.canPush()){
  pushEvent.send()
} else {
  pushEvent.startTimeout()
  this.pushBuffer.push(pushEvent)
}

Later when the channel joined, pushes in pushBuffer will invoke the send method which invoke the startTimeout method.

The problem is startTimeout will be called twice on a push if the channel can not push immediately, cause the ref in buffered push be re-generated. And of course the corresponding refEvent timeoutTimer become useless.

startTimeout(){
    if(this.timeoutTimer){ this.cancelTimeout() }
    this.ref = this.channel.socket.makeRef()
    this.refEvent = this.channel.replyEventName(this.ref)

    this.channel.on(this.refEvent, payload => {
      this.cancelRefEvent()
      this.cancelTimeout()
      this.receivedResp = payload
      this.matchReceive(payload)
    })

    this.timeoutTimer = setTimeout(() => {
      this.trigger("timeout", {})
    }, this.timeout)
}

Maybe we should use the resend method instead of send on buffered push.

xh4 avatar Sep 15 '22 03:09 xh4