Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

memory leak? #82

Open
rvalyi opened this issue Nov 18, 2015 · 14 comments
Open

memory leak? #82

rvalyi opened this issue Nov 18, 2015 · 14 comments

Comments

@rvalyi
Copy link
Member

rvalyi commented Nov 18, 2015

Ola pessoal

Temos um cliente que esta lancando centenas de notas hoje ele usa so a parte de criar NFe's e transmitir elas nesse tempo. A cada duas horas ou algo assim, o servidor cai, parece que ele esta aumentando o consumo da memoria RAM sempre. Provavelemte o processo ultrapassa o que ele pode alcancar.

Tou perguntando aqui se alguem ja viu algo assim porque e o unico projeto que temos onde acontece isso e acontece que o ERP so esta usando o pysped massivamente hoje.

A gente vai resolver o problema la com supervisao, mas seria interessante saber:
alguem ja observou algum memory leak nessa parte da transmissao das notas com o pysped?

Como esta usando algumas bibliotecas com extencoes em C por tras esse tipo de problema nao seria impossivel...

@mileo
Copy link
Member

mileo commented Nov 18, 2015

Qual a configuração da maquina?

@rvalyi
Copy link
Member Author

rvalyi commented Nov 18, 2015

Ubuntu Trusty 64 bits. A memoria ta mais do que suficent (8Go mas tem outras coisas rodando), o lance e que a gente ve que transmissao apos transmissao ele nao libera a memoria. Geralmente o Gunicorn ja supervisa os workers do Odoo e um worker nao consegue matar o processo pai. Nesse caso especifico porem, e o processo global que morre.

Alem de observar a memoria engordar, eu nao sei o que mata o processo no final. Nesse caso nao temos supervisao entao fica misterioso mesmo. Ele morre com uns 80% da memoria ocupada apenas com a messagem:

Killed

no log. Talvez o Gunicorn nao consegue mais reservar a memoria que ele precisa e morre. Eu nao tenho a minima ideia. So tenho a impressao que algo da transmissao nao libera a memoria como deveria. Tambem como e um processo repititivo de cadastrar e transmitir notas, eu realmente acho que o processo para por causa do memory leak e nao algum outro problema pontual.
Esse problema provavelemte seria dentro do pysped ou uma lib que ele usa.

Mas enfim relato o problema aqui. Isso vai ficar chato de debugar mesmo e aqui nao e prioridade. Quis apenas saber se alguem ja encontrou esse problema. Senao fica registrado para que o proximo se toca que pode ter um problema nisso.

@mileo
Copy link
Member

mileo commented Nov 18, 2015

O limite de memoria do worker ta em quanto?

@rvalyi
Copy link
Member Author

rvalyi commented Nov 18, 2015

@mileo nesse caso:

limit_memory_hard = 2684354560
limit_memory_soft = 2147483648

Porem nao e o Gunircorn que mata um worker, porque quando isso acontece, ele escreve no log e alem disso so o um worker morre e nao o processo pai. Eu nao acho que o problema tenha a ver com a supervisao do Gunicorn nesse caso.

@mileo
Copy link
Member

mileo commented Nov 26, 2015

@rvalyi Tivemos alguns problemas no começo, mas eu não consegui diagnosticar se é um problema do PySPED ou algo relacionado.

Mas depois de vários ajustes na nossa infraestrutura tenho rodado instancias com 512 ram emitindo nf-e tranquilamente.

@rvalyi
Copy link
Member Author

rvalyi commented Nov 26, 2015

@mileo no caso nao estamos usando mas de 512Mo nesse servico. O unico problema que eu vejo e que a cada nota transmitida a memoria aumenta. Com uma supervisao por cima isso funciona com certeza. Agora nao deixa de ser um probleminha. Imagine que vc use o Odoo como CMS/ecommerce, vc vai ter seus workers consumindo rapidamente mais RAM do que vc deveria. Ai vc pode ter a supervisao que mata os workers ou o processo global (talvez). Mas ai restartando workers novos vc perde performance porque perde o cache por examplo.

