Reputation: 173
Let's say I have:
I want to tie each opener to a Task instance (so each task has it's own opener, ie. with different auth cookies).
What I currently do is subclass from Task:
class TaskWithOpener(Task):
abstract = True
_openers = None
@property
def openers(self):
if self._openers is None:
print 'creating openers for', self
(...)
print 'openers already created for ', self, ' just returning them'
return self._openers
and make task like this:
@my_celery.task(rate_limit='5/m', base=TaskWithOpener)
def my_task():
opener = random.choice(my_task.openers)
But this way each task has list of multiple openers and they are created for each thread separately so when there are 3 credential pairs (login, password) and concurrency = 3, my program creates 9 openers which is unacceptable.
Upvotes: 1
Views: 1189
Reputation: 5249
This is perfectly valid behavior of Celery. You've basically created a class that for each instance creates three openers and instantiated it three times.
What you're trying to do is to spawn three tasks, each with its own set of credentials:
@celery.task(rate_limit='5/m')
def the_task(login, password):
opener = create_opener(login, password)
…
Then you can call it like:
credentials = [
('login1', 'password1'),
('login2', 'password2'),
('login3', 'password3'),
]
for login, password in credentials:
the_task.delay(login, password)
That way the worker will receive three tasks and apply rate limit to it.
Update:
From your comment and the code I suspect you want to make options a class attribute.
The problem is overwriting the attribute on self makes it an instance attribute.
I think you're trying to create a class property.
Honestly, I don't think this is a good solution. I would like to know why you don't want to create the opener each time.
Is this costly? Then what you're looking for is not a task queue + worker but some server running constantly (may be implemented over twisted).
Upvotes: 1