1- var _ = require ( 'underscore' ) ;
1+ var _ = require ( 'underscore' ) ,
2+ cluster = require ( 'cluster' ) ,
3+ redis = require ( 'redis' ) ;
24
3- function ProducerBackend ( options ) {
4- options = options || { } ;
5+ function ProducerBackend ( frontend , options ) {
6+ options = _ . clone ( options ) || { } ;
57
68 _ . defaults ( options , {
79 host : "localhost" ,
810 port : 6379 ,
9- prefix : "workqueue"
11+ prefix : "workqueue:" ,
1012 } ) ;
13+
14+ this . frontend = frontend ;
15+ this . options = options ;
16+ this . pending = { } ;
17+ this . active = { } ;
18+ this . queue = [ ] ;
19+ this . producerId = - 1 ;
20+ this . choked = false ;
21+
22+ var producerClient = this . producerClient = redis . createClient ( options . port , options . host ) ;
23+ var responseClient = this . responseClient = redis . createClient ( options . port , options . host ) ;
24+
25+ producerClient . on ( 'ready' , _ . bind ( function ( ) {
26+ if ( this . producerId < 0 ) {
27+ producerClient . incr ( options . prefix + "producers" , _ . bind ( function ( err , data ) {
28+ this . producerId = data ;
29+ this . scheduleResponse ( ) ;
30+ this . processQueue ( ) ;
31+ } , this ) ) ;
32+ } else {
33+ this . processQueue ( ) ;
34+ }
35+ } , this ) ) ;
36+ producerClient . on ( 'close' , _ . bind ( function ( ) {
37+ this . producerId = - 1 ;
38+ } ) ) ;
39+ producerClient . on ( 'error' , _ . bind ( function ( ) {
40+ this . producerId = - 1 ;
41+ } , this ) ) ;
42+ producerClient . on ( 'drain' , _ . bind ( function ( ) {
43+ this . choked = false ;
44+ this . processQueue ( ) ;
45+ } , this ) ) ;
46+ responseClient . on ( 'ready' , _ . bind ( function ( ) {
47+ this . scheduleResponse ( ) ;
48+ } , this ) ) ;
49+ responseClient . on ( 'error' , _ . bind ( function ( ) {
50+ } ) ) ;
1151}
1252
1353_ . extend ( ProducerBackend . prototype , {
54+ setupWorker : function ( worker ) {
55+ } ,
56+
57+ queueMessage : function ( message ) {
58+ message . timestamp = new Date ( ) ;
59+ this . queue . push ( message ) ;
60+ this . processQueue ( ) ;
61+ } ,
62+
63+ processQueue : function ( ) {
64+ if ( this . queue . length == 0 ) {
65+ return ;
66+ }
67+
68+ if ( this . choked ) {
69+ if ( this . producerClient . command_queue . length > 0 ) {
70+ return ;
71+ }
72+ this . choked = false ;
73+ }
74+
75+ if ( ! this . producerClient . connected || ( this . producerId < 0 ) ) {
76+ return ;
77+ }
78+
79+ if ( this . producerClient . command_queue . length > 200 ) {
80+ this . choked = true ;
81+ return ;
82+ }
83+
84+ var message = this . queue . shift ( ) ;
85+ this . pending [ message . payload . index ] = message ;
86+ message . payload . sender = this . producerId ;
87+
88+ var jobQueue = this . options . prefix + "jobs" ;
89+ this . producerClient . multi ( ) . rpush ( jobQueue , JSON . stringify ( message . payload ) , _ . bind ( function ( err ) {
90+ if ( err ) {
91+ if ( message . payload . index ) {
92+ delete this . pending [ message . payload . index ] ;
93+ this . queue . unshift ( message ) ;
94+ }
95+ delete message . payload . sender ;
96+
97+ } else {
98+ this . processQueue ( ) ;
99+ }
100+ } , this ) ) . expire ( jobQueue , 20 ) . exec ( ) ;
101+ } ,
102+
103+ scheduleResponse : function ( ) {
104+ if ( this . producerId < 0 ) {
105+ return ;
106+ }
107+
108+ var responseQueue = this . options . prefix + "response." + this . producerId ;
109+ this . responseClient . blpop ( responseQueue , 5 , _ . bind ( function ( err , data ) {
110+ if ( ! err && data ) {
111+ var response = JSON . parse ( data [ 1 ] ) ;
112+ var message = this . pending [ response . index ] ;
113+ if ( message ) {
114+ delete this . pending [ response . index ] ;
115+ this . frontend . onResponse ( message , response ) ;
116+ delete message . payload . index ;
117+ }
118+ }
119+
120+ process . nextTick ( _ . bind ( function ( ) {
121+ this . scheduleResponse ( ) ;
122+ } , this ) ) ;
123+ } , this ) ) ;
124+ } ,
125+
126+ onTimeout : function ( id ) {
127+ var pending = this . pending [ id ] ;
128+ if ( pending ) {
129+ delete this . pending [ id ] ;
130+ delete pending . payload . index ;
131+ } else {
132+ this . queue = _ . filter ( this . queue , function ( message ) {
133+ return message . payload . index != id ;
134+ } ) ;
135+ }
136+ this . processQueue ( ) ;
137+ }
14138} ) ;
15139
16- function ConsumerBackend ( options ) {
17- options = options || { } ;
140+ function ConsumerBackend ( frontend , options ) {
141+ options = _ . clone ( options ) || { } ;
18142
19143 _ . defaults ( options , {
20144 host : "localhost" ,
21145 port : 6379 ,
22- prefix : "workqueue"
146+ prefix : "workqueue: "
23147 } ) ;
148+
149+ this . frontend = frontend ;
150+ this . options = options ;
24151}
25152
26153_ . extend ( ConsumerBackend . prototype , {
27- } ) ;
154+ run : function ( ) {
155+ var redisClient = this . redisClient = redis . createClient ( this . options . port , this . options . host ) ;
156+ redisClient . on ( 'ready' , _ . bind ( function ( ) {
157+ this . reschedule ( ) ;
158+ } , this ) ) ;
159+ redisClient . on ( 'error' , _ . bind ( function ( ) {
160+ } , this ) ) ;
161+ } ,
162+
163+ reschedule : function ( ) {
164+ var jobQueue = this . options . prefix + "jobs" ;
165+ this . redisClient . blpop ( jobQueue , 0 , _ . bind ( function ( err , data ) {
166+ if ( err || ! data ) {
167+ this . reschedule ( ) ;
168+ }
169+ this . frontend . onPayload ( JSON . parse ( data [ 1 ] ) ) ;
170+ } , this ) ) ;
171+ } ,
172+
173+ onResponse : function ( message , response ) {
174+ var responseQueue = this . options . prefix + "response." + message . sender ;
175+ this . redisClient . multi ( ) . rpush ( responseQueue , JSON . stringify ( {
176+ error : response ,
177+ index : message . index
178+ } ) ) . expire ( responseQueue , 20 ) . exec ( ) ;
179+ this . reschedule ( ) ;
180+ }
181+ } ) ;
182+
183+ exports . ProducerBackend = ProducerBackend ;
184+ exports . ConsumerBackend = ConsumerBackend ;
0 commit comments