Skip to content

Divide task dispatch articles em duas task dispatch articles e task harvest articles - #1460

Open
robertatakenaka wants to merge 11 commits into
scieloorg:mainfrom
robertatakenaka:divide_task_dispatch_articles_em_duas_task_dispatch_articles_e_task_harvest_articles
Open

Divide task dispatch articles em duas task dispatch articles e task harvest articles#1460
robertatakenaka wants to merge 11 commits into
scieloorg:mainfrom
robertatakenaka:divide_task_dispatch_articles_em_duas_task_dispatch_articles_e_task_harvest_articles

Conversation

@robertatakenaka

Copy link
Copy Markdown
Member

O que esse PR faz?

Refatora o pipeline de seleção e processamento de artigos:

  • Reescreve ArticleIteratorBuilder (article/controller.py), removendo o
    __iter__ único e substituindo por métodos explícitos from_pid_provider,
    from_article, from_article_source e from_harvest, cada um recebendo
    o filtro exclusivo da sua fonte.
  • Desacopla ArticleSource do modelo legado AMArticle: remove o FK
    am_article e adiciona os campos pid e collection (article/models.py
    • migração correspondente).
  • Simplifica add_pid_provider/request_xml/request_pid, reduzindo
    logging redundante e centralizando o tratamento de erro.
  • Divide task_dispatch_articles em duas tasks: task_harvest_articles
    (coleta externa via OPAC/ArticleMeta) e task_dispatch_articles
    (despacho sequencial de article_source → pid_provider → article).
  • Ajusta article/wagtail_hooks.py aos novos campos de ArticleSource.
  • Atualiza bigbang/tasks_scheduler.py para agendar as novas tasks e
    remover as obsoletas.
  • Simplifica Journal.select_items (journal/models.py), removendo o
    registro de UnexpectedEvent para queryset vazio.
  • Documenta e agrupa os status de PidProviderXML em
    pid_provider/choices.py.
  • Adiciona testes unitários: test_article_iterator_builder.py e
    test_article_pipeline.py, com mocks (unittest.mock) e supressão de
    logging do OpenSearch.

Onde a revisão poderia começar?

Sugiro começar por article/controller.py (o ArticleIteratorBuilder
reescrito), depois article/models.py (mudanças em ArticleSource), e
por fim article/tasks.py para ver como as novas tasks consomem o builder.
Os testes em article/tests/ ajudam a entender o comportamento esperado
de cada método.

Como este poderia ser testado manualmente?

  1. Aplicar a migração 0050_remove_articlesource_am_article_and_more em
    ambiente de homologação e conferir que os dados existentes de
    ArticleSource não foram perdidos (verificar pid/collection
    preenchidos onde aplicável).
  2. Rodar task_harvest_articles manualmente com uma coleção pequena e
    confirmar que os documentos coletados disparam
    task_process_article_pipeline corretamente.
  3. Rodar task_dispatch_articles e verificar nos logs/Flower que cada
    artigo é despachado uma única vez, mesmo quando elegível por mais de
    uma fonte (article_source, pid_provider, article).
  4. Rodar a suíte de testes:
make django_bash
 python manage.py test article.tests --keepdb
  1. Conferir no admin/Wagtail (ArticleSourceSnippetViewSet) que as
    colunas e filtros exibem pid/collection no lugar de am_article.

Algum cenário de contexto que queira dar?

Esta é uma refatoração estrutural sem mudança de escopo funcional externo
esperado — o objetivo é eliminar duplicidade de processamento e reduzir
acoplamento com AMArticle. A migração remove um FK, então é importante
validar em homologação antes de subir para produção. Nenhuma nova
dependência externa foi introduzida.

Screenshots

N/A (mudanças de backend/pipeline, sem impacto visual além do admin
listado acima).

Quais são os tickets relevantes?

  • Relacionado à issue de refatoração do pipeline de artigos (ver issue
    vinculada acima).

Referências

  • N/A

Segurança da informação (NSI.04)

Seção obrigatória, referência NSI.04 - Norma de Desenvolvimento Seguro.

  • Manipula dados sensíveis/pessoais (LGPD)?
    [ ] Sim [x] Não
    N/A — os campos alterados (pid, collection) são identificadores
    bibliográficos/institucionais, não dados pessoais.

  • 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
    Nenhuma dependência de terceiros foi adicionada, atualizada ou removida.

  • Validado pelo pipeline de segurança (SonarQube/Trivy)?
    [ ] Sim [ ] Não — justificar
    Link do job: (preencher com o link do pipeline após execução)

  • Concatena/monta/executa comandos SQL, HTML ou JS a partir de entrada externa?
    [ ] Sim [x] Não
    Todas as consultas usam o ORM do Django (filtros via Q/F e kwargs),
    sem SQL bruto ou interpolação de entrada externa.

  • Expõe novos endpoints, telas ou serviços?
    [ ] Sim [x] Não
    Não há novos endpoints; apenas ajuste de colunas/filtros no admin
    Wagtail existente (ArticleSourceSnippetViewSet).

  • Algum segredo/senha/chave/token adicionado ao código-fonte?
    [ ] Sim [x] Não

