The NSQ protocol is simple so building clients should be trivial in any language. We provide official Go and Python client libraries.
An nsqd
process listens on a configurable TCP port that accepts client connections.
After connecting, a client must send a 4-byte "magic" identifier indicating what version of the protocol they will be communicating (upgrades made easy).
For nsqd
, there is currently only one protocol:
V2
(4-byte[ ][ ][V][2]
) - a push based streaming protocol for consuming (and request/response for publishing)
- Unless stated otherwise, all binary sizes/integers on the wire are network byte order (ie. big endian)
- Valid topic and channel names are characters
[.a-zA-Z0-9_-]
and1 < length < 32
After authenticating, the client can optionally send an IDENTIFY
command to provide custom
metadata (like, for example, more descriptive identifiers). In order to begin consuming messages, a
client must SUB
to a channel.
Upon subscribing the client is placed in a RDY
state of 0. This means that no messages
will be sent to the client. When a client is ready to receive messages it should send a command that
updates its RDY
state to some # it is prepared to handle, say 100. Without any additional
commands, 100 messages will be pushed to the client as they are available (each time decrementing
the server-side RDY
count for that client).
The V2 protocol also features client heartbeats. Every 30 seconds, nsqd
will send a
_heartbeat_
response and expect a command in return. If the client is idle, send NOP
. After 60
seconds, nsqd
will timeout and forcefully close a client connection that it has not heard from.
Commands are line oriented and structured as follows:
-
IDENTIFY
- update client metadata on the serverIDENTIFY\n [ 4-byte size in bytes ][ N-byte JSON data ]
NOTE: this command takes a size prefixed JSON body, relevant fields:
<short_id> - an identifier used as a short-form descriptor (ie. short hostname) <long_id> - an identifier used as a long-form descriptor (ie. fully-qualified hostname)
Success Response:
OK
Error Responses:
E_INVALID E_BAD_BODY
-
SUB
- subscribe to a specified topic/channelSUB <topic_name> <channel_name>\n <topic_name> - a valid string <channel_name> - a valid string (optionally having #ephemeral suffix)
Success response:
OK
Error Responses:
E_INVALID E_BAD_TOPIC E_BAD_CHANNEL
-
PUB
- publish a message to a specified topic:PUB <topic_name>\n [ 4-byte size in bytes ][ N-byte binary data ] <topic_name> - a valid string
Success Response:
OK
Error Responses:
E_INVALID E_BAD_TOPIC E_BAD_MESSAGE E_PUB_FAILED
-
MPUB
- publish multiple messages to a specified topic:NOTE: available in 0.2.16+
MPUB <topic_name>\n [ 4-byte body size ] [ 4-byte num messages ] [ 4-byte message #1 size ][ N-byte binary data ] ... (repeated <num_messages> times) <topic_name> - a valid string
Success Response:
OK
Error Responses:
E_INVALID E_BAD_TOPIC E_BAD_BODY E_BAD_MESSAGE E_MPUB_FAILED
-
RDY
- updateRDY
state (indicate you are ready to receive messages)RDY <count>\n <count> - a string representation of integer N where 0 < N < 2500
NOTE: there is no success response
Error Responses:
E_INVALID
-
FIN
- finish a message (indicate successful processing)FIN <message_id>\n <message_id> - message id as 16-byte hex string
NOTE: there is no success response
Error Responses:
E_INVALID E_FIN_FAILED
-
REQ
- re-queue a message (indicate failure to procees)REQ <message_id> <timeout>\n <message_id> - message id as 16-byte hex string <timeout> - a string representation of integer N where N < configured max timeout 0 is a special case that will not defer re-queueing
NOTE: there is no success response
Error Responses:
E_INVALID E_REQ_FAILED
-
TOUCH
- reset the timeout for an in-flight messageNOTE: available in 0.2.17+
TOUCH <message_id>\n <message_id> - the hex id of the message
NOTE: there is no success response
Error Responses:
E_INVALID E_TOUCH_FAILED
-
CLS
- cleanly close your connection (no more messages are sent)CLS\n
Success Responses:
CLOSE_WAIT
Error Responses:
E_INVALID
-
NOP
- no-opNOP\n
NOTE: there is no response
Data is streamed asynchronously to the client and framed in order to support the various reply bodies, ie:
[x][x][x][x][x][x][x][x][x][x][x][x]...
| (int32) || (int32) || (binary)
| 4-byte || 4-byte || N-byte
------------------------------------...
size frame ID data
A client should expect one of the following frame identifiers:
FrameTypeResponse int32 = 0
FrameTypeError int32 = 1
FrameTypeMessage int32 = 2
And finally, the message format:
[x][x][x][x][x][x][x][x][x][x][x][x][x][x][x][x][x][x][x][x][x][x][x][x][x][x][x][x][x][x]...
| (int64) || || (hex) || (binary)
| 8-byte || || 16-byte || N-byte
------------------------------------------------------------------------------------------...
nanosecond timestamp ^^ message ID message body
(uint16)
2-byte
attempts