Skip to content

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

Open
robertatakenaka wants to merge 18 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 18 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

@patymori patymori left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Migrações do article

Image

Article Sources

Image Image Image

Comment thread article/controller.py Outdated

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Atualizar documentação com as exceções possíveis no lugar de "False".

@patymori patymori left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Resultado da execução da suite de testes:

Image Image Image

Comment on lines +136 to +148
kwargs=dict(
username=username,
user_id=None,
collection_acron_list=None,
from_date=None,
until_date=None,
force_update=False,
export_to_articlemeta=False,
auto_solve_pid_conflict=False,
limit=None,
timeout=None,
opac_url=None,
),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Aqui não deveria ter todos os parâmetros de task_harvest_article?

Comment thread article/tasks.py
exc_type, exc_value, exc_traceback = sys.exc_info()
UnexpectedEvent.create(
action="task_harvest_articles",
item=item,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

❌ esta referencia à variável item dá erro, pois a declaração dela está dentro do try

@patymori patymori left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Execução de task_harvest_articles manualmente com coleção pequena

Image

✔️ documentos coletados disparam task_process_article_pipeline

Execução de task_dispatch_articles

kwargs para execução:

{"username": "scielo", "user_id": null, "collection_acron_list": ["cic"], "journal_acron_list": null, "from_pub_year": "2026", "until_pub_year": "2026", "from_date": null, "until_date": null, "force_update": false, "export_to_articlemeta": false, "auto_solve_pid_conflict": false, "article_source_status_list": ["completed"], "proc_status_list": ["DONE"], "data_status_list": ["completed"]}

❌ A seguinte exceção ocorreu no log do conteiner:

 INFO 2026-07-31 16:06:28,025 strategy 11 138039802255168 Task article.tasks.task_dispatch_articles[a4834b9d-8761-4c48-923c-c20a2dc50a13] received
 ERROR 2026-07-31 16:06:28,082 models 63 138039802255168 Cannot resolve keyword 'pub_date_year' into field. Choices are: aop_pid, article, article_pub_year, articlesource, available_since, collections, created, creator, creator_id, current_version, current_version_id, elocation_id, events, fixpidv2, fpage, fpage_seq, id, issn_electronic, issn_print, lpage, main_doi, number, origin_date, other_pid, other_pid_count, pkg_name, proc_status, pub_year, registered_in_core, suppl, updated, updated_by, updated_by_id, v2, v3, volume, xmlversion, z_collab, z_links, z_partial_body, z_surnames
 Traceback (most recent call last):
   File "/app/article/tasks.py", line 842, in task_dispatch_articles
     for item_kwargs in item_iterator:
   File "/app/article/controller.py", line 426, in from_pid_provider
     PidProviderXML.objects.filter(q, **filters)
   File "/usr/local/lib/python3.11/site-packages/django/db/models/manager.py", line 87, in manager_method
     return getattr(self.get_queryset(), name)(*args, **kwargs)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   File "/usr/local/lib/python3.11/site-packages/django/db/models/query.py", line 1493, in filter
     return self._filter_or_exclude(False, args, kwargs)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   File "/usr/local/lib/python3.11/site-packages/django/db/models/query.py", line 1511, in _filter_or_exclude
     clone._filter_or_exclude_inplace(negate, args, kwargs)
   File "/usr/local/lib/python3.11/site-packages/django/db/models/query.py", line 1518, in _filter_or_exclude_inplace
     self._query.add_q(Q(*args, **kwargs))
   File "/usr/local/lib/python3.11/site-packages/django/db/models/sql/query.py", line 1646, in add_q
     clause, _ = self._add_q(q_object, can_reuse)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   File "/usr/local/lib/python3.11/site-packages/django/db/models/sql/query.py", line 1678, in _add_q
     child_clause, needed_inner = self.build_filter(
                                  ^^^^^^^^^^^^^^^^^^
   File "/usr/local/lib/python3.11/site-packages/django/db/models/sql/query.py", line 1526, in build_filter
     lookups, parts, reffed_expression = self.solve_lookup_type(arg, summarize)
                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   File "/usr/local/lib/python3.11/site-packages/django/db/models/sql/query.py", line 1333, in solve_lookup_type
     _, field, _, lookup_parts = self.names_to_path(lookup_splitted, self.get_meta())
                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   File "/usr/local/lib/python3.11/site-packages/django/db/models/sql/query.py", line 1806, in names_to_path
     raise FieldError(
 django.core.exceptions.FieldError: Cannot resolve keyword 'pub_date_year' into field. Choices are: aop_pid, article, article_pub_year, articlesource, available_since, collections, created, creator, creator_id, current_version, current_version_id, elocation_id, events, fixpidv2, fpage, fpage_seq, id, issn_electronic, issn_print, lpage, main_doi, number, origin_date, other_pid, other_pid_count, pkg_name, proc_status, pub_year, registered_in_core, suppl, updated, updated_by, updated_by_id, v2, v3, volume, xmlversion, z_collab, z_links, z_partial_body, z_surnames
 INFO 2026-07-31 16:06:28,140 base 63 138039750842112 POST http://opensearch:9200/core-logs-dev-2026.07.31/_doc [status:201 request:0.041s]

@pitangainnovare pitangainnovare self-assigned this Aug 3, 2026
#### Propósito
Evitar perda de dados na migração que desacopla ArticleSource de
AMArticle, preenchendo os novos campos pid e collection antes da remoção
do relacionamento legado.

#### Solução técnica
- Reordena as operações para adicionar pid e collection antes de remover
  am_article.
- Adiciona uma operação RunPython que copia pid e collection do AMArticle
  associado.
- Usa PidProviderXML.v2 como fallback de pid e sua única collection como
  fallback de collection quando os dados legados não estão disponíveis.
- Processa o backfill em lotes de 1000 registros com bulk_update.
- Adiciona a dependência da migração
  pid_provider.0012_pidproviderxml_collections.
- Mantém a operação reversa como noop, pois o relacionamento am_article
  não existe mais no estado final da migração.
#### Propósito
Corrigir falhas na seleção de artigos causadas pelo uso de campos de ano
incompatíveis com cada modelo e por um relacionamento inexistente na
consulta de ArticleSource.

#### Solução técnica
- Usa pub_year nos filtros aplicados a PidProviderXML.
- Usa pub_date_year nos filtros aplicados a Article.
- Remove o select_related de pid_provider da consulta de ArticleSource,
  pois esse relacionamento não existe no modelo.
- Atualiza os testes do ArticleIteratorBuilder para refletir os campos e
  a cadeia de consulta corretos.
#### Propósito
Evitar que falhas do pipeline sejam ocultadas ou substituídas por erros
secundários e melhorar o contexto registrado nos eventos inesperados.

#### Solução técnica
- Inicializa item e params antes da obtenção do usuário nas tasks de
  coleta e distribuição, preservando a exceção original em caso de falha.
- Inclui filtros de ano, processamento, dados e ArticleSource no contexto
  registrado por task_dispatch_articles.
- Preenche action, item e detail no evento criado quando a exportação de
  um artigo para o ArticleMeta falha.
- Relança as exceções de task_process_article_pipeline depois de
  registrá-las, permitindo que o Celery sinalize corretamente a falha.
- Documenta os limites do tratamento de erros da exportação em lote.
- Atualiza os testes para validar o registro e a propagação das exceções.
#### Propósito
Manter a configuração da tarefa periódica alinhada à assinatura de
task_harvest_articles e permitir o uso de todos os controles disponíveis
na coleta.

#### Solução técnica
- Adiciona journal_acron_list aos argumentos configurados no agendador.
- Adiciona stop para permitir limitar o ponto de interrupção do fluxo.
- Mantém ambos com valor padrão nulo, preservando o comportamento atual
  quando não forem informados.
#### Propósito
Evitar perda de registros legados e corrigir estados inconsistentes
identificados durante a execução completa do dispatch de artigos.

#### Solução técnica
- Remove de BaseLegacyRecord.get a exclusão automática de registros sem
  url e data, preservando AMArticles gerados pelo pipeline.
- Faz ArticleSource retornar de NOT_PUBLIC para PENDING quando a fonte
  volta a ser identificada como pública.
- Chama mark_as_available quando o artigo já possui disponibilidades,
  garantindo a atualização de seu estado para PUBLIC.
- Adiciona testes de regressão para a preservação de AMArticle e para as
  transições de estado de ArticleSource e Article.
@pitangainnovare

Copy link
Copy Markdown

Continuei a validação da PR #1460 executando o pipeline de artigos de ponta a ponta, desde a coleta até a atualização de disponibilidade. Além de atender aos comentários da revisão, essa execução revelou algumas regressões que não apareciam nos testes isolados.

Contexto e relação com outras PRs

A PR #1460 continua a consolidação do pipeline iniciada pela PR #1402, separando agora a coleta externa (task_harvest_articles) do despacho das fontes internas (task_dispatch_articles) e desacoplando ArticleSource de AMArticle.

Ela também precisa preservar comportamentos introduzidos pela PR #1453, especialmente filtro por periódico, stop e o estado NOT_PUBLIC. A PR #1404 ainda está aberta e possui sobreposição nos parâmetros verify, issn e stop; provavelmente precisará ser conciliada ou atualizada depois desta PR.

Alterações acrescentadas nesta continuação

  1. Migração segura de ArticleSource

A migração original removia am_article sem copiar seus dados para os novos campos. Ela agora:

  • adiciona pid e collection antes de remover o relacionamento;
  • copia os valores do AMArticle associado quando ele existe;
  • usa PidProviderXML.v2 como fallback de pid;
  • usa a coleção do PidProviderXML somente quando existe exatamente uma;
  • processa o backfill em lotes de 1.000 registros;
  • não escolhe arbitrariamente uma coleção quando há ambiguidade.

A análise em homologação encontrou 7.385 ArticleSource, apesar de o ambiente possuir aproximadamente 590 mil Article. Havia 7.362 vínculos com PidProviderXML, todos com v2; 7.343 tinham uma única coleção e 19 tinham duas. A projeção é preencher 7.362 PIDs e 7.343 coleções, preservando NULL nos casos sem fonte ou com coleção ambígua.

  1. Correções no ArticleIteratorBuilder
  • PidProviderXML passa a ser filtrado por pub_year.
  • Article passa a ser filtrado por pub_date_year.
  • Foi removido o select_related("pid_provider") de ArticleSource, pois esse relacionamento não existe.

Isso cobre também o FieldError de pub_date_year registrado na revisão durante a execução de task_dispatch_articles.

  1. Comentários da revisão

Foram atendidos os três apontamentos formais:

  • a documentação de bulk_export_articles_to_articlemeta agora descreve os retornos e as exceções;
  • o agendamento de task_harvest_articles agora contém journal_acron_list e stop;
  • item e params são inicializados antes do bloco que pode falhar, evitando que UnboundLocalError esconda a exceção original.

O contexto registrado em UnexpectedEvent também foi completado, e task_process_article_pipeline passou a relançar a exceção depois do registro para que o Celery sinalize a falha corretamente.

  1. Regressões encontradas no dispatch real

O teste integrado revelou três problemas adicionais:

  • BaseLegacyRecord.get apagava todos os registros sem url e data. Essa limpeza veio da PR #1260, onde esses registros eram tratados como órfãos, mas no pipeline atual ela apagava AMArticle válidos recém-gerados. A exclusão global foi removida.
  • A transição NOT_PUBLIC → PENDING, prevista pela PR feat: adiciona status NOT_PUBLIC para evitar requisições a documentos despublicados #1453 quando um documento volta a ser público, havia se perdido na refatoração de ArticleSource.update; ela foi restaurada.
  • Article.check_availability retornava True quando já havia disponibilidades, mas não chamava mark_as_available, deixando o artigo em COMPLETED. Agora ele volta corretamente para PUBLIC.

Foram adicionados testes de regressão para os três casos.

Validação

Foi executada uma coleta limitada a três documentos. Depois de carregar o fascículo ausente, o dispatch concluiu o fluxo, preservou os três AMArticle, deixou os três PidProviderXML em DONE, associou cinco URLs de disponibilidade a cada artigo e não criou novos UnexpectedEvent. O caso de estado COMPLETED também foi reproduzido e passou a terminar em PUBLIC.

Os testes direcionados do iterator, das tasks, da exportação e dos modelos passaram localmente, incluindo o teste com banco para garantir que AMArticle.get não apague registros. O diff também passou em git diff --check.

As alterações foram separadas em cinco commits:

  • 544ea9d0 — preservação de pid e collection na migração;
  • 66de6c73 — filtros e consultas do ArticleIteratorBuilder;
  • 90e1d667 — tratamento de falhas das tasks;
  • 2044adc9 — parâmetros do agendador;
  • 824c9a3b — regressões de processamento e publicação.

Estado atual do CI

Os checks do GitGuardian e Snyk passaram. O job pytest do GitHub Actions falhou antes de executar os testes porque o runner não possui o comando docker-compose. O linter falhou porque pre-commit --all-files tentou reformatar muitos arquivos preexistentes fora do escopo desta PR. Esses dois pontos de infraestrutura/baseline ainda precisam ser avaliados; não correspondem às falhas funcionais reproduzidas e corrigidas nesta continuação.

#### Propósito
Restaurar a execução dos testes no GitHub Actions, cujo runner não
disponibiliza mais o comando legado docker-compose.

#### Solução técnica
Substitui as chamadas ao executável Docker Compose v1 pelo comando
docker compose, fornecido pelo plugin Compose v2 disponível no runner.
#### Propósito
Permitir que o usuário django do container inicialize as configurações
da aplicação durante as migrações e os testes no GitHub Actions.

#### Solução técnica
Cria o diretório logs no checkout com UID e GID 1000, correspondentes ao
usuário do container, antes de montar o repositório em /app.
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.

3 participants