Nao acho que seja nehnum problema prioritario e nao acho que seja simples de resolver. So queria deixar arquivado algum lugar para ver se temos relatorios convergentes disso ate alguem achar algo para resolver.

@mileo
Copy link
Member

mileo commented Dec 15, 2015

Filename: /home/mileo/Projects/odoo/odoo8-oca/parts/l10n_br/odoo-brazil-eletronic-documents/nfe/sped/nfe/processing/processor.py

Line # Mem usage Increment Line Contents

46    164.3 MiB      0.0 MiB       @profile
47                                 def __init__(self, company):
48    164.3 MiB      0.0 MiB           super(ProcessadorNFe, self).__init__()
49    164.3 MiB      0.0 MiB           self.ambiente = int(company.nfe_environment) or 2
50    164.3 MiB      0.0 MiB           self.estado = company.partner_id.l10n_br_city_id.state_id.code
51    164.3 MiB      0.0 MiB           self.versao = company.nfe_version
52    164.3 MiB      0.0 MiB           self.certificado = Certificado(company)
53    164.3 MiB      0.0 MiB           self.caminho = company.nfe_root_folder
54    164.3 MiB      0.0 MiB           self.salvar_arquivos = False
55    164.3 MiB      0.0 MiB           self.contingencia_SCAN = False
56    164.3 MiB      0.0 MiB           self.contingencia = False
57    164.3 MiB      0.0 MiB           self.danfe = DANFE()
58    164.3 MiB      0.0 MiB           self.daede = DAEDE()
59    164.3 MiB      0.0 MiB           self.caminho_temporario = ''
60    164.3 MiB      0.0 MiB           self.maximo_tentativas_consulta_recibo = 5
61    164.3 MiB      0.0 MiB           self.consulta_servico_ao_enviar = False
62                             
63    164.3 MiB      0.0 MiB           self._servidor     = ''
64    164.3 MiB      0.0 MiB           self._url          = ''
65    164.3 MiB      0.0 MiB           self._soap_envio   = None
66    164.3 MiB      0.0 MiB           self._soap_retorno = None

Filename: /home/mileo/Projects/odoo/odoo8-oca/parts/l10n_br/odoo-brazil-eletronic-documents/nfe/sped/nfe/processing/xml.py

Line # Mem usage Increment Line Contents

35    164.3 MiB      0.0 MiB   @profile
36                             def __processo(company):
37                             
38    164.3 MiB      0.0 MiB       p = ProcessadorNFe(company)
39    164.3 MiB      0.0 MiB       p.ambiente = int(company.nfe_environment)
40    164.3 MiB      0.0 MiB       p.estado = company.partner_id.l10n_br_city_id.state_id.code
41    164.3 MiB      0.0 MiB       p.certificado = Certificado(company)
42    164.3 MiB      0.0 MiB       p.salvar_arquivos = True
43    164.3 MiB      0.0 MiB       p.contingencia_SCAN = False
44    164.3 MiB      0.0 MiB       p.caminho = company.nfe_root_folder
45    164.3 MiB      0.0 MiB       return p

Filename: /home/mileo/Projects/odoo/odoo8-oca/parts/l10n_br/odoo-brazil-eletronic-documents/nfe/sped/nfe/processing/xml.py

Line # Mem usage Increment Line Contents

47    164.3 MiB      0.0 MiB   @profile
48                             def monta_caminho_nfe(company, chave_nfe):
49    164.3 MiB      0.0 MiB       p = __processo(company)
50    164.3 MiB      0.0 MiB       return p.monta_caminho_nfe(p.ambiente, chave_nfe)

Filename: /home/mileo/Projects/odoo/odoo8-oca/parts/l10n_br/odoo-brazil-eletronic-documents/nfe/models/account_invoice.py

