5
5
remote workers.
6
6
"""
7
7
8
- from __future__ import absolute_import , division , print_function , unicode_literals
8
+ from __future__ import (absolute_import , division ,
9
+ print_function , unicode_literals )
9
10
11
+ from urllib .parse import urlparse
10
12
from abc import ABCMeta , abstractmethod
11
13
from concurrent .futures import Future
12
14
from threading import Thread
23
25
24
26
25
27
class TasqClientNotConnected (Exception ):
26
-
27
- def __init__ (self , msg = u'' ):
28
- self .message = msg
29
- super ().__init__ (self .message )
28
+ pass
30
29
31
30
32
31
class TasqFuture (Future ):
@@ -44,10 +43,22 @@ def exec_time(self):
44
43
45
44
class BaseTasqClient (metaclass = ABCMeta ):
46
45
47
- """
48
- Simple client class to schedule jobs to remote workers, currently
46
+ """Simple client class to schedule jobs to remote workers, currently
49
47
supports a synchronous way of calling tasks awaiting for results and an
50
48
asynchronous one which collect results in a dedicated dictionary
49
+
50
+ Attributes
51
+ ----------
52
+ :type host: str
53
+ :param host: The IP address to connect with
54
+
55
+ :type port: int
56
+ :param port: The port associated with the host param
57
+
58
+ :type sign_data: bool or False
59
+ :param sign_data: Boolean flag, sign bytes passing around through sockets
60
+ if True
61
+
51
62
"""
52
63
53
64
def __init__ (self , host , port , sign_data = False ):
@@ -100,11 +111,6 @@ def __exit__(self, exc_type, exc_value, exc_traceback):
100
111
pass
101
112
self .close ()
102
113
103
- def __repr__ (self ):
104
- status = 'connected' if self .is_connected else 'disconnected'
105
- return f"<BaseTasqClient worker=(tcp://{ self .host } :{ self .port } , " \
106
- f"tcp://{ self .host } :{ self .port } ) status={ status } >"
107
-
108
114
@abstractmethod
109
115
def _make_client (self ):
110
116
pass
@@ -188,7 +194,11 @@ def schedule_blocking(self, func, *args, **kwargs):
188
194
:type func: func
189
195
:param func: A function to be executed on a worker by enqueing it
190
196
197
+ :rtype: tasq.remote.client.TasqFuture
191
198
:return: The result of the func execution
199
+
200
+ :raise: tasq.remote.client.TasqClientNotConnected, in case of not
201
+ connected client
192
202
"""
193
203
if not self .is_connected :
194
204
raise TasqClientNotConnected ('Client not connected to no worker' )
@@ -203,8 +213,31 @@ class ZMQTasqClient(BaseTasqClient):
203
213
"""Simple client class to schedule jobs to remote workers, currently
204
214
supports a synchronous way of calling tasks awaiting for results and an
205
215
asynchronous one which collect results in a dedicated dictionary
216
+
217
+ Attributes
218
+ ----------
219
+ :type host: str
220
+ :param host: The IP address to connect with
221
+
222
+ :type port: int
223
+ :param port: The port associated with the host param for PUSH channel
224
+ communication
225
+
226
+ :type plport: int or None
227
+ :param plport: The pull port to retrieve bytes from
228
+
229
+ :type sign_data: bool or False
230
+ :param sign_data: Boolean flag, sign bytes passing around through sockets
231
+ if True
232
+
233
+ :type unix_socket: bool or False
234
+ :param unix_socket: Boolean flag to decide wether to use a UNIX socket or a
235
+ TCP one
236
+
206
237
"""
207
238
239
+ __extraparams__ = {'plport' }
240
+
208
241
def __init__ (self , host , port , plport = None , sign_data = False , unix_socket = False ):
209
242
self ._plport = plport or port + 1
210
243
# Unix socket flag, if set to true, unix sockets for interprocess
@@ -245,12 +278,52 @@ def _gather_results(self):
245
278
except KeyError :
246
279
self ._log .error ("Can't update result: key not found" )
247
280
281
+ @classmethod
282
+ def from_url (cls , url , sign_data = False ):
283
+ u = urlparse (url )
284
+ scheme = u .scheme or 'zmq'
285
+ assert scheme in ('zmq' , 'unix' , 'tcp' ), f"Unsupported { scheme } "
286
+ extras = {t .split ('=' )[0 ]: t .split ('=' )[1 ] for t in u .query .split ('?' )}
287
+ extras = {k : v for k , v in extras .items () if k in cls .__extraparams__ }
288
+ conn_args = {
289
+ 'host' : u .hostname or '127.0.0.1' ,
290
+ 'port' : u .port or 9000 ,
291
+ 'plport' : int (extras .get ('plport' , 0 )),
292
+ 'sign_data' : sign_data ,
293
+ 'unix_socket' : scheme == 'unix'
294
+ }
295
+ return cls (** conn_args )
296
+
248
297
249
298
class RedisTasqClient (BaseTasqClient ):
250
299
251
- """"""
300
+ """Simple Redis client class to schedule jobs to remote workers using
301
+ redis as the backend broker.
302
+
303
+ Attributes
304
+ ----------
305
+ :type host: str or 'localhost'
306
+ :param host: The IP address of the Redis instance to connect with
307
+
308
+ :type port: int or 6379
309
+ :param port: The port associated with the host param
310
+
311
+ :type db: int or 0
312
+ :param db: The database to use on redis for the queues
313
+
314
+ :type name: str or redis-queue
315
+ :param name: The name of the redis queue
316
+
317
+ :type sign_data: bool or False
318
+ :param sign_data: Boolean flag, sign bytes passing around through sockets
319
+ if True
320
+
321
+ """
322
+
323
+ __extraparams__ = {'db' , 'name' }
252
324
253
- def __init__ (self , host , port , db , name , sign_data = False ):
325
+ def __init__ (self , host = 'localhost' , port = 6379 ,
326
+ db = 0 , name = 'redis-queue' , sign_data = False ):
254
327
self ._db = db
255
328
self ._name = name
256
329
super ().__init__ (host , port , sign_data )
@@ -304,12 +377,49 @@ def disconnect(self):
304
377
if self .is_connected :
305
378
self ._is_connected = False
306
379
380
+ @classmethod
381
+ def from_url (cls , url , sign_data = False ):
382
+ u = urlparse (url )
383
+ scheme = u .scheme or 'redis'
384
+ assert scheme == 'redis' , f"Unsupported { scheme } "
385
+ extras = {t .split ('=' )[0 ]: t .split ('=' )[1 ] for t in u .query .split ('?' )}
386
+ extras = {k : v for k , v in extras .items () if k in cls .__extraparams__ }
387
+ conn_args = {
388
+ 'host' : u .hostname or 'localhost' ,
389
+ 'port' : u .port or 6379 ,
390
+ 'db' : int (extras .get ('db' , 0 )),
391
+ 'name' : extras .get ('name' , 'redis-queue' ),
392
+ 'sign_data' : sign_data
393
+ }
394
+ return cls (** conn_args )
395
+
307
396
308
397
class RabbitMQTasqClient (BaseTasqClient ):
309
398
310
- """"""
399
+ """Simple RabbitMQ client class to schedule jobs to remote workers using
400
+ RabbitMQ as the backend broker.
401
+
402
+ Attributes
403
+ ----------
404
+ :type host: str or 'localhost'
405
+ :param host: The IP address of the RabbitMQ instance to connect with
406
+
407
+ :type port: int or 5672
408
+ :param port: The port associated with the host param
409
+
410
+ :type name: str or amqp-queue
411
+ :param name: The name of the RabbitMQ queue
412
+
413
+ :type sign_data: bool or False
414
+ :param sign_data: Boolean flag, sign bytes passing around through sockets
415
+ if True
311
416
312
- def __init__ (self , host , port , name , sign_data = False ):
417
+ """
418
+
419
+ __extraparams__ = {'name' }
420
+
421
+ def __init__ (self , host = 'localhost' , port = 5672 ,
422
+ name = 'amqp-queue' , sign_data = False ):
313
423
self ._name = name
314
424
super ().__init__ (host , port , sign_data )
315
425
@@ -357,6 +467,21 @@ def disconnect(self):
357
467
if self .is_connected :
358
468
self ._is_connected = False
359
469
470
+ @classmethod
471
+ def from_url (cls , url , sign_data = False ):
472
+ u = urlparse (url )
473
+ scheme = u .scheme or 'amqp'
474
+ assert scheme == 'amqp' , f"Unsupported { scheme } "
475
+ extras = {t .split ('=' )[0 ]: t .split ('=' )[1 ] for t in u .query .split ('?' )}
476
+ extras = {k : v for k , v in extras .items () if k in cls .__extraparams__ }
477
+ conn_args = {
478
+ 'host' : u .hostname or 'localhost' ,
479
+ 'port' : u .port or 5672 ,
480
+ 'name' : extras .get ('name' , 'amqp-queue' ),
481
+ 'sign_data' : sign_data
482
+ }
483
+ return cls (** conn_args )
484
+
360
485
361
486
class TasqClientPool :
362
487
0 commit comments