User manual
The Queue Expert is a managed message queue. Your code keeps a WebSocket open, and each message is sent to it the moment it arrives.
Quick start
The service is not open yet. The names below, such as QUEUE-ID, are examples. You will replace them with your own values.
In about five minutes, you will send a message from one terminal and receive it in another.
What you need
When you create a queue, you get a host name and three logins: one for a publisher, one for a subscriber, and one for an administrator.
You also need websocat, a small free program. It connects to a WebSocket from a terminal. Each line you type is sent as one message.
1. Start a subscriber
A subscriber receives messages. Open a terminal, and connect:
websocat wss://QUEUE-ID.q.CLUSTER.thequeueexpert.com/
Type this line, with your subscriber's name and password, and press Enter:
{"username":"SUBSCRIBER-NAME","password":"SUBSCRIBER-PASSWORD","role":"subscriber","queuetype":"distribute","capacity":1}
The queue replies:
{"status":"Success.","sessionid":"01a1c0a0-d4d9-7000-9721-b211a887145b"}
2. Start a publisher
A publisher sends messages. Open a second terminal, connect with the same websocat command, and log in:
{"username":"PUBLISHER-NAME","password":"PUBLISHER-PASSWORD","role":"publisher","queuetype":"distribute"}
{"status":"Success."}
3. Send a message
In the publisher's terminal, type:
{"body":"Hello"}
The queue replies with the message's id:
{"id":"01a1c09f-62da-7000-a30b-0817c9a42e3f","status":"Success."}
4. Receive it
The message appears at once in the subscriber's terminal:
{"id":"01a1c09f-62da-7000-a30b-0817c9a42e3f","type":1,"body":"Hello","recdat":1794233033}
5. Acknowledge it
Tell the queue that you have finished with the message. Use the id that you received:
{"id":"MESSAGE-ID","ack":1}
{"id":"01a1c09f-62da-7000-a30b-0817c9a42e3f","status":"Success."}
The queue removes the message. To finish, log the subscriber out. The queue replies, and then closes the connection:
{"logout":true}
{"status":"Logout Success."}
How the queue works
Two queue types
Every queue has two types at the same address. You choose one each time you log in.
distribute | copy | |
|---|---|---|
| Who gets a message | One subscriber | Every subscriber connected at that moment |
| Is it stored? | Yes, until it is acknowledged | No |
| Acknowledgements | Yes | No |
| Delay, durability, publisher key | Yes | No |
| Administrators | Yes | No |
The rest of this section is about the distribute type.
Three roles
- A publisher sends messages.
- A subscriber receives messages.
- An administrator watches and manages the queue.
A queue has one login for each role. Many connections can use the same login at the same time.
Who gets a message
Subscribers stand in a line, in the order they logged in. Each new message goes to the first subscriber in the line that has room. Messages are not spread evenly. Subscribers near the end of the line stay idle when they are not needed, so you can remove them.
A subscriber's capacity is the number of messages it can hold before it acknowledges them. Example: with a capacity of 3, a subscriber can hold 3 messages. The next one goes to the next subscriber in the line.
Acknowledge or reject
A subscriber ends its work on a message in one of two ways:
- An ack says "done". The queue removes the message.
- A nack says "I cannot handle this". The message moves to the dead letter queue, and it is not delivered again.
The dead letter queue (DLQ) keeps rejected messages until an administrator deletes them. An administrator can read them first.
Sessions
If a connection drops, a subscriber that has received a message can resume its session. It keeps the messages it held and gets its place in the line back. It must do this within the saved-session time limit. See Resume after a drop.
When a session ends without a resume, or a subscriber logs out, the messages it held go to the first subscriber with room. If no subscriber has room, they go to the back of the queue.
What delivery promises
- At least once. A message can arrive more than once, for example after a resume. Use its id to find duplicates.
- Order is not promised. Messages usually arrive in the order they were published, but a returned message goes to the back, and a delayed message waits.
- No expiry. A message stays until it is acknowledged, rejected or deleted.
Durability
Each message has a durability level. It says how safe the message is if the machine fails.
| Value | Name | What happens |
|---|---|---|
0 | None | Kept in memory only. It is the fastest, but the message is lost if the queue restarts. It cannot go to the dead letter queue. |
1 | Eventual (the default) | Written to the disk. A machine failure just after the write can lose it. |
2 | Immediate | Written to the disk and synced before the publisher gets its reply. |
Connect and log in
All three roles connect and log in the same way.
The address
wss://QUEUE-ID.q.CLUSTER.thequeueexpert.com/
- The queue speaks only WebSocket, over TLS 1.2 or newer, on port 443. Any other HTTP request gets a 400 reply.
- The host name always has an IPv6 address. It has an IPv4 address only if your queue has one.
- Requests and replies are JSON text, except where this manual says otherwise.
The login
The first message on a connection must be the login:
{"username":"PUBLISHER-NAME","password":"PUBLISHER-PASSWORD","role":"publisher","queuetype":"distribute"}
| Field | Value |
|---|---|
username | Your login's name, up to 128 bytes. |
password | Your login's password, up to 128 bytes. |
role | "publisher", "subscriber" or "admin". |
queuetype | "distribute" or "copy". |
context | Optional. See Matching replies. |
Each role can add its own fields. See Publishers and Subscribers.
- Send the login within 10 seconds of connecting.
- Wait for the login's reply before you send anything else. A message sent during the login ends the connection.
- After a failed login, the queue sends the reply and closes the connection.
- After a login, there is no idle time limit. The connection can stay open as long as you like.
Replies
Every reply has a status, which is "Success.", "Failure." or, for a logout, "Logout Success.". A failure also has a number and a text:
{"status":"Failure.","code":203,"reason":"Invalid delay."}
In your programs, use code. The numbers do not change. reason is for people, and its words can change. The Reference lists every code. Fields can come in any order.
Matching replies
Any request can have a context: a number, or a text of up to 256 bytes. The queue copies it into the reply, so you can tell which request a reply is for.
{"body":"hello","context":7}
{"context":7,"id":"01a1c09f-62da-7000-a30b-0817c9a42e3f","status":"Success."}
Choosing a client
Any WebSocket client works. The examples use websocat, the ws package for Node.js, and the websockets package for Python.
Do not put a password in a web page. Every visitor could read it.
Why not Node.js's built-in WebSocket? When the queue sends a last reply and closes the connection at once, the built-in client can lose that reply. It unpacks compressed messages in the background, and the connection can close first. A failed login then shows only close code 1006, with no reason, and a logout shows no reply. We saw this with Node.js 26. The ws package, Python's websockets package and websocat all receive the reply.
Publishers
Log in
{"username":"PUBLISHER-NAME","password":"PUBLISHER-PASSWORD","role":"publisher","queuetype":"distribute"}
{"status":"Success."}
Publish a message
{"body":"Order 1234 is ready","delay":60,"durability":2,"publisherkey":"order-1234"}
{"id":"01a1c09f-62df-7000-84ba-6bd164337f31","status":"Success."}
| Field | Value |
|---|---|
body | Required. The message, as a string. To send JSON as the message, put it in the string. |
type | 1 is text, and is the default. 2 is binary, and body must then be base64. |
delay | Seconds to wait before delivery, from 0 to 172800 (two days). The default is 0. |
durability | 0, 1 or 2. The default is 1. See Durability. |
publisherkey | Your own label for the message, which the subscriber receives. 1 to 128 of these characters: letters, digits, and - _ . : / + =. |
context | See Matching replies. |
The biggest WebSocket message is 65536 bytes by default, and an administrator can change this. The limit includes the JSON around the body, and base64 makes a binary body about a third bigger. A bigger message closes the connection with code 1009.
Binary messages
{"body":"aGVsbG8=","type":2}
You can also send a binary WebSocket frame. The queue encodes it as base64, and the subscriber receives it with "type":2. Delay, durability and a publisher key cannot be used with this form.
Plain text
A text frame that is not a JSON object is itself the message. The frame Hello publishes the text Hello. Delay, durability and a publisher key cannot be used with this form.
A JSON object must have a body. Without one, it is refused with code 206, so a typing mistake does not become a message.
Publish in the login
A short job can log in and publish with one request. Put the message's fields in the login:
{"username":"PUBLISHER-NAME","password":"PUBLISHER-PASSWORD","role":"publisher","queuetype":"distribute","body":"in the login"}
The reply is the publish's reply. You can then close the connection.
{"id":"01a1c09f-63ed-7000-a185-6465c0a6482f","status":"Success."}
When the queue is full
Code 210 means the queue holds as many messages as it can. Code 211 means the messages use all the memory the queue has for them. Messages in the dead letter queue count too. Wait, and publish again, or ask an administrator to delete messages from the dead letter queue.
Copy queues
Log in with "queuetype":"copy". The reply says how many subscribers got the message:
{"status":"Success.","subscribers":1}
This reply has no message id. A copy queue refuses delay, durability and publisherkey.
A full program
Node.js. Install the package with npm install ws, and save the program as publisher.mjs.
import WebSocket from "ws";
const address = "wss://QUEUE-ID.q.CLUSTER.thequeueexpert.com/";
const login = {
username: "PUBLISHER-NAME",
password: "PUBLISHER-PASSWORD",
role: "publisher",
queuetype: "distribute",
};
const socket = new WebSocket(address);
let loggedIn = false;
socket.on("open", () => socket.send(JSON.stringify(login)));
socket.on("error", (error) => console.log("Connection error:", error.code || error.message));
socket.on("message", (data) => {
const reply = JSON.parse(data);
if (reply.status !== "Success.") {
console.log("Failed:", reply.code, reply.reason);
socket.close();
} else if (!loggedIn) {
loggedIn = true;
socket.send(JSON.stringify({ body: "Hello from Node.js" }));
} else {
console.log("Published. The message id is", reply.id);
socket.close();
}
});
Python. Install the package with pip install websockets.
import asyncio
import json
from websockets.asyncio.client import connect
from websockets.exceptions import WebSocketException
ADDRESS = "wss://QUEUE-ID.q.CLUSTER.thequeueexpert.com/"
LOGIN = {
"username": "PUBLISHER-NAME",
"password": "PUBLISHER-PASSWORD",
"role": "publisher",
"queuetype": "distribute",
}
async def main():
try:
async with connect(ADDRESS) as socket:
await socket.send(json.dumps(LOGIN))
reply = json.loads(await socket.recv())
if reply["status"] != "Success.":
print("Failed:", reply["code"], reply["reason"])
else:
await socket.send(json.dumps({"body": "Hello from Python"}))
reply = json.loads(await socket.recv())
print("Published. The message id is", reply["id"])
except (OSError, WebSocketException) as error:
print("Connection error:", error)
asyncio.run(main())
Subscribers
Log in
{"username":"SUBSCRIBER-NAME","password":"SUBSCRIBER-PASSWORD","role":"subscriber","queuetype":"distribute","capacity":10}
{"status":"Success.","sessionid":"01a1c09f-64be-7000-99d3-a74b8cef2465"}
capacity is required, from 1 to the max-subscriber-capacity setting, which is 1024 by default. Keep the sessionid: you need it to resume. Every login gives a new one.
What you receive
Three kinds of frame arrive on the connection. All are JSON text.
A message has a body:
{"id":"01a1c09f-62e2-7000-b616-7c246d151566","publisherkey":"order-1234","type":1,"body":"Order 1234 is ready","recdat":1794233033}
| Field | Value |
|---|---|
id | The message's id. Ids sort in time order. |
publisherkey | Only if the publisher gave one. |
type | 1 is text, 2 is binary. A binary body is base64. |
body | The message. |
recdat | When the queue received it, in seconds since 1970 (UTC). |
A reply to something you sent has a status.
A notice says that an administrator took away a message you hold. Stop working on it, and do not acknowledge it:
{"deleted":true,"id":"01a1c09f-62da-7000-a30b-0817c9a42e3f"}
{"movedtodlq":true,"id":"01a1c09f-62da-7000-a30b-0817c9a42e3f"}
Acknowledge or reject
To acknowledge, send "ack":1. To reject, which moves the message to the dead letter queue, send "ack":0.
{"id":"MESSAGE-ID","ack":1}
{"id":"MESSAGE-ID","ack":0}
{"id":"01a1c09f-62da-7000-a30b-0817c9a42e3f","status":"Success."}
Code 301 means you do not hold that message. A message with durability 0 cannot be rejected, because it is not on the disk. The queue refuses with code 305. Acknowledge it instead.
Change the capacity
{"capacity":2}
{"status":"Success."}
If the new capacity leaves room, messages that are waiting are sent at once.
Resume after a drop
Log in again with your last sessionid. You can leave out capacity to keep the one you had.
{"username":"SUBSCRIBER-NAME","password":"SUBSCRIBER-PASSWORD","role":"subscriber","queuetype":"distribute","sessionid":"SESSION-ID","replay":true}
{"status":"Success.","sessionid":"01a1c09f-9b9c-7000-9c23-6bf133d5b10e"}
With "replay":true, the queue sends again every message you hold. With "replay":false or no replay, it sends only the ones it never sent you.
The time limit is 10 seconds by default, and one hour on the Dev/test tier. An administrator can set it from 10 seconds to one day.
A session is saved when a connection drops if the subscriber holds a message, or has received one in the past. A resume fails with code 109, and the connection closes, in these cases:
- The queue still sees your old connection as open. This can happen just after a network failure.
- Another connection is resuming the same session at that moment.
- The time limit has passed.
- The subscriber logged out.
- The subscriber never received a message.
- The subscriber held no message when it dropped, and the queue already has
max-taskssaved sessions.
Because of the first two, try the resume again a few times, a few seconds apart. If it still fails, connect and log in with a capacity and no sessionid. You go to the end of the line.
Log out
{"logout":true}
{"status":"Logout Success."}
The queue replies, and then closes the connection with code 1000. The messages you still hold go to other subscribers.
Wait for the reply to every ack before you log out. If you do not, the ack still counts, but its reply can be lost, and the message can be delivered again.
Copy queues
Log in with "queuetype":"copy" and no capacity. You receive each message that is published while you are connected. You send nothing after the login, and there is no ack. A JSON frame is refused with code 306. A frame that is not JSON gets code 100, and the connection closes.
A full program
Each program handles every message and acknowledges it. A real program should also connect again if the connection drops, and resume.
Node.js. Save it as subscriber.mjs.
import WebSocket from "ws";
const address = "wss://QUEUE-ID.q.CLUSTER.thequeueexpert.com/";
const login = {
username: "SUBSCRIBER-NAME",
password: "SUBSCRIBER-PASSWORD",
role: "subscriber",
queuetype: "distribute",
capacity: 10,
};
const socket = new WebSocket(address);
socket.on("open", () => socket.send(JSON.stringify(login)));
socket.on("error", (error) => console.log("Connection error:", error.code || error.message));
socket.on("message", (data) => {
const frame = JSON.parse(data);
if (frame.body !== undefined) {
console.log("Received:", frame.body);
socket.send(JSON.stringify({ id: frame.id, ack: 1 }));
} else if (frame.status === "Failure.") {
console.log("Failed:", frame.code, frame.reason);
}
});
Python.
import asyncio
import json
from websockets.asyncio.client import connect
from websockets.exceptions import WebSocketException
ADDRESS = "wss://QUEUE-ID.q.CLUSTER.thequeueexpert.com/"
LOGIN = {
"username": "SUBSCRIBER-NAME",
"password": "SUBSCRIBER-PASSWORD",
"role": "subscriber",
"queuetype": "distribute",
"capacity": 10,
}
async def main():
try:
async with connect(ADDRESS) as socket:
await socket.send(json.dumps(LOGIN))
async for text in socket:
frame = json.loads(text)
if "body" in frame:
print("Received:", frame["body"], flush=True)
await socket.send(json.dumps({"id": frame["id"], "ack": 1}))
elif frame.get("status") == "Failure.":
print("Failed:", frame["code"], frame["reason"], flush=True)
except (OSError, WebSocketException) as error:
print("Connection error:", error, flush=True)
asyncio.run(main())
Administrators
Log in with the role "admin" and the queue type "distribute". Then send commands. Each command has a cmd field, and can have a context.
{"username":"ADMIN-NAME","password":"ADMIN-PASSWORD","role":"admin","queuetype":"distribute"}
{"status":"Success."}
Watch the queue
getlivestats gives the counters right now:
{"cmd":"getlivestats"}
{"status":"Success.","csv":"10,0,1,0,1,3,0,1,9"}
The columns of csv, in order: messages, publishers, subscribers, saved subscribers, administrators, unacknowledged, dead letter, delayed, durable. "Messages" counts every message the queue holds: waiting, held, delayed, and in the dead letter queue.
Add subscribe to get the counters pushed to you every so many seconds, from 30 to 900. Each push has "cmd":"getlivestats" and a csv. A value of 0 stops the pushes. Pushes stop when the connection closes.
{"cmd":"getlivestats","subscribe":30}
getstats gives the history of one day, in UTC. With "average":false you get every record of the day, and with true you get one line of averages. Each line is the time in seconds since 1970, then the same nine columns.
{"cmd":"getstats","average":false,"year":2026,"month":11,"day":9}
getusage gives the usage of one day, in UTC. With "totals":false you get every record of the day, and with true you get one line for the whole day.
{"cmd":"getusage","totals":true,"year":2026,"month":11,"day":9}
{"status":"Success.","csv":"1794182400,0,0,0,0,4096,m4.xlarge,us-east-1,1\n"}
The columns: time, network bytes sent, network bytes received, storage bytes written, storage bytes read, storage bytes held, instance type, region, and 1 if the queue has an IPv4 address. In the day's totals, the bytes are added up and the storage is an average.
Manage messages
getmsgs lists the messages in the queue: waiting, held and delayed. Give exactly one of after or before, with a message id. An empty string means the start (for after) or the end (for before). count is from 1 to 1600.
{"cmd":"getmsgs","after":"","count":20}
{"status":"Success.","csv":"01a1c09f-62da-7000-a30b-0817c9a42e3f,89,0,1,1,1794233033\n"}
The columns: id, length in bytes, delay, durability, type, time received.
getmsg shows one message, with its content. It does not change the message.
{"cmd":"getmsg","id":"MESSAGE-ID"}
{"status":"Success.","id":"01a1c09f-62da-7000-a30b-0817c9a42e3f","msg":{"id":"01a1c09f-62da-7000-a30b-0817c9a42e3f","type":1,"body":"hello","recdat":1794233033},"len":89,"delay":0,"durability":1}
addmsg publishes a message. It takes the same fields as a publish, and the reply has the new id.
{"cmd":"addmsg","body":"Added by an administrator"}
{"id":"01a1c09f-827a-7000-b75c-99301d00e385","status":"Success."}
delmsg deletes a message that is waiting, held or delayed. movetodlq moves one to the dead letter queue. A message with durability 0 cannot be moved, and is refused with code 413. If a subscriber holds the message, it gets a notice.
{"cmd":"delmsg","id":"MESSAGE-ID"}
{"cmd":"movetodlq","id":"MESSAGE-ID"}
The dead letter queue
getdlqmsgs lists it, and works like getmsgs. getdlqmsg shows one message, and works like getmsg. deldlqmsg deletes one.
{"cmd":"getdlqmsgs","after":"","count":20}
{"cmd":"getdlqmsg","id":"MESSAGE-ID"}
{"cmd":"deldlqmsg","id":"MESSAGE-ID"}
If a message's file is damaged on the disk, the queue moves it here. Its msg is then {"id":"..","damaged":true,"file":".."}, where file is the whole file in base64. file is left out when the file is too big.
Put a message back in the queue
There is no single command for this. Use three:
getdlqmsgto read the message.addmsgto publish it again, with the samebodyandtype. It gets a new id.deldlqmsgto remove the old copy. Do this last. If your program stops before this step, the message is in both places, and nothing is lost.
Settings
getcfg shows every setting as a name, with "r" (read only) or "w" (you can change it), and its value.
{"cmd":"getcfg"}
setcfg changes one or more settings. The change takes effect at once, and is kept after a restart. The Reference lists the settings.
{"cmd":"setcfg","saved-session-timeout-secs":60}
{"status":"Success."}
A full program
Each program prints the queue's live counters.
Node.js. Save it as admin.mjs.
import WebSocket from "ws";
const address = "wss://QUEUE-ID.q.CLUSTER.thequeueexpert.com/";
const login = {
username: "ADMIN-NAME",
password: "ADMIN-PASSWORD",
role: "admin",
queuetype: "distribute",
};
const socket = new WebSocket(address);
let loggedIn = false;
socket.on("open", () => socket.send(JSON.stringify(login)));
socket.on("error", (error) => console.log("Connection error:", error.code || error.message));
socket.on("message", (data) => {
const reply = JSON.parse(data);
if (reply.status !== "Success.") {
console.log("Failed:", reply.code, reply.reason);
socket.close();
} else if (!loggedIn) {
loggedIn = true;
socket.send(JSON.stringify({ cmd: "getlivestats" }));
} else {
console.log("Messages in the queue:", reply.csv.split(",")[0]);
socket.close();
}
});
Python.
import asyncio
import json
from websockets.asyncio.client import connect
from websockets.exceptions import WebSocketException
ADDRESS = "wss://QUEUE-ID.q.CLUSTER.thequeueexpert.com/"
LOGIN = {
"username": "ADMIN-NAME",
"password": "ADMIN-PASSWORD",
"role": "admin",
"queuetype": "distribute",
}
async def main():
try:
async with connect(ADDRESS) as socket:
await socket.send(json.dumps(LOGIN))
reply = json.loads(await socket.recv())
if reply["status"] != "Success.":
print("Failed:", reply["code"], reply["reason"])
else:
await socket.send(json.dumps({"cmd": "getlivestats"}))
reply = json.loads(await socket.recv())
print("Messages in the queue:", reply["csv"].split(",")[0])
except (OSError, WebSocketException) as error:
print("Connection error:", error)
asyncio.run(main())
Reference
Limits and settings
An administrator can change these with setcfg.
| Setting | Default | Range | What it is |
|---|---|---|---|
max-ws-msg-len | 65536 | 1024 to 1048576 | The biggest WebSocket message, in bytes, including the JSON around the body. |
max-subscriber-capacity | 1024 | 1 to 1024 | The biggest capacity a subscriber can ask for. |
saved-session-timeout-secs | 10 | 10 to 86400 | How long a dropped session can be resumed. One hour on Dev/test. |
no-reply-timeout-secs | 10 | 1 to 300 | How long a new connection has to log in. |
stats-frequency-secs | 300 | 300 to 3600 | How often a stats record is made. One hour on Dev/test. |
stats-retention-period-yrs | 5 | 1 to 10 | How long stats are kept. One year on Dev/test. |
usage-frequency-secs | 1800 | 1800 to 86400 | How often a usage record is made. |
usage-retention-period-yrs | 5 | 1 to 20 | How long usage is kept. |
These can only be read, with getcfg:
| Setting | What it is |
|---|---|
max-tasks | The most connections at one time. 100 on Dev/test. On other tiers, it depends on the machine's memory. |
max-messages | The most messages the queue can hold, counting the dead letter queue. It depends on the machine's memory, and is never more than 1,000,000. |
max-messages-memory | The memory the queue can use for messages, in bytes. |
messages-memory-used | The memory messages use now, in bytes. |
max-write-queue-bytes | How many bytes can wait to be sent to one connection. The default is 4 MiB, and 1 MiB on Dev/test. A client that reads too slowly and goes over this is disconnected. |
message-timeout-secs | A message sent in several WebSocket frames must arrive whole within this time. The default is 30 seconds. |
log-level | How much the queue writes to its own log. |
Why a connection closed
| Close code | Meaning |
|---|---|
| 1000 | You logged out. |
| 1002 | The client broke the WebSocket protocol. |
| 1007 | A text frame was not valid UTF-8. |
| 1008 | A message did not arrive whole within message-timeout-secs. |
| 1009 | A message was bigger than max-ws-msg-len. |
| 1011 | A compressed message could not be unpacked. |
After a failed login, or text that is not JSON from a subscriber or an administrator, the queue sends a reply and closes the connection with no close code. Your client may report this as 1006. When every connection slot is in use, a new connection is closed with no message.
Failure codes
The 500s are the queue's own problems, and trying again later is usually sensible. Codes 506 and 507 are different: the change was made, but it may not survive a machine failure. Do not send it again. If you do, a message is published twice.
Connecting and logging in
| Code | Reason |
|---|---|
| 100 | Invalid json. |
| 101 | Invalid context. |
| 102 | Login message must be of type text, not binary. |
| 103 | Invalid username. |
| 104 | Invalid password. |
| 105 | Invalid role. |
| 106 | Invalid queue type. |
| 107 | Authentication failed. Invalid combination of username, password and role. |
| 108 | Admin login is only allowed for distribute type queue. |
| 109 | Invalid session id. |
| 110 | Invalid "replay". |
Publishing
| Code | Reason |
|---|---|
| 200 | Invalid message body. |
| 201 | Invalid message type. |
| 202 | Body must be base64 encoded for binary messages. |
| 203 | Invalid delay. |
| 204 | Invalid durability. |
| 205 | Invalid publisher key. |
| 206 | Cannot publish: a JSON object must have a body field. To send JSON as the message, put it in body as a string. |
| 207 | Delay is only allowed for distribute type queue. |
| 208 | Durability is only allowed for distribute type queue. |
| 209 | Publisher key is only allowed for distribute type queue. |
| 210 | Max allowed message count exceeded. |
| 211 | Max allowed message memory exceeded. |
Subscribers
| Code | Reason |
|---|---|
| 300 | Invalid capacity. |
| 301 | Invalid message id. |
| 302 | Invalid ack. |
| 303 | Invalid logout. |
| 304 | Invalid message. Expecting ack or logout or capacity update. |
| 305 | Cannot nack: a message with durability 0 is not on the disk, so it cannot go to the dead letter queue. Ack it instead. |
| 306 | No incoming messages are allowed after successful login for copy queue subscribers. |
Administrators
| Code | Reason |
|---|---|
| 400 | Invalid command (cmd). |
| 401 | Invalid subscription period. Must be zero, or between 30 and 900 (inclusive). |
| 402 | A subscription is already active. Cancel it first by using value 0 for subscribe. |
| 403 | No active subscription to cancel. |
| 404 | Invalid year. |
| 405 | Invalid month. |
| 406 | Invalid day. |
| 407 | Invalid date, don't have data before (a time). |
| 408 | Invalid average (or totals), not specified. Or: must be boolean. |
| 409 | Exactly one of before/after must be specified. |
| 410 | Invalid before. |
| 411 | Invalid after. |
| 412 | Invalid message count. Or: Count must be a value between 1 and 1600 (both inclusive). |
| 413 | Cannot move: a message with durability 0 is not on the disk, so it cannot go to the dead letter queue. Use delmsg instead. |
| 414 | Invalid (setting). Must be between (its limits). |
| 415 | Read only parameter (setting) specified. |
| 416 | No valid parameter with write permission specified. |
The queue's own problems
| Code | Reason |
|---|---|
| 500 | Internal error. |
| 501 | Out of memory. |
| 502 | Database is down. |
| 503 | Database server did not respond in time. |
| 504 | Unknown failure. |
| 505 | Could not save the settings. Nothing has changed. |
| 506 | Settings changed, but the save may not survive a machine crash. |
| 507 | Sync to file failed. This operation has eventual durability. |
Coming from Amazon SQS
The main difference is that you do not poll. Your subscriber keeps a WebSocket open, and each message is sent to it the moment it arrives.
| Amazon SQS | The Queue Expert |
|---|---|
SendMessage | A publish on an open connection |
ReceiveMessage, long polling | None. Messages are pushed to you. |
DeleteMessage | An ack |
| Visibility timeout | None. A subscriber holds a message until it answers or goes away. |
MaxNumberOfMessages | capacity, which limits how many messages a subscriber holds |
| Delay of up to 15 minutes | delay of up to two days |
| Retention of up to 14 days | No expiry. A message stays until it is handled. |
| Dead-letter queue, after too many receives | Dead letter queue, after a nack. The queue does not count deliveries. |
| DLQ redrive | Three commands |
| Message attributes | Put them in body, or use publisherkey for one label |
| Batch requests | None. Send messages one at a time on the open connection. |
PurgeQueue | None. Delete messages one at a time with delmsg. |
| Amazon SNS fan-out | A copy queue |
| HTTPS API | WebSocket only |