Line # Mem usage Increment Line Contents

64    114.2 MiB      0.0 MiB       @api.multi
65                                 @profile
66                                 def nfe_export(self):
67                             
68    164.3 MiB     50.1 MiB           for inv in self:
69                             
70    114.2 MiB    -50.1 MiB               validate_nfe_configuration(inv.company_id)
71                             
72    114.2 MiB      0.0 MiB               nfe_obj = self._get_nfe_factory(inv.nfe_version)
73                             
74                                         # nfe_obj = NFe310()
75    114.2 MiB      0.0 MiB               nfes = nfe_obj.get_xml(self.env.cr, self.env.uid, self.ids,
76    114.2 MiB      0.0 MiB                                      int(inv.company_id.nfe_environment),
77    116.9 MiB      2.6 MiB                                      self.env.context)
78                             
79    164.3 MiB     47.5 MiB               for nfe in nfes:
80                                             # erro = nfe_obj.validation(nfe['nfe'])
81    164.3 MiB      0.0 MiB                   erro = XMLValidator.validation(nfe['nfe'], nfe_obj)
82    164.3 MiB      0.0 MiB                   nfe_key = nfe['key'][3:]
83    164.3 MiB      0.0 MiB                   if erro:
84                                                 raise RedirectWarning(
85                                                     erro, _(u'Erro na validaço da NFe!'))
86                             
87    164.3 MiB      0.0 MiB                   inv.write({'nfe_access_key': nfe_key})
88    164.3 MiB      0.0 MiB                   save_dir = os.path.join(
89    164.3 MiB      0.0 MiB                       monta_caminho_nfe(
90    164.3 MiB      0.0 MiB                           inv.company_id,
91    164.3 MiB      0.0 MiB                           chave_nfe=nfe_key) +
92    164.3 MiB      0.0 MiB                       'tmp/')
93    164.3 MiB      0.0 MiB                   nfe_file = nfe['nfe'].encode('utf8')
94                             
95    164.3 MiB      0.0 MiB                   file_path = save_dir + nfe_key + '-nfe.xml'
96    164.3 MiB      0.0 MiB                   try:
97    164.3 MiB      0.0 MiB                       if not os.path.exists(save_dir):
98    164.3 MiB      0.0 MiB                           os.makedirs(save_dir)
99    164.3 MiB      0.0 MiB                       f = open(file_path, 'w')
   100                                             except IOError:
   101                                                 raise RedirectWarning(
   102                                                     _(u'Erro!'), _(u"""Não foi possível salvar o arquivo
   103                                                         em disco, verifique as permissões de escrita
   104                                                         e o caminho da pasta"""))
   105                                             else:
   106    164.3 MiB      0.0 MiB                       f.write(nfe_file)
   107    164.3 MiB     -0.0 MiB                       f.close()
   108                             
   109    164.3 MiB      0.0 MiB                       event_obj = self.env['l10n_br_account.document_event']
   110    164.3 MiB      0.0 MiB                       event_obj.create({
   111    164.3 MiB      0.0 MiB                           'type': '0',
   112    164.3 MiB      0.0 MiB                           'company_id': inv.company_id.id,
   113    164.3 MiB      0.0 MiB                           'origin': '[NF-E]' + inv.internal_number,
   114    164.3 MiB      0.0 MiB                           'file_sent': file_path,
   115    164.3 MiB      0.0 MiB                           'create_date': datetime.datetime.now(),
   116    164.3 MiB      0.0 MiB                           'state': 'draft',
   117    164.3 MiB      0.0 MiB                           'document_event_ids': inv.id
   118                                                 })
   119    164.3 MiB      0.0 MiB                       inv.write({'state': 'sefaz_export'})

Filename: /home/mileo/Projects/odoo/odoo8-oca/parts/l10n_br/odoo-brazil-eletronic-documents/nfe/sped/nfe/processing/processor.py

