fix(slotqueue): asyncSpawns futures correctly
- asyncSpawns `run` and worker `dispatch` in slotqueue. - removes usage of `then` from slotqueue.
This commit is contained in:
parent
dc244a36bd
commit
f241d84e18
|
@ -10,7 +10,6 @@ import ../rng
|
||||||
import ../utils
|
import ../utils
|
||||||
import ../contracts/requests
|
import ../contracts/requests
|
||||||
import ../utils/asyncheapqueue
|
import ../utils/asyncheapqueue
|
||||||
import ../utils/then
|
|
||||||
import ../utils/trackedfutures
|
import ../utils/trackedfutures
|
||||||
|
|
||||||
logScope:
|
logScope:
|
||||||
|
@ -333,7 +332,7 @@ proc addWorker(self: SlotQueue): ?!void =
|
||||||
|
|
||||||
proc dispatch(self: SlotQueue,
|
proc dispatch(self: SlotQueue,
|
||||||
worker: SlotQueueWorker,
|
worker: SlotQueueWorker,
|
||||||
item: SlotQueueItem) {.async.} =
|
item: SlotQueueItem) {.async: (raises: []).} =
|
||||||
logScope:
|
logScope:
|
||||||
requestId = item.requestId
|
requestId = item.requestId
|
||||||
slotIndex = item.slotIndex
|
slotIndex = item.slotIndex
|
||||||
|
@ -380,22 +379,7 @@ proc clearSeenFlags*(self: SlotQueue) =
|
||||||
|
|
||||||
trace "all 'seen' flags cleared"
|
trace "all 'seen' flags cleared"
|
||||||
|
|
||||||
proc start*(self: SlotQueue) {.async.} =
|
proc run(self: SlotQueue) {.async: (raises: []).} =
|
||||||
if self.running:
|
|
||||||
return
|
|
||||||
|
|
||||||
trace "starting slot queue"
|
|
||||||
|
|
||||||
self.running = true
|
|
||||||
|
|
||||||
# must be called in `start` to avoid sideeffects in `new`
|
|
||||||
self.workers = newAsyncQueue[SlotQueueWorker](self.maxWorkers)
|
|
||||||
|
|
||||||
# Add initial workers to the `AsyncHeapQueue`. Once a worker has completed its
|
|
||||||
# task, a new worker will be pushed to the queue
|
|
||||||
for i in 0..<self.maxWorkers:
|
|
||||||
if err =? self.addWorker().errorOption:
|
|
||||||
error "start: error adding new worker", error = err.msg
|
|
||||||
|
|
||||||
while self.running:
|
while self.running:
|
||||||
try:
|
try:
|
||||||
|
@ -405,8 +389,8 @@ proc start*(self: SlotQueue) {.async.} =
|
||||||
# block until unpaused is true/fired, ie wait for queue to be unpaused
|
# block until unpaused is true/fired, ie wait for queue to be unpaused
|
||||||
await self.unpaused.wait()
|
await self.unpaused.wait()
|
||||||
|
|
||||||
let worker = await self.workers.popFirst().track(self) # if workers saturated, wait here for new workers
|
let worker = await self.workers.popFirst() # if workers saturated, wait here for new workers
|
||||||
let item = await self.queue.pop().track(self) # if queue empty, wait here for new items
|
let item = await self.queue.pop() # if queue empty, wait here for new items
|
||||||
|
|
||||||
logScope:
|
logScope:
|
||||||
reqId = item.requestId
|
reqId = item.requestId
|
||||||
|
@ -434,19 +418,34 @@ proc start*(self: SlotQueue) {.async.} =
|
||||||
|
|
||||||
trace "processing item"
|
trace "processing item"
|
||||||
|
|
||||||
self.dispatch(worker, item)
|
asyncSpawn self.dispatch(worker, item).track(self)
|
||||||
.track(self)
|
|
||||||
.catch(proc (e: ref CatchableError) =
|
|
||||||
error "Unknown error dispatching worker", error = e.msg
|
|
||||||
)
|
|
||||||
|
|
||||||
await sleepAsync(1.millis) # poll
|
await sleepAsync(1.millis) # poll
|
||||||
except CancelledError:
|
except CancelledError:
|
||||||
trace "slot queue cancelled"
|
trace "slot queue cancelled"
|
||||||
return
|
break
|
||||||
except CatchableError as e: # raised from self.queue.pop() or self.workers.pop()
|
except CatchableError as e: # raised from self.queue.pop() or self.workers.pop()
|
||||||
warn "slot queue error encountered during processing", error = e.msg
|
warn "slot queue error encountered during processing", error = e.msg
|
||||||
|
|
||||||
|
proc start*(self: SlotQueue) =
|
||||||
|
if self.running:
|
||||||
|
return
|
||||||
|
|
||||||
|
trace "starting slot queue"
|
||||||
|
|
||||||
|
self.running = true
|
||||||
|
|
||||||
|
# must be called in `start` to avoid sideeffects in `new`
|
||||||
|
self.workers = newAsyncQueue[SlotQueueWorker](self.maxWorkers)
|
||||||
|
|
||||||
|
# Add initial workers to the `AsyncHeapQueue`. Once a worker has completed its
|
||||||
|
# task, a new worker will be pushed to the queue
|
||||||
|
for i in 0..<self.maxWorkers:
|
||||||
|
if err =? self.addWorker().errorOption:
|
||||||
|
error "start: error adding new worker", error = err.msg
|
||||||
|
|
||||||
|
asyncSpawn self.run().track(self)
|
||||||
|
|
||||||
proc stop*(self: SlotQueue) {.async.} =
|
proc stop*(self: SlotQueue) {.async.} =
|
||||||
if not self.running:
|
if not self.running:
|
||||||
return
|
return
|
||||||
|
|
|
@ -27,8 +27,8 @@ suite "Slot queue start/stop":
|
||||||
check not queue.running
|
check not queue.running
|
||||||
|
|
||||||
test "can call start multiple times, and when already running":
|
test "can call start multiple times, and when already running":
|
||||||
asyncSpawn queue.start()
|
queue.start()
|
||||||
asyncSpawn queue.start()
|
queue.start()
|
||||||
check queue.running
|
check queue.running
|
||||||
|
|
||||||
test "can call stop when alrady stopped":
|
test "can call stop when alrady stopped":
|
||||||
|
@ -36,12 +36,12 @@ suite "Slot queue start/stop":
|
||||||
check not queue.running
|
check not queue.running
|
||||||
|
|
||||||
test "can call stop when running":
|
test "can call stop when running":
|
||||||
asyncSpawn queue.start()
|
queue.start()
|
||||||
await queue.stop()
|
await queue.stop()
|
||||||
check not queue.running
|
check not queue.running
|
||||||
|
|
||||||
test "can call stop multiple times":
|
test "can call stop multiple times":
|
||||||
asyncSpawn queue.start()
|
queue.start()
|
||||||
await queue.stop()
|
await queue.stop()
|
||||||
await queue.stop()
|
await queue.stop()
|
||||||
check not queue.running
|
check not queue.running
|
||||||
|
@ -62,8 +62,6 @@ suite "Slot queue workers":
|
||||||
queue = SlotQueue.new(maxSize = 5, maxWorkers = 3)
|
queue = SlotQueue.new(maxSize = 5, maxWorkers = 3)
|
||||||
queue.onProcessSlot = onProcessSlot
|
queue.onProcessSlot = onProcessSlot
|
||||||
|
|
||||||
proc startQueue = asyncSpawn queue.start()
|
|
||||||
|
|
||||||
teardown:
|
teardown:
|
||||||
await queue.stop()
|
await queue.stop()
|
||||||
|
|
||||||
|
@ -79,7 +77,7 @@ suite "Slot queue workers":
|
||||||
discard SlotQueue.new(maxSize = 1, maxWorkers = 2)
|
discard SlotQueue.new(maxSize = 1, maxWorkers = 2)
|
||||||
|
|
||||||
test "does not surpass max workers":
|
test "does not surpass max workers":
|
||||||
startQueue()
|
queue.start()
|
||||||
let item1 = SlotQueueItem.example
|
let item1 = SlotQueueItem.example
|
||||||
let item2 = SlotQueueItem.example
|
let item2 = SlotQueueItem.example
|
||||||
let item3 = SlotQueueItem.example
|
let item3 = SlotQueueItem.example
|
||||||
|
@ -97,7 +95,7 @@ suite "Slot queue workers":
|
||||||
|
|
||||||
queue.onProcessSlot = processSlot
|
queue.onProcessSlot = processSlot
|
||||||
|
|
||||||
startQueue()
|
queue.start()
|
||||||
let item1 = SlotQueueItem.example
|
let item1 = SlotQueueItem.example
|
||||||
let item2 = SlotQueueItem.example
|
let item2 = SlotQueueItem.example
|
||||||
let item3 = SlotQueueItem.example
|
let item3 = SlotQueueItem.example
|
||||||
|
@ -122,7 +120,7 @@ suite "Slot queue":
|
||||||
onProcessSlotCalled = true
|
onProcessSlotCalled = true
|
||||||
onProcessSlotCalledWith.add (item.requestId, item.slotIndex)
|
onProcessSlotCalledWith.add (item.requestId, item.slotIndex)
|
||||||
done.complete()
|
done.complete()
|
||||||
asyncSpawn queue.start()
|
queue.start()
|
||||||
|
|
||||||
setup:
|
setup:
|
||||||
onProcessSlotCalled = false
|
onProcessSlotCalled = false
|
||||||
|
|
Loading…
Reference in New Issue