GustavoHenrique.net

  • About
  • Contact
  • RSS Feed
  • Twitter

 

21
Jan

Problema com cache do mod_wsgi

By gustavohenrique|Django|5 Comments

Certo dia terminei um projeto em Django e após vários testes finalmente foi ao ar. Feito isso, liguei para o cliente e marcamos uma reunião para o dia seguinte. Na reunião, conversa vai, conversa vem, o sistema é exibido, tudo funcionando, cliente feliz, eu feliz, tudo ótimo e maravilhoso. Eis então que o cliente sugere uma pequena alteração: Alterar uma mensagem emitida ao usuário. Tarefa simples, pensei. Vou abrir o arquivo e alterar uma string. Pronto! Nada complicado ou demorado que exija marcar uma nova reunião para apresentar essa mudança. Em casa eu atualizo o arquivo e fica tudo como está. Erro meu ter pensado assim. Após a modificação ter sido feita, o sistema não quis atualizar por nada. Apertei Crtl+F5, limpei o cache do navegador, testei em outros navegadores… e nada. Só podia ser cache no servidor de hospedagem. Então deletei todos os .pyc e mesmo assim não funcionou. A coisa era do mal mesmo.
Bom, expliquei ao cliente o que estava acontecendo e ganhei algum tempo para tentar resolver. Percebi que alterações feitas no código da aplicação não eram atualizadas em tempo real. Em outras palavras, se seu projeto já está no servidor de produção usando o mod_wsgi e você alterar o código de uma view ou model, a atualização não será refletida no exato momento.
Não me aprofundei no assunto mas aparentemente o mod_wsgi provê um sistema de cache que leva horas para verificar se houve alterações no código da aplicação. De fato, essa é uma atitude inteligente, pois uma vez que o projeto está em ambiente de produção, nenhuma alteração deveria ser feita naquele espaço. As alterações deveriam ser feitas no ambiente de desenvolvimento e só depois de passar nos testes seria levada ao ambiente de produção.
Então fui pedir ajuda ao oráculo (google) e, após algum tempo, encontrei um site contendo um script que me ajudou bastante naquele momento.

Crie um arquivo chamado monitor.py e ponha-o no diretório do projeto. Abaixo o conteúdo do arquivo:

import os
import sys
import time
import signal
import threading
import atexit
import Queue
 
_interval = 1.0
_times = {}
_files = []
 
_running = False
_queue = Queue.Queue()
_lock = threading.Lock()
 
def _restart(path):
  _queue.put(True)
  prefix = 'monitor (pid=%d):' % os.getpid()
  print >> sys.stderr, '%s Change detected to \'%s\'.' % (prefix, path)
  print >> sys.stderr, '%s Triggering process restart.' % prefix
  os.kill(os.getpid(), signal.SIGINT)
 
def _modified(path):
  try:
    if not os.path.isfile(path):
      return path in _times
 
    mtime = os.stat(path).st_mtime
    if path not in _times:
      _times[path] = mtime
 
    if mtime != _times[path]:
      return True
  except:
    return True
 
  return False
 
def _monitor():
  while 1:
    for module in sys.modules.values():
      if not hasattr(module, '__file__'):
        continue
      path = getattr(module, '__file__')
      if not path:
        continue
      if os.path.splitext(path)[1] in ['.pyc', '.pyo', '.pyd']:
        path = path[:-1]
      if _modified(path):
        return _restart(path)
    for path in _files:
      if _modified(path):
        return _restart(path)
 
    try:
      return _queue.get(timeout=_interval)
    except:
      pass
 
_thread = threading.Thread(target=_monitor)
_thread.setDaemon(True)
 
def _exiting():
  try:
    _queue.put(True)
  except:
    pass
  _thread.join()
 
atexit.register(_exiting)
 
def track(path):
  if not path in _files:
    _files.append(path)
 
def start(interval=1.0):
  global _interval
  if interval < _interval:
    _interval = interval
 
  global _running
  _lock.acquire()
  if not _running:
    prefix = 'monitor (pid=%d):' % os.getpid()
    print >> sys.stderr, '%s Starting change monitor.' % prefix
    _running = True
    _thread.start()
  _lock.release()