Line # Mem usage Increment Line Contents

46    165.0 MiB      0.0 MiB       @profile
47                                 def __init__(self, company):
48    165.0 MiB      0.0 MiB           super(ProcessadorNFe, self).__init__()
49    165.0 MiB      0.0 MiB           self.ambiente = int(company.nfe_environment) or 2
50    165.0 MiB      0.0 MiB           self.estado = company.partner_id.l10n_br_city_id.state_id.code
51    165.0 MiB      0.0 MiB           self.versao = company.nfe_version
52    165.0 MiB      0.0 MiB           self.certificado = Certificado(company)
53    165.0 MiB      0.0 MiB           self.caminho = company.nfe_root_folder
54    165.0 MiB      0.0 MiB           self.salvar_arquivos = False
55    165.0 MiB      0.0 MiB           self.contingencia_SCAN = False
56    165.0 MiB      0.0 MiB           self.contingencia = False
57    165.0 MiB      0.0 MiB           self.danfe = DANFE()
58    165.0 MiB      0.0 MiB           self.daede = DAEDE()
59    165.0 MiB      0.0 MiB           self.caminho_temporario = ''
60    165.0 MiB      0.0 MiB           self.maximo_tentativas_consulta_recibo = 5
61    165.0 MiB      0.0 MiB           self.consulta_servico_ao_enviar = False
62                             
63    165.0 MiB      0.0 MiB           self._servidor     = ''
64    165.0 MiB      0.0 MiB           self._url          = ''
65    165.0 MiB      0.0 MiB           self._soap_envio   = None
66    165.0 MiB      0.0 MiB           self._soap_retorno = None

Filename: /home/mileo/Projects/odoo/odoo8-oca/parts/l10n_br/odoo-brazil-eletronic-documents/nfe/sped/nfe/processing/xml.py

Line # Mem usage Increment Line Contents

35    165.0 MiB      0.0 MiB   @profile
36                             def __processo(company):
37                             
38    165.0 MiB      0.0 MiB       p = ProcessadorNFe(company)
39    165.0 MiB      0.0 MiB       p.ambiente = int(company.nfe_environment)
40    165.0 MiB      0.0 MiB       p.estado = company.partner_id.l10n_br_city_id.state_id.code
41    165.0 MiB      0.0 MiB       p.certificado = Certificado(company)
42    165.0 MiB      0.0 MiB       p.salvar_arquivos = True
43    165.0 MiB      0.0 MiB       p.contingencia_SCAN = False
44    165.0 MiB      0.0 MiB       p.caminho = company.nfe_root_folder
45    165.0 MiB      0.0 MiB       return p

Filename: /home/mileo/Projects/odoo/odoo8-oca/parts/l10n_br/odoo-brazil-eletronic-documents/nfe/sped/nfe/processing/xml.py

Line # Mem usage Increment Line Contents

85    165.0 MiB      0.0 MiB   @profile
86                             def send(company, nfe):
87                             
88    165.0 MiB      0.0 MiB       p = __processo(company)
89                                 # Busca a versão da NF a ser emitida, não a do cadastro da empresa
90    165.0 MiB      0.0 MiB       p.versao = str(nfe[0].infNFe.versao.valor)
91    165.1 MiB      0.1 MiB       p.danfe.logo = add_backgound_to_logo_image(company)
92    165.1 MiB      0.0 MiB       p.danfe.leiaute_logo_vertical = True
93    165.1 MiB      0.0 MiB       p.danfe.nome_sistema = company.nfe_email or \
94                                     u"""Odoo/OpenERP - Sistema de Gestao Empresarial de Codigo Aberto
95    165.1 MiB      0.0 MiB           - 100%% WEB - www.openerpbrasil.org"""
96                             
97    165.1 MiB      0.0 MiB       return p.processar_notas(nfe)

