fix: split Network-listener into capture/processor to prevent modem_message loss
CC:Tweaked's parallel.waitForAny drops events when a coroutine's filter doesn't match. The old Network-listener processed commands inline, causing it to yield with filter 'task_complete' during peripheral calls (pushItems, list, etc). Any modem_message arriving during that window was consumed by the scheduler and lost. Split into two coroutines: - Network-capture: only ever yields for 'modem_message', inserts into a shared networkQueue table, queues 'network_queued' event - Network-processor: drains the queue and runs all handler logic, safe to yield for peripheral calls without losing messages This fixes the ~80% message loss rate on dispense requests.
This commit is contained in:
@@ -383,6 +383,11 @@ local function main()
|
||||
-- Parallel tasks
|
||||
-----------------------------------------------
|
||||
|
||||
-- Shared queue: capture task writes here, processor task reads.
|
||||
-- This ensures modem_message events are never lost while the
|
||||
-- processor yields for peripheral calls (pushItems, list, etc).
|
||||
local networkQueue = {}
|
||||
|
||||
parallel.waitForAny(
|
||||
-- Task 1: Background inventory scanner
|
||||
resilient("Scanner", function()
|
||||
@@ -630,14 +635,36 @@ local function main()
|
||||
end
|
||||
end),
|
||||
|
||||
-- Task 13: Network order/command listener
|
||||
resilient("Network-listener", function()
|
||||
-- Task 13a: Network message capture (fast — never yields to peripheral calls)
|
||||
-- This coroutine's filter is ALWAYS "modem_message", so it can never
|
||||
-- miss events while other tasks yield for "task_complete" etc.
|
||||
resilient("Network-capture", function()
|
||||
if not ctx.networkModem then
|
||||
while true do sleep(3600) end
|
||||
end
|
||||
while true do
|
||||
local event, side, channel, replyChannel, message, distance = os.pullEvent("modem_message")
|
||||
if channel == cfg.ORDER_CHANNEL and type(message) == "table" then
|
||||
table.insert(networkQueue, { replyChannel = replyChannel, message = message })
|
||||
os.queueEvent("network_queued")
|
||||
end
|
||||
end
|
||||
end),
|
||||
|
||||
-- Task 13b: Network message processor (drains queue — safe to yield)
|
||||
resilient("Network-processor", function()
|
||||
if not ctx.networkModem then
|
||||
while true do sleep(3600) end
|
||||
end
|
||||
while true do
|
||||
if #networkQueue == 0 then
|
||||
os.pullEvent("network_queued")
|
||||
end
|
||||
while #networkQueue > 0 do
|
||||
local entry = table.remove(networkQueue, 1)
|
||||
local message = entry.message
|
||||
local replyChannel = entry.replyChannel
|
||||
|
||||
if isCommandDuplicate(message.commandId) then
|
||||
log.debug("NET", "Duplicate command skipped: %s", tostring(message.commandId))
|
||||
else
|
||||
@@ -888,7 +915,7 @@ local function main()
|
||||
log.error("NET", "Handler error: %s", tostring(handlerErr))
|
||||
end
|
||||
end -- idempotency else
|
||||
end
|
||||
end -- queue loop
|
||||
end
|
||||
end)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user