@robertatakenaka
robertatakenaka requested a review from patymori July 27, 2026 22:45
@robertatakenaka
robertatakenaka force-pushed the divide_task_dispatch_articles_em_duas_task_dispatch_articles_e_task_harvest_articles branch from 0830753 to ac10d72 Compare July 29, 2026 13:03
#### Propósito
Deixar explícito o significado de cada status de PidProviderXML e oferecer
agrupamentos reutilizáveis para os filtros do pipeline de artigos.

#### Solução técnica
- Adicionado comentário explicativo a cada constante PPXML_STATUS_*.
- Criadas as listas PPXML_STATUS_TO_CREATE_OR_UPDATE_ARTICLE_SOURCE e
  PPXML_STATUS_TO_IGNORE, consumidas por ArticleIteratorBuilder.from_article_source
  em article/controller.py.
…ovider

#### Propósito
Remover a dependência de ArticleSource no modelo legado AMArticle e tornar
o fluxo de obtenção de XML/PID mais direto, com menos logging redundante
e menos chamadas save() implícitas.

#### Solução técnica
- Substituído o FK am_article por pid (CharField) e collection (FK para
  Collection) em ArticleSource.
- create/create_or_update reescritos para usar pid/collection/detail;
  extraído o método update() que aplica mudanças incrementais e informa
  se algo mudou.
- add_pid_provider reestruturado com try/except mais enxuto: retorna
  bool `changed`, delega erros a mark_as_xml_error/mark_as_url_error/
  mark_as_error e evita salvar o objeto múltiplas vezes.
- request_xml e request_pid simplificados; erros de PID agora levantam
  UnableToRegisterPIDError diretamente, sem lista `detail` acumulada
  manualmente.
- Adicionados ArticleSource.get_pid_provider_xml_id() e a propriedade
  ContribPerson.data.
- Import ajustado para `from pid_provider import choices as
  pid_provider_choices` e removidos logging.info/logging.exception de
  baixo valor ao longo do arquivo.
…eSource

#### Propósito
Persistir no banco de dados as alterações do modelo ArticleSource:
remoção do FK am_article e inclusão dos campos pid e collection.

#### Solução técnica
Migração gerada automaticamente (makemigrations) refletindo as mudanças
já aplicadas em article/models.py: RemoveField(am_article), AddField(pid),
AddField(collection) com FK para Collection.
…ource

#### Propósito
Refletir no admin/Wagtail a remoção do FK am_article e a introdução dos
campos pid/collection em ArticleSource.

#### Solução técnica
Substituído am_article por url/pid/collection em list_display,
list_filter e search_fields de ArticleSourceSnippetViewSet.
…ryset vazio

#### Propósito
Uma consulta sem resultados não é necessariamente um erro; registrar
UnexpectedEvent para esse caso gerava ruído desnecessário.

#### Solução técnica
- Removida a criação de UnexpectedEvent.create quando o queryset filtrado
  vem vazio em Journal.select_items.
- Journal.get_ids ajustado para encadear select_items().values_list()
  diretamente, sem variável intermediária.
…radores

#### Propósito
O antigo __iter__ disparava todos os iteradores simultaneamente, permitindo
que o mesmo artigo/pp_xml_id fosse selecionado por mais de uma fonte na
mesma execução. É preciso que quem chama escolha explicitamente uma fonte.

#### Solução técnica
- Removido __iter__; __init__ mantém apenas os filtros comuns a mais de
  uma fonte (usuário, coleção/periódico, datas/anos, force_update,
  parâmetros de harvest).
- Métodos privados _iter_from_* convertidos em métodos públicos from_*,
  cada um recebendo como parâmetro o filtro exclusivo da sua fonte
  (proc_status_list, data_status_list, article_source_status_list).
- from_pid_provider reescrito para resolver ISSNs via SciELOJournal e
  retornar apenas dicts prontos via values(pp_xml_id=F("id")).distinct(),
  sem instanciar os objetos completos.
- from_article_source e from_harvest movidos para o builder (antes viviam
  em ArticleSource/Collection), com a mesma otimização via values().
- Removidos os contadores internos (_iter_from_*_count) e logging.info
  intermediário.
- export_article_to_articlemeta passa a levantar ValueError quando não há
  legacy_keys, em vez de registrar UnexpectedEvent e retornar silenciosamente.