Filename: /home/mileo/Projects/odoo/odoo8-oca/parts/l10n_br/odoo-brazil-eletronic-documents/nfe/models/account_invoice.py

Line # Mem usage Increment Line Contents

   122    164.3 MiB      0.0 MiB       @api.multi
   123                                 @profile
   124                                 def action_invoice_send_nfe(self):
   125                             
   126    169.7 MiB      5.4 MiB           for inv in self:
   127                             
   128    164.3 MiB     -5.4 MiB               event_obj = self.env['l10n_br_account.document_event']
   129    164.3 MiB      0.0 MiB               event = max(
   130    164.3 MiB      0.0 MiB                   event_obj.search([('document_event_ids', '=', inv.id),
   131    164.3 MiB      0.0 MiB                                     ('type', '=', '0')]))
   132    164.3 MiB      0.0 MiB               arquivo = event.file_sent
   133    164.3 MiB      0.0 MiB               nfe_obj = self._get_nfe_factory(inv.nfe_version)
   134                             
   135    164.3 MiB      0.0 MiB               nfe = []
   136    164.3 MiB      0.0 MiB               results = []
   137    164.3 MiB      0.0 MiB               protNFe = {}
   138    164.3 MiB      0.0 MiB               protNFe["state"] = 'sefaz_exception'
   139    164.3 MiB      0.0 MiB               protNFe["status_code"] = ''
   140    164.3 MiB      0.0 MiB               protNFe["message"] = ''
   141    164.3 MiB      0.0 MiB               protNFe["nfe_protocol_number"] = ''
   142    164.3 MiB      0.0 MiB               try:
   143    165.0 MiB      0.7 MiB                   nfe.append(nfe_obj.set_xml(arquivo))
   144    169.7 MiB      4.7 MiB                   for processo in send(inv.company_id, nfe):
   145    169.7 MiB      0.0 MiB                       vals = {
   146    169.7 MiB      0.0 MiB                           'type': str(processo.webservice),
   147    169.7 MiB      0.0 MiB                           'status': processo.resposta.cStat.valor,
   148    169.7 MiB      0.0 MiB                           'response': '',
   149    169.7 MiB      0.0 MiB                           'company_id': inv.company_id.id,
   150    169.7 MiB      0.0 MiB                           'origin': '[NF-E]' + inv.internal_number,
   151                                                     # TODO: Manipular os arquivos manualmente
   152                                                     # 'file_sent': processo.arquivos[0]['arquivo'],
   153                                                     # 'file_returned': processo.arquivos[1]['arquivo'],
   154    169.7 MiB      0.0 MiB                           'message': processo.resposta.xMotivo.valor,
   155    169.7 MiB      0.0 MiB                           'state': 'done',
   156    169.7 MiB      0.0 MiB                           'document_event_ids': inv.id}
   157    169.7 MiB      0.0 MiB                       results.append(vals)
   158    169.7 MiB      0.0 MiB                       if processo.webservice == 1:
   159    169.7 MiB      0.0 MiB                           for prot in processo.resposta.protNFe:
   160    169.7 MiB      0.0 MiB                               protNFe["status_code"] = prot.infProt.cStat.valor
   161                                                         protNFe["nfe_protocol_number"] = \
   162    169.7 MiB      0.0 MiB                                   prot.infProt.nProt.valor
   163    169.7 MiB      0.0 MiB                               protNFe["message"] = prot.infProt.xMotivo.valor
   164    169.7 MiB      0.0 MiB                               vals["status"] = prot.infProt.cStat.valor
   165    169.7 MiB      0.0 MiB                               vals["message"] = prot.infProt.xMotivo.valor
   166    169.7 MiB      0.0 MiB                               if prot.infProt.cStat.valor in ('100', '150'):
   167    169.7 MiB      0.0 MiB                                   protNFe["state"] = 'open'
   168                                                         elif prot.infProt.cStat.valor in ('110', '301',
   169                                                                                           '302'):
   170                                                             protNFe["state"] = 'sefaz_denied'
   171    169.7 MiB      0.0 MiB                           self.attach_file_event(None, 'nfe', 'xml')
   172    169.7 MiB      0.0 MiB                           self.attach_file_event(None, None, 'pdf')
   173                                         except Exception as e:
   174                                             _logger.error(e.message, exc_info=True)
   175                                             vals = {
   176                                                 'type': '-1',
   177                                                 'status': '000',
   178                                                 'response': 'response',
   179                                                 'company_id': self.company_id.id,
   180                                                 'origin': '[NF-E]' + inv.internal_number,
   181                                                 'file_sent': 'False',
   182                                                 'file_returned': 'False',
   183                                                 'message': 'Erro desconhecido ' + str(e),
   184                                                 'state': 'done',
   185                                                 'document_event_ids': inv.id
   186                                             }
   187                                             results.append(vals)
   188                                         finally:
   189    169.7 MiB     -0.0 MiB                   for result in results:
   190    169.7 MiB      0.0 MiB                       if result['type'] == '0':
   191    169.7 MiB      0.0 MiB                           event_obj.write(result)
   192                                                 else:
   193    169.7 MiB      0.0 MiB                           event_obj.create(result)
   194                             
   195    169.7 MiB      0.0 MiB                   self.write({
   196    169.7 MiB      0.0 MiB                       'nfe_status': protNFe["status_code"] + ' - ' +
   197    169.7 MiB      0.0 MiB                       protNFe["message"],
   198    169.7 MiB      0.0 MiB                       'nfe_date': datetime.datetime.now(),
   199    169.7 MiB      0.0 MiB                       'state': protNFe["state"],
   200    169.7 MiB      0.0 MiB                       'nfe_protocol_number': protNFe["nfe_protocol_number"],
   201                                             })
   202    169.7 MiB      0.0 MiB           return True

