Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 395 lines (276 sloc) 9.557 kB
afe7fd5 @tj rename to axon
authored
1 # Axon
5c2217f @tj Initial commit
authored
2
4777ca2 @tj Update Readme.md
authored
3 Axon is a message-oriented socket library for node.js heavily inspired by zeromq.
5c2217f @tj Initial commit
authored
4
00b5dcc @tj add some docs
authored
5 ## Installation
6
afe7fd5 @tj rename to axon
authored
7 $ npm install axon
00b5dcc @tj add some docs
authored
8
5c2217f @tj Initial commit
authored
9 ## Features
10
11 - message oriented
12 - automated reconnection
13 - light-weight wire protocol
14 - supports arbitrary binary message (msgpack, json, BLOBS, etc)
3613011 @tj docs
authored
15 - supports JSON messages out of the box
23b783e document new sockets
Garrett Johnson authored
16
17 ## Patterns
18
19 - push / pull
20 - pub / sub
21 - req / rep
779e21d @tj docs
authored
22 - pub-emitter / sub-emitter
5c2217f @tj Initial commit
authored
23
24 ## Push / Pull
25
0e7ade0 @tj tweak docs
authored
26 `PushSocket`s distribute messages round-robin:
5c2217f @tj Initial commit
authored
27
28 ```js
afe7fd5 @tj rename to axon
authored
29 var axon = require('axon')
30 , sock = axon.socket('push');
5c2217f @tj Initial commit
authored
31
32 sock.bind(3000);
33 console.log('push server started');
34
35 setInterval(function(){
36 sock.send('hello');
37 }, 150);
38 ```
39
0e7ade0 @tj tweak docs
authored
40 Receiver of `PushSocket` messages:
5c2217f @tj Initial commit
authored
41
42 ```js
afe7fd5 @tj rename to axon
authored
43 var axon = require('axon')
44 , sock = axon.socket('pull');
5c2217f @tj Initial commit
authored
45
b3cabbb @tj fix readme example
authored
46 sock.connect(3000);
5c2217f @tj Initial commit
authored
47
b3cabbb @tj fix readme example
authored
48 sock.on('message', function(msg){
49 console.log(msg.toString());
50 });
5c2217f @tj Initial commit
authored
51 ```
52
23b783e document new sockets
Garrett Johnson authored
53 Both `PushSocket`s and `PullSocket`s may `.bind()` or `.connect()`. In the
561889c @tj add more docs
authored
54 following configuration the push socket is bound and pull "workers" connect
55 to it to receive work:
7449cfb @tj add more docs for push/pull
authored
56
57 ![push bind](http://f.cl.ly/items/473u3m1a0k1i0J0I3s04/ss-push.png)
561889c @tj add more docs
authored
58
59 This configuration shows the inverse, where workers connect to a "sink"
60 to push results:
61
7449cfb @tj add more docs for push/pull
authored
62 ![pull bind](http://f.cl.ly/items/3Y0j2v153Q0l1r373i0H/ss-pull.png)
63
5c2217f @tj Initial commit
authored
64 ## Pub / Sub
65
23b783e document new sockets
Garrett Johnson authored
66 `PubSocket`s send messages to all subscribers without queueing. This is an
67 important difference when compared to a `PushSocket`, where the delivery of
68 messages will be queued during disconnects and sent again upon the next connection.
5c2217f @tj Initial commit
authored
69
70 ```js
afe7fd5 @tj rename to axon
authored
71 var axon = require('axon')
72 , sock = axon.socket('pub');
5c2217f @tj Initial commit
authored
73
74 sock.bind(3000);
75 console.log('pub server started');
76
77 setInterval(function(){
78 sock.send('hello');
79 }, 500);
80 ```
81
c5d571e @tj add some docs
authored
82 `SubSocket` simply receives any messages from a `PubSocket`:
5c2217f @tj Initial commit
authored
83
84 ```js
afe7fd5 @tj rename to axon
authored
85 var axon = require('axon')
86 , sock = axon.socket('sub');
5c2217f @tj Initial commit
authored
87
88 sock.connect(3000);
89
90 sock.on('message', function(msg){
91 console.log(msg.toString());
92 });
93 ```
94
c5d571e @tj add some docs
authored
95 `SubSocket`s may optionally `.subscribe()` to one or more "topics" (the first multipart value),
96 using string patterns or regular expressions:
97
98 ```js
99 var axon = require('axon')
100 , sock = axon.socket('sub');
101
102 sock.connect(3000);
853c449 @tj add more docs
authored
103 sock.subscribe('user:login');
104 sock.subscribe('upload:*:progress');
c5d571e @tj add some docs
authored
105
106 sock.on('message', function(topic, msg){
107
108 });
109 ```
110
6792e01 @tj add req/rep docs
authored
111 ## Req / Rep
112
113 `ReqSocket` is similar to a `PushSocket` in that it round-robins messages
114 to connected `RepSocket`s, however it differs in that this communication is
115 bi-directional, every `req.send()` _must_ provide a callback which is invoked
116 when the `RepSocket` replies.
117
118 ```js
119 var axon = require('axon')
120 , sock = axon.socket('req');
121
122 req.bind(3000);
123
124 req.send(img, function(res){
125
126 });
127 ```
128
129 `RepSocket`s receive a `reply` callback that is used to respond to the request,
130 you may have several of these nodes.
131
132 ```js
133 var axon = require('axon')
134 , sock = axon.socket('rep');
135
136 sock.connect(3000);
137
138 sock.on('message', function(img, reply){
139 // resize the image
140 reply(img);
141 });
142 ```
143
144 Like other sockets you may provide multiple arguments or an array of arguments,
145 followed by the callbacks. For example here we provide a task name of "resize"
146 to facilitate multiple tasks over a single socket:
147
148 ```js
149 var axon = require('axon')
150 , sock = axon.socket('req');
151
152 req.bind(3000);
153
154 req.send('resize', img, function(res){
155
156 });
157 ```
158
159 `RepSocket`s receive a `reply` callback that is used to respond to the request,
160 you may have several of these nodes.
161
162 ```js
163 var axon = require('axon')
164 , sock = axon.socket('rep');
165
166 sock.connect(3000);
167
168 sock.on('message', function(task, img, reply){
169 switch (task.toString()) {
170 case 'resize':
171 // resize the image
172 reply(img);
173 break;
174 }
175 });
176 ```
177
779e21d @tj docs
authored
178 ## PubEmitter / SubEmitter
5c2217f @tj Initial commit
authored
179
8bb5ddd @tj docs
authored
180 `PubEmitter` and `SubEmitter` are higher-level `Pub` / `Sub` sockets, using the "json" codec to behave much like node's `EventEmitter`. When a `SubEmitter`'s `.on()` method is invoked, the event name is `.subscribe()`d for you. Each wildcard (`*`) or regexp capture group is passed to the callback along with regular message arguments.
5c2217f @tj Initial commit
authored
181
779e21d @tj docs
authored
182 app.js:
5c2217f @tj Initial commit
authored
183
184 ```js
afe7fd5 @tj rename to axon
authored
185 var axon = require('axon')
779e21d @tj docs
authored
186 , sock = axon.socket('pub-emitter');
5c2217f @tj Initial commit
authored
187
779e21d @tj docs
authored
188 sock.connect(3000);
5c2217f @tj Initial commit
authored
189
190 setInterval(function(){
191 sock.emit('login', { name: 'tobi' });
192 }, 500);
193 ```
194
779e21d @tj docs
authored
195 logger.js:
5c2217f @tj Initial commit
authored
196
197 ```js
afe7fd5 @tj rename to axon
authored
198 var axon = require('axon')
779e21d @tj docs
authored
199 , sock = axon.socket('sub-emitter');
5c2217f @tj Initial commit
authored
200
779e21d @tj docs
authored
201 sock.bind(3000);
5c2217f @tj Initial commit
authored
202
853c449 @tj add more docs
authored
203 sock.on('user:login', function(user){
5c2217f @tj Initial commit
authored
204 console.log('%s signed in', user.name);
205 });
853c449 @tj add more docs
authored
206
207 sock.on('user:*', function(action, user){
208 console.log('%s %s', user.name, action);
209 });
210
211 sock.on('*', function(event){
212 console.log(arguments);
213 });
5c2217f @tj Initial commit
authored
214 ```
215
23b783e document new sockets
Garrett Johnson authored
216 ## Req / Rep
217
065e458 @tj fix readme typos
authored
218 `ReqSocket`s send and receive messages, queueing messages on remote disconnects. There
219 is no "lock step" involved, allowing messages sent later to receive replies prior to
220 previously sent messages. `RepSocket`s reply to received messages, there is no concept of `send()`. Each
221 received message will have a `reply` callback, which will send the response back to the remote peer:
23b783e document new sockets
Garrett Johnson authored
222
223 client.js
224 ```js
1c22b06 @tj fix readme require()s
authored
225 var axon = require('axon')
23b783e document new sockets
Garrett Johnson authored
226 , sock = axon.socket('req');
227
228 sock.connect(3000);
229
230 sock.on('message', function(msg){
231 console.log('got: %s', msg.toString());
232 });
233
234 setInterval(function(){
235 sock.send('ping');
236 }, 150);
237 ```
238
239 server.js
240 ```js
241
1c22b06 @tj fix readme require()s
authored
242 var axon = require('axon')
23b783e document new sockets
Garrett Johnson authored
243 , sock = axon.socket('rep');
244
245 sock.bind(3000);
246
247 sock.on('message', function(msg, reply){
248 console.log('got: %s', msg.toString());
249 reply('pong');
250 });
251 ```
252
253 ## Socket Options
254
255 Every socket has associated options that can be configured via `get/set`.
256
257 - `identity` - The "name" of the socket that uniqued identifies it.
258 - `retry timeout` - The amount of time until retries will not be attempted again.
259
065e458 @tj fix readme typos
authored
260 PubSockets additionally have options for batching:
23b783e document new sockets
Garrett Johnson authored
261
065e458 @tj fix readme typos
authored
262 - `batch max` - Max amount of messages to buffer in memory.
23b783e document new sockets
Garrett Johnson authored
263 - `batch ttl` - Amount of time to buffer messages before sending.
264
2153413 @tj add some docs for the previous commit
authored
265 ## Binding / Connecting
266
23b783e document new sockets
Garrett Johnson authored
267 In addition to passing a portno, binding to INADDR_ANY by default, you
268 may also specify the hostname via `.bind(port, host)`, another alternative
269 is to specify the url much like zmq via `tcp://<hostname>:<portno>`, thus
270 the following are equivalent:
2153413 @tj add some docs for the previous commit
authored
271
272 ```
273 sock.bind(3000)
274 sock.bind(3000, '0.0.0.0')
275 sock.bind('tcp://0.0.0.0:3000')
276
277 sock.connect(3000)
278 sock.connect(3000, '0.0.0.0')
279 sock.connect('tcp://0.0.0.0:3000')
280 ```
281
5c2217f @tj Initial commit
authored
282 ## Protocol
283
23b783e document new sockets
Garrett Johnson authored
284 The wire protocol is simple and very much zeromq-like, where `<length>` is
285 a BE 24 bit unsigned integer representing a maximum length of roughly ~16mb. The `<meta>`
286 data byte is currently only used to store the codec, for example "json" is simply `1`,
287 in turn JSON messages received on the client end will then be automatically decoded for
288 you by selecting this same codec.
5c2217f @tj Initial commit
authored
289
290 ```
291 octet: 0 1 2 3 <length>
292 +------+------+------+------+------------------...
293 | meta | <length> | data ...
294 +------+------+------+------+------------------...
295 ```
296
23b783e document new sockets
Garrett Johnson authored
297 Thus 5 bytes is the smallest message axon supports at the moment. Later if
298 necessary we can use the meta to indicate a small message and ditch octet 2 and 3
299 allowing for 3 byte messages.
05fbb1f @tj refactor framing
authored
300
43fbdf1 @tj add ss.codec.define() docs
authored
301 ## Codecs
302
23b783e document new sockets
Garrett Johnson authored
303 To define a codec simply invoke the `axon.codec.define()` method, for example
304 here is the JSON codec:
43fbdf1 @tj add ss.codec.define() docs
authored
305
306 ```js
23b783e document new sockets
Garrett Johnson authored
307 var axon = require('axon');
43fbdf1 @tj add ss.codec.define() docs
authored
308
23b783e document new sockets
Garrett Johnson authored
309 axon.codec.define('json', {
43fbdf1 @tj add ss.codec.define() docs
authored
310 encode: JSON.stringify,
311 decode: JSON.parse
312 });
313 ```
314
23b783e document new sockets
Garrett Johnson authored
315 __Note:__ codecs must be defined on both the sending and receiving ends, otherwise
316 axon cannot properly decode the messages. You may of course ignore this
065e458 @tj fix readme typos
authored
317 feature all together and simply pass encoded data to `.send()`.
43fbdf1 @tj add ss.codec.define() docs
authored
318
91f026a @tj add benchmarks to readme
authored
319 ## Performance
320
23b783e document new sockets
Garrett Johnson authored
321 I haven't profiled or tuned anything yet but so far for on my macbook pro.
8a27a53 @tj add more bm results to readme
authored
322
dd52c6d @tj add new batching benchmarks
authored
323 64 byte messages:
8a27a53 @tj add more bm results to readme
authored
324
325 ```
326
f195b92 use MBP benchmarks
Tyler Holowaychuk authored
327 min: 22,085 ops/s
328 mean: 585,944 ops/s
329 median: 606,176 ops/s
330 total: 326,7126 ops in 6.5s
331 through: 35.76318359375 mb/s
8a27a53 @tj add more bm results to readme
authored
332
333 ```
334
335 1k messages:
336
337 ```
338
f195b92 use MBP benchmarks
Tyler Holowaychuk authored
339 min: 1,851 ops/s
340 mean: 34,0156 ops/s
341 median: 449,660 ops/s
342 total: 329,831 ops in 4.241s
343 through: 332.18359375 mb/s
5fb13be @tj add redis comparison
authored
344
345 ```
346
00b5dcc @tj add some docs
authored
347 ## What's it good for?
348
56d87b6 @tj docs
authored
349 Axon are not meant to combat zeromq nor provide feature parity,
00b5dcc @tj add some docs
authored
350 but provide a nice solution when you don't need the insane
351 nanosecond latency or language interoperability that zeromq provides
afe7fd5 @tj rename to axon
authored
352 as axon do not rely on any third-party compiled libraries.
00b5dcc @tj add some docs
authored
353
5c2217f @tj Initial commit
authored
354 ## Running tests
355
356 ```
357 $ npm install
358 $ make test
359 ```
360
a3db9ac @tj authors
authored
361 ## Authors
362
363 - [visionmedia](http://github.com/visionmedia)
364 - [gjohnson](https://github.com/gjohnson)
365
18f2621 @tj Update master
authored
366 ## Links
367
368 - [Screencast](https://vimeo.com/45818408)
369
23b783e document new sockets
Garrett Johnson authored
370 ## License
5c2217f @tj Initial commit
authored
371
372 (The MIT License)
373
374 Copyright (c) 2012 TJ Holowaychuk &lt;tj@vision-media.ca&gt;
375
376 Permission is hereby granted, free of charge, to any person obtaining
377 a copy of this software and associated documentation files (the
378 'Software'), to deal in the Software without restriction, including
379 without limitation the rights to use, copy, modify, merge, publish,
380 distribute, sublicense, and/or sell copies of the Software, and to
381 permit persons to whom the Software is furnished to do so, subject to
382 the following conditions:
383
384 The above copyright notice and this permission notice shall be
385 included in all copies or substantial portions of the Software.
386
387 THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
388 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
389 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
390 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
391 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
392 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
393 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
394
Something went wrong with that request. Please try again.