Deixa para depois, Procrastinando com Celery em Python

Post on 05-Dec-2014

1.477 views 0 download

description

Palestra do #TDC2011 que mostra como usar o celery para tarefas distribuidas

Transcript of Deixa para depois, Procrastinando com Celery em Python

Procrastinando com Celery

adriano petrich petrich@gmail.com #TDC2011

.

O que é o Celery?

Ponto forte do Celery

• Gerenciador de tarefas assíncrono

Ponto forte do Celery

• Gerenciador de tarefasassíncrono

• Distribuído entre máquinas

Os dois pontos fortesdo Celery

• Gerenciador de tarefasassíncrono

• Distribuído entre máquinas

Os dois pontos fortesdo Celery

• Gerenciador de tarefasassíncrono

• Distribuído entre máquinas

• Agendador

CeleryDentre os pontos fortes do Celerydestacam-se

• Gerenciador de tarefasassíncrono

• Distribuído entre máquinas

• Agendador

• Com tolerância a falhas

Como Funciona?

Resposta Curta

.

Resposta Longa

EstruturaTarefa

Publicadores

Fila

Trabalhadores/Consumidores

Tarefa

Tarefa

from celery.task import task

@taskdef foo(val): return val

Publicador

PublicadoresSincronamente

>>> foo(5)5

PublicadoresAssincronamente

>>> res = foo.delay(5)

Dois Jeitos

# não bloqueia>>> res.ready()True ou False>>> res.result5# ou bloqueia>>> res.get()5

Fila

FilaBackend sugerido é o RabbitMQ

(todas as crianças legais do bairro usamerlang)

Mas também suportaRedis

Beanstalk

MongoDB

CouchDB

e bancos suportados pelo ORM do Django

Trabalhador

TrabalhadorPode estar rodando em outra máquina

Cada Worker process ainda pode usarvários threads

Trabalhador

$ celeryd

$ ./manage celeryd

Por que?

Web ou StandAlone?

WebPainel de Escalabilidade (djangocon.eu)

http://2011.djangocon.eu/talks/47/

Problemas comunsWhat are the common mistakes you see.--------------------------------------Things that take a long time ("sending an email")that lock up a process. Using the filesystem for caching.Testing locally and pushing it live and see it fall over.Using an external API can also take a long time.Work with timeouts to work around it.

Processos demoradosentopem os tubes

Soluções comunsTenha um celery de criança:Scaling wise, what should you think about before scalingbecomes an actual issue? And what should you definitelyleave until the moment comes you need to scale?----------------------------------------------

First things first: use a queue like celery, even on small sites.Get used to such a queue and have it in place, that'll help alot with performance later.Make sure you've got your databaseschema is mostly OK. It doesn't have to be perfect right away,but at least mostly OK.

Expect something to change and assume you'll have to swap somethingout later to improve the performance.

email.pyfrom celery.task import taskfrom django.core.mail import send_mail

@taskdef send(subject, message, recipient_list, from_email=None, **kwargs): if subject[0] != "[": subject = "[projeto] "+ subject if from_email is None: from_email = "suporte@fuuuuuu.com" send_mail(subject, message, from_email, recipient_list, **kwargs)

Um bom padrãofrom email import send

@taskdef relatorio(dados): ....gera relatorio.... send.delay("Relatorio Pronto", """ Pode baixadas daqui: http://fuuuuuu.com/relatorios/%s.pdf """% filename, (email,))

StandAloneScripts

Map Reducetarefas = []livros =["iliada.txt","odisseia.txt"....]for filename in livros: tarefas.append( conta_palavras.delay(filename) )

para pegar o resultado

if all([i.ready() for i in tarefas]): palavras = sum([i.result for i in tarefas])

Armadilhas e dicas

Django-celery noadmin

Inicia um worker

$ ./manage.py celeryd -l info -E

e daí: BAM!

Tem que rolar também

$ ./manage.py celerycam

Testar#no settings.pyTEST_RUNNER='djcelery.contrib.test_runner.run_tests'

from django.test import TestCasefrom myapp.tasks import add

class AddTestCase(TestCase):

def testNoError(self): """Test that the ``add`` task runs with no errors, and returns the correct result.""" result = add.delay(8, 8)

self.assertEquals(result.get(), 16) self.assertTrue(result.successful())

Sem resposta

CELERY_IGNORE_RESULT = True

Transactions nodjangodef bar(request): sanduiche = Sanduiche("Pernil") sanduiche.save() avisa_novo.delay(sanduiche.id)

Especialmente seMIDDLEWARE_CLASSES = ( 'django.middleware.transaction.TransactionMiddleware', ...

Assimdef bar(request): sanduiche = Sanduiche("Pernil") sanduiche.save() if transaction.is_managed(): transaction.commit() avisa_novo.delay(sanduiche.id)

Para desenvolvimentofrom socket import error

try: avisa_novo.delay(sanduiche.id)except error: log.error("conexao recusada") if not DEBUG: raise error

Muitas tarefas

for i in algo_grande: avisa_novo.delay(i)

Muitas tarefassubtasks = []for i in algo_grande: subtasks.append(subtask(avisa_novo, args=(i)))

TaskSet(tasks=subtasks).apply_async()

Créditoshttp://www.flickr.com/photos/lexnger/1794462309http://www.flickr.com/photos/atmtx/4250159996http://www.flickr.com/photos/prettydaisies/2368005479http://www.flickr.com/photos/benobryan/3766107097http://www.flickr.com/photos/eli_k_hayasaka/3989808211http://www.flickr.com/photos/carolinabarmell/2980660350http://www.flickr.com/photos/jjay/2415455625http://www.flickr.com/photos/tim_proffitt_white/3181616233http://www.flickr.com/photos/daniele_sartori/4484430735http://www.flickr.com/photos/project-404/27730644

Dúvidas?@fractal

+Adriano Petrich

[codando.com.br, sfp.adrianopetrich.com,blog.adrianopetrich.com]