Evita a sincronização de dados de journal com dados do core desnecessariamente - #1028
Evita a sincronização de dados de journal com dados do core desnecessariamente#1028robertatakenaka wants to merge 4 commits into
Conversation
…te_or_update Propósito: Garantir que, após a criação/atualização bem-sucedida de um Journal via create_or_update_journal, o campo journal.core_synchronized seja definido como True. Sem essa marcação, a lógica downstream (proc/tasks.py) não conseguia distinguir periódicos já sincronizados com o Core dos que ainda precisam de sincronização. Solução técnica: Adicionada atribuição journal.core_synchronized = True e journal.save() logo após a criação/atualização do journal, antes do retorno da função.
…ted_journal Propósito: Alinhar o registro de eventos inesperados (UnexpectedEvent) ao padrão action/item já utilizado em outros pontos do código (ex: proc/tasks.py), substituindo o dicionário verboso de detail por campos padronizados. Solução técnica: Removido o dict detail com task/user_id/username/collection/pid/force_update. Adicionados os parâmetros action="proc.sources.classic_website.create_or_update_migrated_journal" e item=scielo_issn diretamente na chamada de UnexpectedEvent.create.
…rnals nao sincronizados com o Core
Propósito:
Desacoplar o controle de resincronização com o SciELO Core do parâmetro
genérico force_update, introduzindo force_core_sync como controle
independente. Além disso, garantir que periódicos ainda não sincronizados
com o Core (journal.core_synchronized=False) sejam sempre incluídos no
processamento, mesmo quando não correspondem ao filtro de status
informado — evitando que fiquem "presos" sem sincronização.
Solução técnica:
- Adicionado o parâmetro force_core_sync em task_migrate_and_publish_journals
e em task_migrate_and_publish_journals_by_collection, propagado via .delay().
- Compatibilidade retroativa: force_import_acron_id_file e force_core_sync
também são ativados quando force_update=True (force_x = force_x or force_update).
- create_or_update_migrated_journal passa a receber force_import_acron_id_file
no lugar de force_update.
- Quando force_core_sync=False, query_by_status passa a incluir via OR a
condição Q(journal__core_synchronized=False), garantindo que periódicos
não sincronizados sejam processados independente do filtro de status.
- Removida a variável completed (não utilizada) e refeita a decisão entre
fetch_and_create_journal (quando force_core_sync ou journal ainda não
sincronizado) e journal_proc.create_or_update_item (fluxo padrão via
classic website).
- Adicionados registros de rastreabilidade em detail: journal_data_source
("core data" ou "classic website data") e sinalização de agendamento de
task_publish_journal (QA e público).
- Corrigido item de log em UnexpectedEvent.create, que referenciava
journal_acron fora de escopo; agora usa apenas collection_acron.
…agendador Propósito: Disponibilizar os novos parâmetros granulares de controle (force_import_acron_id_file e force_core_sync), introduzidos em proc/tasks.py, na tarefa agendada de migração e publicação de periódicos, para permitir execuções manuais ou agendadas com esse nível de controle. Solução técnica: Adicionados force_import_acron_id_file=False e force_core_sync=False aos kwargs default de _schedule_migrate_and_publish_journals.
patymori
left a comment
There was a problem hiding this comment.
Testes automatizados
👎 Testes unitários executados, erros não relacionados ao PR.
Inclusão dos novos kwargs na tarefa migrate_and_publish_journals
Execução de migrate_and_publish_journals sem force_core_sync, sem periódico específico
✔️ Havia 1 periódico com core_synchronized=False. Resultado após execução da tarefa:
Evento registrado em JournalProc (único evento novo):
Journal com core_sincronized = True
Execução de migrate_and_publish_journals com force_core_sync=True, sem periódico específico
❌ Nenhum periódico foi processado. Resultado da tarefa:
❌ Nenhum periódico passou pelo filtro fetch_and_create_journal, com
detail["journal_data_source"] == "core data". O registro anterior permaneceu como estava.
Execução de migrate_and_publish_journals com force_core_sync=False e True, com periódico específico já sincronizado
❌ Nenhum periódico foi processado, independente do force_core_sync. De acordo com a descrição do teste, não segue o fluxo journal_proc.create_or_update_item
(detail["journal_data_source"] == "classic website data").
Resultado da tarefa:
Execução de migrate_and_publish_journals com force_update=True, sem definir os novos parâmetros explicitamente
✔️ Periódicos processados com sucesso, seguindo o fluxo journal_proc.create_or_update_item
(detail["journal_data_source"] == "classic website data"). Resultado da tarefa:
Todos os periódicos do filtro com os eventos registrados:
❌ Um dos periódicos registrou um erro nos eventos do Journal Proc:
Event newest to oldest 1
Name
migrate journal
Creation date
July 30, 2026, 3:07 p.m.
Last update date
July 30, 2026, 3:07 p.m.
Completed
True
Detail
{
"journal_data_source": "classic website data"
}
---
Event newest to oldest 2
Name
create or update journal
Creation date
July 30, 2026, 3:07 p.m.
Last update date
July 30, 2026, 3:07 p.m.
Completed
False
Detail
{
"exception_message": "get() returned more than one OfficialJournal -- it returned 2!",
"exception_type": "<class 'journal.models.OfficialJournal.MultipleObjectsReturned'>",
"traceback": "[' File \"/app/proc/models.py\", line 790, in create_or_update_item\\n registered = callable_register_data(user, self, force_update, **kwargs)\\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\\n', ' File \"/app/migration/controller.py\", line 110, in create_or_update_journal\\n raise e\\n', ' File \"/app/migration/controller.py\", line 93, in create_or_update_journal\\n official_journal = OfficialJournal.create_or_update(user=user, **params)\\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\\n', ' File \"/app/journal/models.py\", line 195, in create_or_update\\n obj = cls.get(issn_print, issn_electronic, issnl)\\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\\n', ' File \"/app/journal/models.py\", line 176, in get\\n return cls.objects.get(issn_print=issn_print)\\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\\n', ' File \"/usr/local/lib/python3.11/site-packages/django/db/models/manager.py\", line 87, in manager_method\\n return getattr(self.get_queryset(), name)(*args, **kwargs)\\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\\n', ' File \"/usr/local/lib/python3.11/site-packages/django/db/models/query.py\", line 636, in get\\n raise self.model.MultipleObjectsReturned(\\n']"
}
---
Event newest to oldest 3
Name
create_or_update_journal
Creation date
July 30, 2026, 3:07 p.m.
Last update date
July 30, 2026, 3:07 p.m.
Completed
False
Detail
{
"event": "OfficialJournal.create_or_update",
"exception_message": "get() returned more than one OfficialJournal -- it returned 2!",
"exception_type": "<class 'journal.models.OfficialJournal.MultipleObjectsReturned'>",
"foundation_year": 1998,
"issn_electronic": null,
"issn_print": "1415-790X",
"title": "Revista Brasileira de Epidemiologia",
"title_iso": "Rev. bras. epidemiol",
"traceback": "[' File \"/app/migration/controller.py\", line 93, in create_or_update_journal\\n official_journal = OfficialJournal.create_or_update(user=user, **params)\\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\\n', ' File \"/app/journal/models.py\", line 195, in create_or_update\\n obj = cls.get(issn_print, issn_electronic, issnl)\\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\\n', ' File \"/app/journal/models.py\", line 176, in get\\n return cls.objects.get(issn_print=issn_print)\\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\\n', ' File \"/usr/local/lib/python3.11/site-packages/django/db/models/manager.py\", line 87, in manager_method\\n return getattr(self.get_queryset(), name)(*args, **kwargs)\\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\\n', ' File \"/usr/local/lib/python3.11/site-packages/django/db/models/query.py\", line 636, in get\\n raise self.model.MultipleObjectsReturned(\\n']"
}
Este é um periódico que tem 2 registros em Journal:
Neste caso, estes dois registros estão por testes. Mas no caso de coleções mantidas por SciELO BR, onde haverá migração de mesmas revistas para coleções diferentes, pode ser um problema.
O que esse PR faz?
Introduz o parâmetro
force_core_syncpara desacoplar o controle deresincronização com o SciELO Core do parâmetro genérico
force_update.Garante ainda que periódicos com
journal.core_synchronized=Falsesejamsempre incluídos no processamento (via OR na query de status), evitando
que fiquem sem sincronizar indefinidamente. Padroniza o registro de
eventos inesperados em
source_classic_website.py, adicionarastreabilidade da origem dos dados do journal e do agendamento de
publicação, e propaga o novo parâmetro até o agendador
(
bigbang/tasks_scheduler.py).Onde a revisão poderia começar?
Por
migration/controller.py(marcação decore_synchronized), seguidode
proc/tasks.py— especialmente a nova condiçãoquery_by_status |= Q(journal__core_synchronized=False)e o trecho dedecisão entre
fetch_and_create_journalejournal_proc.create_or_update_itememtask_migrate_and_publish_journals_by_collection.Como este poderia ser testado manualmente?
force_core_sync, com um filtro destatusque nãoinclua um periódico específico com
core_synchronized=False, econfirmar que esse periódico é processado mesmo assim.
force_core_sync=Truee confirmar que todos os periódicos dofiltro passam por
fetch_and_create_journal, comdetail["journal_data_source"] == "core data".core_synchronized=True) econfirmar que ele segue o fluxo
journal_proc.create_or_update_item(
detail["journal_data_source"] == "classic website data").force_update=True(sem definir os novos parâmetrosexplicitamente) e confirmar que ambos os comportamentos são ativados,
preservando compatibilidade com chamadas antigas.
Algum cenário de contexto que queira dar?
N/A
Screenshots
N/A (alteração apenas em lógica de backend/tasks).
Quais são os tickets relevantes?
#1027
Referências
Segurança da informação (NSI.04)
Manipula dados sensíveis/pessoais (LGPD)?
[ ] Sim [x] Não
(Os dados tratados são metadados de periódicos científicos — ISSN, acrônimo, coleção — sem dados pessoais de indivíduos.)
Altera autenticação, autorização, controle de acesso ou sessão?
[ ] Sim [x] Não
Introduz/atualiza/remove dependências de terceiros?
[ ] Sim [x] Não
Validado pelo pipeline de segurança (SonarQube/Trivy)?
[x] Sim, link do job:
[ ] Não aplicável — justificativa:
Concatena/monta/executa comandos SQL, HTML ou JS a partir de entrada externa?
[ ] Sim [x] Não
Expõe novos endpoints, telas ou serviços?
[ ] Sim [x] Não
Algum segredo/senha/chave/token adicionado ao código-fonte?
[ ] Sim [x] Não