- Corrigido bug: uso de pub_year trocado por pub_date_year em
  bulk_export_articles_to_articlemeta.
- Removido bloco de código comentado (get_pp_xml_ids/select_pp_xml).
#### Propósito
Cobrir com testes o novo comportamento de ArticleIteratorBuilder após a
remoção do __iter__ único e a introdução dos métodos from_pid_provider,
from_article, from_article_source e from_harvest, garantindo que cada
fonte seja testada isoladamente e não haja sobreposição de seleção.

#### Solução técnica
Suite baseada em unittest com mocks (unittest.mock) para isolar consultas
ao banco/Journal/SciELOJournal/PidProviderXML/ArticleSource, cobrindo:
- filtros aplicados por from_pid_provider (ISSNs, datas, status);
- comportamento de from_article com/sem pp_xml existente;
- filtros de status em from_article_source, incluindo o caso force_update;
- montagem de kwargs em from_harvest via harvester mockado.
Supressão de ruído de logging do OpenSearch configurada no setUp para
manter a saída de testes limpa.
…orBuilder

#### Propósito
Separar o fluxo de harvest (coleta externa via OPAC/ArticleMeta) do fluxo
de despacho das fontes internas pendentes (article_source, pid_provider,
article), e ajustar as tasks ao novo builder com métodos from_* explícitos.

#### Solução técnica
- Nova task task_harvest_articles, isolando builder.from_harvest().
- task_dispatch_articles reescrita para iterar sequencialmente
  from_article_source, from_pid_provider e from_article; parâmetros de
  harvest (limit/timeout/opac_url/stop) removidos dessa task, pois agora
  pertencem só a task_harvest_articles.
- task_process_article_pipeline ajustada: não depende mais de
  AMArticle.create_or_update; ArticleSource.create_or_update passa a
  receber collection/pid/detail; pp_xml_id obtido via
  article_source.get_pid_provider_xml_id().
- Removido parâmetro `item` indevido em UnexpectedEvent.create de
  task_export_article_to_articlemeta e diversos logging.info de baixo valor.
…correlatas

#### Propósito
Validar os três fluxos de entrada do pipeline (xml_url, article_source_id,
pp_xml_id) após a reescrita de task_process_article_pipeline, e cobrir
task_harvest_articles e a nova task_dispatch_articles sequencial.

#### Solução técnica
Testes com unittest.mock isolando ArticleSource.create_or_update,
PidProviderXML.get_by_id, Article.get_or_create e as chamadas
task_export_article_to_articlemeta.delay/task_process_article_pipeline.delay,
verificando:
- levantamento de ValueError quando faltam collection_acron/pid com xml_url;
- obtenção correta de pp_xml_id via article_source.get_pid_provider_xml_id();
- que export_to_articlemeta só dispara quando article.is_classic_public e
  article.valid são verdadeiros;
- que task_dispatch_articles percorre article_source, pid_provider e
  article sem duplicar despachos;
- registro de UnexpectedEvent em caso de exceção nas tasks.
Logging do OpenSearch suprimido no setUp para reduzir ruído nos testes.
…ticles

#### Propósito
Registrar o agendamento da nova task_harvest_articles e ajustar
task_dispatch_articles ao novo conjunto de parâmetros, além de limpar
tasks obsoletas do scheduler.

#### Solução técnica
- Adicionada schedule_task_harvest_articles (cron diário às 02:01).
- schedule_task_dispatch_articles ajustada para os novos kwargs
  (article_source_status_list/proc_status_list/data_status_list, sem
  limit/timeout/opac_url) e horário movido para 02:16.
- Incluídas na lista de tasks a remover: task_dispatch_articles antiga e
  as variantes por fonte (task_dispatch_articles_from_pid_provider,
  _from_article, _from_article_source), substituídas pelas duas tasks
  especializadas.
…or url

#### Propósito
1. Refletir no painel Wagtail de ArticleSource a remoção do FK am_article,
   exibindo collection e pid em seu lugar.
2. Simplificar ArticleAvailability.get, já que url é único (unique=True)
   e por si só já identifica o registro, tornando o parâmetro article
   redundante.

#### Solução técnica
- panels de ArticleSource: substituído FieldPanel("am_article", read_only=True)
  por FieldPanel("collection", read_only=True) e FieldPanel("pid", read_only=True).
- ArticleAvailability.get(cls, url) agora recebe apenas url; create() e
  create_or_update() ajustados para chamar cls.get(url) sem o argumento
  article, aproveitando o índice único já existente em url.
@robertatakenaka
robertatakenaka force-pushed the divide_task_dispatch_articles_em_duas_task_dispatch_articles_e_task_harvest_articles branch from ac10d72 to 97b2303 Compare July 30, 2026 13:42
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.

1 participant