Skip to content

Evita a sincronização de dados de journal com dados do core desnecessariamente - #1028

Open
robertatakenaka wants to merge 4 commits into
scieloorg:mainfrom
robertatakenaka:fix_journal_data_core_synch_timing
Open

Evita a sincronização de dados de journal com dados do core desnecessariamente#1028
robertatakenaka wants to merge 4 commits into
scieloorg:mainfrom
robertatakenaka:fix_journal_data_core_synch_timing

Conversation

@robertatakenaka

Copy link
Copy Markdown
Member

O que esse PR faz?

Introduz o parâmetro force_core_sync para desacoplar o controle de
resincronização com o SciELO Core do parâmetro genérico force_update.
Garante ainda que periódicos com journal.core_synchronized=False sejam
sempre 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, adiciona
rastreabilidade 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 de core_synchronized), seguido
de proc/tasks.py — especialmente a nova condição
query_by_status |= Q(journal__core_synchronized=False) e o trecho de
decisão entre fetch_and_create_journal e
journal_proc.create_or_update_item em
task_migrate_and_publish_journals_by_collection.

Como este poderia ser testado manualmente?

  1. Rodar a task sem force_core_sync, com um filtro de status que não
    inclua um periódico específico com core_synchronized=False, e
    confirmar que esse periódico é processado mesmo assim.
  2. Rodar com force_core_sync=True e confirmar que todos os periódicos do
    filtro passam por fetch_and_create_journal, com
    detail["journal_data_source"] == "core data".
  3. Rodar com um periódico já sincronizado (core_synchronized=True) e
    confirmar que ele segue o fluxo journal_proc.create_or_update_item
    (detail["journal_data_source"] == "classic website data").
  4. Rodar com force_update=True (sem definir os novos parâmetros
    explicitamente) 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

…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.
@robertatakenaka
robertatakenaka requested a review from patymori July 25, 2026 15:50

@patymori patymori left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Testes automatizados

👎 Testes unitários executados, erros não relacionados ao PR.

Inclusão dos novos kwargs na tarefa migrate_and_publish_journals

Image

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:

Image

Evento registrado em JournalProc (único evento novo):

Image

Journal com core_sincronized = True

Image

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:

Image

❌ 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:

Image

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:

Image

Todos os periódicos do filtro com os eventos registrados:

Image Image

❌ 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:

Image

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.

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

Successfully merging this pull request may close these issues.

2 participants