Description
build_snapshot() limits active skill scans with a semaphore, but the full set of per-skill operations is still admitted to asyncio.gather() at once.
This bounds the number of scans executing concurrently, but does not bound the number of pending asyncio tasks created for the snapshot operation.
I reproduced this behavior with 512 local skill identifiers and an active scan limit of 8.
Observed behavior:
Input skills: 512
Configured active scan limit: 8
Peak active scans: 8
Pending child tasks before release: 512
External service contacted: No
The active I/O concurrency limit therefore works as intended, but the number of pending tasks still scales with the total number of skills. For large registries, this can introduce unnecessary task allocation and event-loop overhead even when scan concurrency is configured conservatively.
Affected Version
Confirmed on:
malwar==0.4.0
src/malwar/monitor/snapshot.py:126-175
build_snapshot()
PoC runtime:
Python 3.13.14
Other versions have not been tested.
Reproduction
The attached PoC loads the released build_snapshot() implementation and supplies 512 local skill identifiers with the active scan limit set to 8.
The scan operation is replaced with a controlled local implementation that waits on an event, allowing the number of active scans and already-created child tasks to be measured before completion.
Observed result:
input skills: 512
configured active scan limit: 8
peak active scans: 8
pending child tasks before release: 512
input-proportional pending task creation reproduced: yes
No registry or model service is contacted during reproduction.
Attachment
run.py
Description
build_snapshot() limits active skill scans with a semaphore, but the full set of per-skill operations is still admitted to asyncio.gather() at once.
This bounds the number of scans executing concurrently, but does not bound the number of pending asyncio tasks created for the snapshot operation.
I reproduced this behavior with 512 local skill identifiers and an active scan limit of 8.
Observed behavior:
Input skills: 512
Configured active scan limit: 8
Peak active scans: 8
Pending child tasks before release: 512
External service contacted: No
The active I/O concurrency limit therefore works as intended, but the number of pending tasks still scales with the total number of skills. For large registries, this can introduce unnecessary task allocation and event-loop overhead even when scan concurrency is configured conservatively.
Affected Version
Confirmed on:
malwar==0.4.0
src/malwar/monitor/snapshot.py:126-175
build_snapshot()
PoC runtime:
Python 3.13.14
Other versions have not been tested.
Reproduction
The attached PoC loads the released build_snapshot() implementation and supplies 512 local skill identifiers with the active scan limit set to 8.
The scan operation is replaced with a controlled local implementation that waits on an event, allowing the number of active scans and already-created child tasks to be measured before completion.
Observed result:
input skills: 512
configured active scan limit: 8
peak active scans: 8
pending child tasks before release: 512
input-proportional pending task creation reproduced: yes
No registry or model service is contacted during reproduction.
Attachment
run.py