Para finalizar a configuração, altere o arquivo de configuração do mod_wsgi de modo a conter as duas últimas linhas do código abaixo:

import os, sys
sys.path.append('/home/usuario/www/apps_wsgi')
os.environ['DJANGO_SETTINGS_MODULE']='meuprojeto.settings'
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()
 
import meuprojeto.monitor
meuprojeto.monitor.start(interval=1.0)

Feito isso as alterações no código serão atualizadas no navegador em tempo real.
Lamento não inserir uma referência para o site do qual copiei o script, pois já faz algum tempo e não me lembro mais o nome nem a URL.

Links Relacionados

http://blog.dscpl.com.au/2009/02/source-code-reloading-with-modwsgi-on.html
http://blog.dscpl.com.au/2008/12/using-modwsgi-when-developing-django.html

Bookmark It

Add to Del.icio.us Add to Diigo Add to Facebook Add to Google Bookmarks Add to LinkedIn Add to Mister Wong Add to Twitter Add to Yahoo My Web
Tagged as: cache, Django, mod_wsgi
Add your comment →

5 Comments

  1. Cara, com mod_wsgi, basta vc criar um arquivo chamado /tmp/restart.txt no seu projeto que o wsgi recarrega o projeto. O lance é que o deploy de coisas Python (independente de framework) não será igual ao uso de PHP,onde basta substituir os arquivos e estará tudo ok.

    É isso!

    By: Walter Cruz Reply →
    January 23, 2009 at 1:12 am
  2. @Walter
    Obrigado pela dica!

    By: admin Reply →
    January 23, 2009 at 6:10 am
  3. Olha só eu divulgando informação incorreta… Pra recarregar o projeto, basta dar um touch no .wsgi que faz a interface com o apache! Abraço.

    By: Walter Cruz Reply →
    March 20, 2009 at 11:36 am
  4. Muito legal, parabéns pela dica.

    Conforme a dica do Walter Cruz, parece que você foi meio pelo caminho das pedras. Mas foi algo que funcionou legal.

    No final das contas, o conhecimento e a experiência valeu a pena.

    Parabéns e obrigado por compartilhar. :)

    By: Francisco Antônio da Silva Souza Reply →
    April 4, 2009 at 1:53 pm
  5. Muito boa a dica, ainda estou pensando em tirar o mod_python para usar o mod_wsgi, tenho algumas dúvidas ainda, e ter essas dicas ja nos ajuda se tivermos problemas.

    Abraços

    By: Mandrado Santos Reply →
    June 24, 2010 at 11:56 am

Leave your comment below! Cancel Reply

View More Posts:
  • ←
  • →

Tags

admin Django extjs firewall grails jquery KingHost liberações Linux manual model modelform mod_wsgi moeda brasileira mudanças mysql nível de serviço oo PagSeguro pdf php PIL pisa problemas proxy python qa qos real relacionamento roteamento service desk shell script sites tdd tipsforlinux traducao ubicomp ubuntu urllib virtualhost Webservices wikipedia xsol __init__

Recent Posts

  • Configurando um servidor LDAP no CentOS 6.2
  • Introdução ao padrão MVC no Ext JS 4
  • Virtualização com KVM
  • Autenticação Facebook no Grails
  • Grails com Sqlite3 no Ubuntu 11.04
  • Deploy no tomcat usando django-jython
  • Deploy múltiplas versões do Django no Nginx com VirtualEnv
  • Comandos básicos do Git
  • Introdução ao Apache Wicket
  • Feliz 2011

Archives

Categories

My tweets

  • @tregismoreira Genesis 7200 com android 4 2 days ago
  • @marcomaciel blz! 1 week ago
  • @marcomaciel hack com qualquer linguagem em qualquer plataforma pra mim ta valendo! #soudev 1 week ago
  • Fui instalar o android 2.3 da lg e agora meu celular não liga. #ffuuu 1 week ago
  • Tentando gerar uma NFe e não consigo =/ #stacktrace Impressionante como todos os sites e apps do governo são ruins. 2 weeks ago
  • More updates...

Powered by the inLine Minimal WordPress Theme