status-im / nim-chronos

Chronos - An efficient library for asynchronous programming
https://status-im.github.io/nim-chronos/
Apache License 2.0
362 stars 51 forks source link

AsyncEventBus subscribing two callbacks for the same event results in only one being called twice #270

Closed dbrignoli closed 2 years ago

dbrignoli commented 2 years ago
import chronos

type
  Payload = object
    test: int

let eventBus = newAsyncEventBus()

proc eventEV1(bus: AsyncEventBus, payload: EventPayload[Payload]) {.async.} =
  echo "eventEV1"

proc eventEV2(bus: AsyncEventBus, payload: EventPayload[Payload]) {.async.} =
  echo "eventEV2"

proc main() {.async.} =
  var payload: Payload
  discard eventBus.subscribe("EV", eventEV1)
  discard eventBus.subscribe("EV", eventEV2)
  eventBus.emit("EV", payload)
  await sleepAsync(1000)

waitFor main()

Expected output:

eventEV1
eventEV2

Actual output:

eventEV2
eventEV2
dbrignoli commented 2 years ago

using capture from sugar in proc emit[T]() like so:

      capture subscriber_copy:
        callSoon(proc (udata: pointer) = subscriber_copy.cb(bus, event, subscriber_copy, payload))

makes the test code from my previous comment output the expected text.

Menduist commented 2 years ago

Hi, with which GC & nim version are you hitting this? EDIT: Just saw the version 1.6.4

Menduist commented 2 years ago

Thanks for reporting! I have opened an PR integrating your fix, #271

dbrignoli commented 2 years ago

Great, thank you @Menduist! I also tried to capture subscriber directly but found it didn't work. It's probably caused by an issue with the for loop macro implementation.