Open rvalyi opened 8 years ago
Qual a configuração da maquina?
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.
O limite de memoria do worker ta em quanto?
@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.
@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.
@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.
Filename: /home/mileo/Projects/odoo/odoo8-oca/parts/l10n_br/odoo-brazil-eletronic-documents/nfe/sped/nfe/processing/processor.py
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
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
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
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
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
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
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
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
@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
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é?
Sim, incremento de memoria
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
Que profiler é esse, pycharm?
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.
@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
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...