sleep(0) wakes the processor only on timer ticks, causing a
1-tick delay. os.pullEvent() with no filter wakes the processor
on ANY event — including the modem_message that triggered the
capture — so items are processed in the same event cycle.
Added logging to capture and processor tasks:
- NET-CAP: logs each queued message with type and queue depth
- NET-PROC: logs each message being processed
- Both log on startup to confirm they're running
Two robustness improvements to the Network capture/processor split:
1. Processor wake-up: replaced os.queueEvent('network_queued') /
os.pullEvent('network_queued') with sleep(0) polling. Custom events
can be consumed by other coroutines (e.g. craftItem's unfiltered
os.pullEvent()) or swallowed by the OS event layer. Polling the
shared queue every tick is simpler and guaranteed reliable.
2. craftItem: removed ORDER_CHANNEL message buffering and re-queuing.
With the dedicated Network-capture task, ORDER_CHANNEL messages are
already safely captured into networkQueue. The old buffering caused
double-capture: capture task adds to queue, craftItem also buffers,
then re-queues via os.queueEvent -> capture captures again -> dup.
The commandId dedup caught these, but removing the source is cleaner.
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.
The additional_contexts approach required cc-platform-core to exist on
the Docker host at a relative path. This fails on servers where the
repo layout differs. Instead, use a multi-stage build: stage 1 clones
cc-platform-core from Gitea (depth 1), stage 2 copies server/ into the
app and rewrites the file: path. Fully self-contained — no host deps.
Use additional_contexts to copy platform server package into the Docker
build context. Rewrites the file: dependency path and removes the
lockfile so npm install can resolve the local package correctly.