AceCommQueue-1.0 - Transparent Send-Queue for AceComm-3.0
Are your addon's large AceComm messages arriving garbled with CRC errors? Does your guild communication addon silently drop or corrupt multi-chunk messages under load? AceCommQueue-1.0 is the solution.
AceCommQueue-1.0 is a lightweight, transparent queuing library that sits between your addon and AceComm-3.0, ensuring that only one message per channel is ever in-flight through ChatThrottleLib at a time — eliminating the chunk-interleaving bug that causes CRC failures on receivers.
The Problem
AceComm-3.0 splits large messages into FIRST/NEXT/LAST chunks and hands them all to ChatThrottleLib (CTL) at once. CTL maintains separate priority rings — ALERT, NORMAL, BULK — and drains ALERT before NORMAL before BULK.
If a second message is submitted on the same prefix immediately after a large first message, and the two use different CTL priorities, CTL can drain the second message's chunks ahead of remaining chunks from the first message. The receiver's AceComm spool is keyed on prefix + sender. When a new FIRST frame arrives mid-stream, the partial spool is overwritten — the assembled payload is garbage and the CRC check fails.
BULK message: FIRST ─── NEXT ─── NEXT ─── LAST
NORMAL message: FIRST ─ LAST
↑
receiver spool corrupted here
This bug is silent. No error is printed. The message simply never arrives. It hits any addon that sends multiple large messages in rapid succession using different CTL priorities.
The Solution
AceCommQueue-1.0 maintains an app-level queue per (prefix, distribution, target). Only one message is ever active in CTL at a time for that combination. The next queued message is not submitted until CTL's callback confirms the previous message's final chunk was handed off.
Between messages, higher-priority items drain first (ALERT > NORMAL > BULK), so an urgent message pushed onto the queue still goes out before pending lower-priority traffic — matching CTL's own intent.
Core Features
Fully Transparent Integration
- Zero Call-Site Changes: Embed once in
OnInitialize— all existingself:SendCommMessage(...)calls are automatically queued - Wrapper-Safe: Captures whatever
SendCommMessageis present at embed time — compatible with your existing wrappers - LibStub-Versioned: Standard LibStub upgrade semantics — multiple addons can embed the library without conflicts
- Queue State Preserved: Internal queues survive LibStub upgrades across repeated
/reloadcycles
Priority-Aware Draining
- ALERT drains before NORMAL before BULK — mirrors CTL's own priority ordering
- Urgent messages (ALERT) are never held behind lower-priority backlog
- Per-channel queues: separate queues per
(prefix, distribution, target)so unrelated channels never block each other
Suppression Compatible
- Works with send-suppression wrappers (e.g. in-raid guards) — suppressing wrappers just call the callback with
(arg, 0, 0, nil)to unblock the queue cleanly - Never stalls: the
0 >= 0condition satisfies last-chunk detection regardless of real send
Predictable Callbacks
- Every message you hand to the queue ends in exactly one callback — whether it was sent, suppressed by one of your wrappers, rejected for a bad argument, or failed outright
- So a send chained on the previous message's callback can never be stranded by one bad message
- A send that raises is still reported to the error handler, exactly as it would be without the queue in the way — the queue keeps running, but nothing is swallowed
Debug & Diagnostics
- Optional runtime debug output via
AceCommQueue:SetDebug(true) - Optional slash command registration:
ACQ:RegisterSlashCommand("/acq")— pick any command name you like - Slash command lets you toggle debug output and inspect live queue state without a reload
How It Works
Integration (Three Steps)
- Load the library in your
.tocbefore your own files:
Libs\LibStub\LibStub.lua
Libs\AceCommQueue-1.0\AceCommQueue-1.0.lua - Embed after AceComm in
OnInitialize:
AceComm must be embedded first, then any custom wrappers, then AceCommQueue last so it wraps the complete chain. - Done. Use
self:SendCommMessage(...)as normal — queueing is fully transparent.
Suppression Wrappers
If your addon has a wrapper that sometimes suppresses sends (e.g. an in-raid guard), install it before calling ACQ:Embed(self), and have it call callbackFn(callbackArg, 0, 0, nil) when suppressing. This satisfies last-chunk detection and unblocks the queue so it never stalls permanently.
Why Use AceCommQueue-1.0?
Correctness
- Eliminates the silent CRC-corruption bug that affects any addon sending large multi-chunk messages in rapid succession
- No lost messages, no garbage payloads, no confusing intermittent failures under guild channel load
- Backlogs of any size drain safely — a burst of tens of thousands of queued messages is delivered in full, in order
- Verified by an offline test suite that runs the real Ace3 and ChatThrottleLib code and reproduces the corruption end to end, so the fix is demonstrated rather than asserted
Zero Overhead
- Single Lua file, no external dependencies beyond LibStub and AceComm-3.0
- No polling, no frame update hooks — purely callback-driven
- Queue drain happens in the same CTL callback that already fires per chunk
Drop-In
- No refactoring of call sites required
- Compatible with every current WoW client — Classic Era, Anniversary realms, Burning Crusade, Wrath, Cataclysm, Mists, and Retail
- Ships as a standalone addon or embedded in your own Libs folder
Slash Commands
Register with LibStub("AceCommQueue-1.0"):RegisterSlashCommand("/acq"). Available commands:
- /acq on — Enable debug output
- /acq off — Disable debug output
- /acq status — Print current queue state for all active channels
- /acq unstick — Get a blocked channel moving again immediately, without waiting for the automatic recovery. Anything that was stuck is re-sent. Channels the game is still working through are left alone
- /acq — Toggle debug output
Requirements
- LibStub
- AceComm-3.0 (part of Ace3)
Recent Updates
v1.0.6 (Latest Release)
- Fixed: a perfectly healthy message could be reported as a fault in your addon. When the game rate-limits a whisper, it keeps retrying that message several times a second and says nothing at all while it does — which looked exactly like a message that had been lost. The library reported it as a bug in the sending addon and named a cause it had no way to check, sending authors to search codebases that were not at fault. It now asks the game's own send queue first, and stays quiet for as long as the message is genuinely still on its way. Whisper rate-limiting on a busy realm triggered the old check routinely
- Fixed: that same check assumed every addon sends messages the same way. It looked for the message in one specific place — the place the most common comms library happens to file it. An addon that organises its outgoing messages differently would have had a perfectly healthy message reported as lost and then sent a second time. The check now looks everywhere the message could be and identifies it by its own destination details, so it no longer depends on how the sending addon is built. This library is published for anyone to use, so that assumption was not safe to ship
- A blocked channel now recovers itself instead of staying blocked. Previously a channel whose message never reported back was stuck for the rest of the session, with everything behind it waiting forever. Now, once the library has confirmed the message really is gone, it clears the channel and re-sends the message — keeping its place at the front of the queue — so a lost notification costs a delay rather than a message
- Added /acq unstick and a matching
Unstickcall, for getting a channel moving right now instead of waiting out the timer. It applies the same safety check, so it will never cut in front of a message the game is still sending - The wait before a channel is considered blocked is now five minutes rather than one. Reporting late costs nothing; reporting wrongly costs someone an afternoon
- Repeat problems on the same channel are now counted rather than repeated. The first one is reported normally; the running total appears in /acq status, so a persistent fault stays visible without burying the chat frame
- Your send callback can now report a further outcome — the message's fate is unknown and its retries are used up — so an addon tracking delivery can tell it apart from one it deliberately chose not to send
v1.0.5
- Fixed: a message could be reported to your addon as delivered when the client had actually refused part of it. If one piece of a large multi-part message was rejected, the remaining pieces still went out and your addon was told the send succeeded — while the receiving end reassembled a corrupted payload. The delivery result now covers the whole message, so a refused piece means you are told it failed
- Added automatic retry: a send the client refuses is retried three times with an increasing delay before being reported as failed. The channel keeps its place in the queue while it waits, so message order is never disturbed by a retry. Tune or disable it with
SetRetryPolicy - A refused message sent without a callback is now reported through the standard error handler, so it can no longer disappear without a trace
- Your send callback now receives a fifth value naming the outcome — delivered, refused, suppressed by your own code, rejected, or errored — so an addon counting failures can tell a message it deliberately chose not to send from one that was genuinely lost. Existing callbacks are unaffected
- Added stall detection: if a send's completion callback never arrives, that channel used to block silently for the rest of the session. After a minute of no progress it is now reported, naming the channel and how many messages are waiting behind it. Nothing is dropped or re-sent — the queue is left exactly as it was, and recovers on its own if the callback turns up
- New documentation section spelling out the delivery contract: what the callback's fourth argument means, and the two traps that catch otherwise-careful code — the result describes the whole message rather than the last piece, and it is a true/false value rather than one of the game's send-result codes
v1.0.4
- Fixed a crash when sending to a numbered channel — the send died on the way into the queue instead of going out
- Fixed silent message loss when a very large backlog drained all at once: past roughly twenty thousand queued messages, a few were dropped with no error at all. Backlogs of any size now drain in full, in order
- A message the queue refuses (bad prefix, missing text, unknown priority) now reports back to your callback instead of ending in silence, so a send chained on the previous message's callback is never stranded
- A send that fails is now reported to the error handler as well, rather than only appearing with debug output turned on
- Added an offline test suite that runs the real Ace3 and ChatThrottleLib code outside the game and reproduces the message corruption this library prevents — the three fixes above were found by it. Development-only; it is not part of the download
v1.0.3
- Updated for the current Classic Era client so the library is no longer flagged out of date; every other supported version (Anniversary realms, Burning Crusade, Wrath, Cataclysm, Mists, and Retail) is unchanged
- Fixed the packaging rules so the documentation folder and the development-only scripts are correctly left out of the released download — the published zip is now just the library file, the TOC, and the license
- Internal library revision bumped so this copy takes precedence over an older embedded copy when several addons ship the library side by side
- No behavioural change — queueing, priority ordering, and the embed contract are identical to v1.0.2
v1.0.2
- Ace3 is now declared as a proper required dependency for the standalone addon, so it is resolved automatically on install instead of a duplicate copy of LibStub being bundled into the download
- No change for authors who embed the library — you continue to supply your own LibStub and AceComm-3.0
v1.0.1
- Added a full changelog, published with each release
- Expanded the documentation with the background on why chunk interleaving corrupts messages, a step-by-step integration walkthrough, the suppression-wrapper contract, and the slash command reference
v1.0.0
- Initial public release — transparent per-
(prefix, distribution, target)send queue on top of AceComm-3.0; prevents ChatThrottleLib priority-bucket reordering from interleaving chunks across messages; queue drains via CTL callback on last chunk; priority ordering preserved (ALERT > NORMAL > BULK); fully transparent to existing call sites; includes optional/acqslash commands for debug output and live queue inspection
Bug Reports & Feature Requests
Found a bug or have a suggestion?
- CurseForge page: TBD
If you have any questions, comments or anything else, please feel free to reach out on Discord!
Credits
Developed by:
- Pimptasty - Author
Special Thanks:
- The Old Gods guild community for real-world testing
- Ace3 library maintainers for the excellent framework
- WoW Classic community for feedback and support
License
AceCommQueue-1.0 is open-source software. See LICENSE file for details.