@mileo
Copy link
Member

mileo commented Dec 15, 2015

@rvalyi Não sou especialista nessas analises mas com um teste rápido aqui não vi o PySPED alocando muita memoria não.

Inclusive removendo a geração do Danfe apos a transmissão e a opção de salvar aquivos

@danimaribeiro
Copy link
Contributor

E essa linha aqui:

143 165.0 MiB 0.7 MiB nfe.append(nfe_obj.set_xml(arquivo))
144 169.7 MiB 4.7 MiB for processo in send(inv.company_id, nfe):

A segunda coluna me parece ser o incremento de memória né?

@mileo
Copy link
Member

mileo commented Dec 15, 2015

Sim, incremento de memoria

@mileo
Copy link
Member

mileo commented Dec 15, 2015

143 134.5 MiB 8.6 MiB nfe.append(nfe_obj.set_xml(arquivo))
143 165.0 MiB 0.7 MiB nfe.append(nfe_obj.set_xml(arquivo))

Realizei vários testes, mas não esta me parecendo algo exato

@danimaribeiro
Copy link
Contributor

Que profiler é esse, pycharm?

@rvalyi
Copy link
Member Author

rvalyi commented Dec 15, 2015

na verdade nao falei que ele usaria muita memoria, so me parece que ele nao estaria liberando tudo o que aloca e a cada nota ele usaria mais. Eu precisaria gastar um tempo com o profiler na instancia onde eu observei isso (ate esgotar a RAM varias vezes no caso), infelizmente tou ocupado com algumas outras coisas no momento... Mas enfim certeza que esse levantamento do uso da memoria servira o dia que mergulhar nisso de novo.

@mileo
Copy link
Member

mileo commented Dec 15, 2015

@rvalyi Pior q era isso mesmo! Tava com tanto sono hoje a tarde q nem me liguei. Vou continuar com o profile ativo nos testes da NT003 e verificar se a memoria sobe ao longo do tempo. []s

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants