+
    #qj(                        R t ^ RIt^ RIt^ RIHtHt ^ RIHt ^ RIH	t	H
t
HtHtHtHt ^ RIHtHt ^ RIHt ^ RIHt ^ RIHt ^ R	IHt ^ R
IHtHtHtHt ^ RIH t H!t!H"t" ]	! RR.R7      t#]PH                  ! ]%4      t&Rt'R*R R llt( ! R R]4      t) ! R R]4      t*]#PW                  R]
! ](4      .R7      ]! ^^^R7      3R R ll4       t,]#PW                  R]
! ](4      .R7      R R l4       t- ! R R]4      t. ! R  R!]4      t/]#PW                  R"]
! ](4      .R7      ]! ^^^R7      3R# R$ ll4       t0]#PW                  R%]
! ](4      .R7      R& R' l4       t1R( R) lt2R# )+u  Fila de conteúdo do registo comercial, servida a trabalhadores remotos.

Existe por uma razão só: **o que é escasso é o IP, não o processador.** O ritmo de
pedidos ao portal do IRN é limitado de propósito para não parecermos um ataque, e
esse tecto é por endereço. Um segundo trabalhador na mesma máquina não adianta
nada; um que saia por outra linha duplica a recolha sem que nenhum dos dois se
porte pior. Faltavam 805 mil actos por abrir e o CT sozinho levava sete dias e
meio.

**O trabalhador remoto só busca HTML.** Quem parseia e escreve arestas continua a
ser este processo, e isso não é detalhe de arrumação: no dia em que o
`REGISTRY_PARSE_VERSION` sobe — subiu hoje, para 2 — uma máquina lá fora com a
versão antiga escreveria dados desactualizados sem nada acusar. Assim o parser
está num sítio só, e o trabalhador não conhece a base de dados nem precisa de
credenciais dela.

A fila já estava preparada: `take_content` reclama com `FOR UPDATE SKIP LOCKED` e
devolve sozinha os actos reclamados há mais de 15 minutos. Um trabalhador que
morra a meio não perde nada — só atrasa aqueles actos um quarto de hora.
N)	AnnotatedAny)UUID)	APIRouterDependsHeaderHTTPExceptionQuerystatus)	BaseModelField)text)AsyncSession)get_session)app_settings)ingest_contentpublication_payloadrelease_contenttake_content)finish_queue_itemingest_publicationstake_from_queuez	/registryz
public-api)prefixtagsregistry_worker_keyc          	          V ^8  d   QhR\         \        \        \        4      3,          R\         \        R,          \        RR7      3,          RR/# )   sessionx_worker_keyNzX-Worker-Key)aliasreturn)r   r   r   r   strr   )formats   "app/api/v1/registry_work.py__annotate__r$   7   sM     T T|W[%99:TC$J^(DDET 
T    c                 0  "   \         P                  ! V \        4      G R j  xL
 pV'       g   \        \        P
                  RR7      hV'       d'   \        P                  ! V\        V4      4      '       g   \        \        P                  RR7      hR #  Lr5i)Nu4   recolha remota desligada: não há chave configurada)detailu   chave inválida)
r   getSETTING_KEYr   r
   HTTP_503_SERVICE_UNAVAILABLEsecretscompare_digestr!   HTTP_401_UNAUTHORIZED)r   r   expecteds   && r#   require_worker_keyr/   7   sr      "%%g{;;H//I
 	

 w55lCMRRF88ARSS  S <s   BBB"BABc                   <   a  ] tR t^Ft o RtRtRtRtV 3R ltRt	V t
R# )DeliveryNFc                r   < V ^8  d   Qh/ S[ ;R&   S[ R,          ;R&   S[ R,          ;R&   S[;R&   S[;R&   # )r   act_idNhtmlerrorversion_changedreleased)r!   bool)r"   __classdict__s   "r#   r$   Delivery.__annotate__F   sI     K 
* 
 :  !   r%    )__name__
__module____qualname____firstlineno__r4   r5   r6   r7   __annotate_func____static_attributes____classdictcell__r9   s   @r#   r1   r1   F   s&     D E "O H  r%   r1   c                   @   a  ] tR t^Ut o ]! ]^2R7      tV 3R ltRtV t	R# )	DeliverIndefault_factory
max_lengthc                6   < V ^8  d   Qh/ S[ S[,          ;R&   # r   results)listr1   )r"   r9   s   "r#   r$   DeliverIn.__annotate__U   s     (^H r%   r;   N
r<   r=   r>   r?   r   rL   rK   r@   rA   rB   rC   s   @r#   rE   rE   U   s     #DRHG  r%   rE   z/claim)dependencies)gelec                    V ^8  d   QhR\         \        \        \        4      3,          R\        R\
        \        \        3,          /# r   r   nr    r   r   r   r   intdictr!   r   )r"   s   "r#   r$   r$   Z   s=      |W[%99:
 
#s(^r%   c           
        "   \        WR7      G Rj  xL
 pV P                  4       G Rj  xL
  RV Uu. uF  pRVR,          R\        V4      /NK  	  up/#  LD L.u upi 5i)u
  Reclama actos da fila e devolve o que é preciso para os ir buscar.

O trabalhador recebe o `id` (para depois entregar) e a publicação tal como o
`content_for` a consome. Nada mais: nem NIPC para cruzar, nem o corpo de
outros actos, nem contexto da base de dados.
limitNactsr3   idpublication)r   commitr   )r   rT   batchacts   &&  r#   claimra   Y   sl      w00E
..

 s4y-1DS1IJ
  1
s0   A AA A	A AA A A z/deliverc                    V ^8  d   QhR\         R\        \        \        \        4      3,          R\
        \        \        3,          /# r   payloadr   r    )rE   r   r   r   r   rW   r!   rV   )r"   s   "r#   r$   r$   o   s=     ) ))|W[%99:) 
#s(^)r%   c           
       "   R^ R^ R^ R^ R^ /pV P                    EFr  p\        WP                  4      G Rj  xL
 pV'       g   VR;;,          ^,          uu&   K@   VP                  '       d7   \	        WP                  RRR7      G Rj  xL
  VR;;,          ^,          uu&   MVP
                  '       g   VP                  '       dQ   \	        VVP                  VP                  VP
                  '       * R7      G Rj  xL
  VR;;,          ^,          uu&   M]\        WVP                  4      G Rj  xL
 pVR;;,          VR	,          ,          uu&   VR;;,          ^VR	,          ,
          ,          uu&   VP                  4       G Rj  xL
  EKu  	  V#  EL] EL L Lj L  \         d   pTP                  4       G Rj  xL 
  \        P                  R
TP                  T4       \	        YP                  \        T4      RR7      G Rj  xL 
  TP                  4       G Rj  xL 
  TR;;,          ^,          uu&    Rp?EK)  Rp?ii ; i5i)uJ  Recebe o HTML buscado e fecha cada acto.

Cada resultado é tratado à parte e com commit próprio: um acto cujo parse
rebente não pode arrastar consigo os outros nove que vieram bem. É
idempotente — reentregar o mesmo corpo reescreve as mesmas arestas, que é o
que o `apply_parse` já garante ao apagar por `source_act_id`.
	guardadosvazioserros
devolvidosdesconhecidosNF)r5   count_attemptvazioz$entrega remota do acto %s falhou: %sT)rK   _act_forr3   r7   r   r6   r5   r   r4   r^   	Exceptionrollbackloggerwarningr!   )rd   r   totalsitemr`   countses   &&     r#   deliverrv   n   s     1h7A|QYZ[FWkk22?#q(#	!}}}%g{{$V[\\\|$)$%%%%KK**&*&:&:":	   w1$-gDIIFFx F7O3 {#q6'?'::#.."""-  : M9 3 ] G # 	!""$$$NNA4;;PQR!';;c!fTXYYY.."""7Oq OO	!s   5IFIIF .F 	F
+F 6F 5F =F>3F 1F2AF F	F IF F F F  I	+I>G?A
I	H
I"H%#I=II		Ic                   \   a  ] tR t^t o ]! ^	R7      t]! ]R7      tRtRt	Rt
V 3R ltRtV tR# )NipcDelivery)rH   )rG   NFc                   < V ^8  d   Qh/ S[ ;R&   S[S[S[ S[3,          ,          ;R&   S[ R,          ;R&   S[;R&   S[;R&   # )r   nifpublicationsNr5   r6   r7   )r!   rL   rW   r   r8   )r"   r9   s   "r#   r$   NipcDelivery.__annotate__   sU     	" 
 tCH~&D  :  !   r%   r;   )r<   r=   r>   r?   r   rz   rL   r{   r5   r6   r7   r@   rA   rB   rC   s   @r#   rx   rx      s1     "C */t)DLE!OH  r%   rx   c                   @   a  ] tR t^t o ]! ]^R7      tV 3R ltRtV t	R# )DeliverNipcInrF   c                6   < V ^8  d   Qh/ S[ S[,          ;R&   # rJ   )rL   rx   )r"   r9   s   "r#   r$   DeliverNipcIn.__annotate__   s     ,L r%   r;   NrN   rC   s   @r#   r~   r~      s     "'"LG  r%   r~   z/claim-nipcc                    V ^8  d   QhR\         \        \        \        4      3,          R\        R\
        \        \        3,          /# rS   rU   )r"   s   "r#   r$   r$      sB     Z Z|W[%99:Z
Z 
#s(^Zr%   c           	        "   \        WR7      G Rj  xL
 pV P                  4       G Rj  xL
  RV Uu. uF  pRVR,          RVR,          /NK  	  up/#  LB L,u upi 5i)u  Reclama entidades da fila do histórico por NIPC.

Lotes pequenos por defeito: cada NIPC são uma a trinta chamadas ao IRN,
conforme o histórico, e um lote grande fica reclamado muito tempo. A
recuperação de reclamações penduradas existe, mas é melhor não a exercitar.
rY   Nentitiesrz   depth)r   r^   )r   rT   r_   rs   s   &&  r#   
claim_nipcr      s]      "'33E
..
RWXRW$%egtG}ERWXYY 4Xs0   AAAA	AAAAAz/deliver-nipcc                    V ^8  d   QhR\         R\        \        \        \        4      3,          R\
        \        \        3,          /# rc   )r~   r   r   r   r   rW   r!   rV   )r"   s   "r#   r$   r$      s=     . ..|W[%99:. 
#s(^.r%   c           
       "   R^ R^ R^ R^ /pV P                    EF  pVP                  ;'       g    RP                  4       p\        V4      ^	8w  d   VR;;,          ^,          uu&   KO   VP                  '       d-   \        WRRR7      G Rj  xL
  VR;;,          ^,          uu&   MVP                  '       d-   \        WRR	R7      G Rj  xL
  VR;;,          ^,          uu&   MVP                  '       d7   \        WR
VP                  R7      G Rj  xL
  VR;;,          ^,          uu&   Mn\        WVP                  RR7      G Rj  xL
 p\        WRVR7      G Rj  xL
  VR;;,          VR,          ,          uu&   VR;;,          VR,          ,          uu&   VP                  4       G Rj  xL
  EK  	  V#  EL. L L Lx Ld L  \         d   pTP                  4       G Rj  xL 
  \        P                  RYF4       \        YR
\        T4      R,          R7      G Rj  xL 
  TP                  4       G Rj  xL 
  TR;;,          ^,          uu&    Rp?EKD  Rp?ii ; i5i)u  Recebe a listagem de cada NIPC e fecha-o na fila.

**Sem rede deste lado**: o `ingest_publications` grava os actos como
`pending` e a fila de conteúdo abre-os depois, pela escada de prioridades que
já põe a cap table mais recente à frente do resto do histórico.

Commit por entidade, como na entrega de conteúdo: um NIPC cuja escrita
rebente não pode arrastar os outros do lote.
listadosactos_novosrh   ri    pendingN)r
   r5   IrnVersionChangedr5   F)fetch_contentok)r
   statsnovosz$entrega remota do NIPC %s falhou: %s:Ni  N)rK   rz   striplenr7   r   r6   r5   r   r{   r^   rn   ro   rp   rq   r!   )rd   r   totaisrs   rz   r   ru   s   &&     r#   deliver_nipcr      s     !]Aw<KFxx~~2$$&s8q=7Oq O	!}}}'YdSSS|$)$%%%':M   |$)$'WDJJWWWw1$1$"3"35  (TOOOz"eJ&77"}%w7%.."""3  @ M3 T
 X P # 	!""$$$NNA3J#GAtUUU.."""7Oq OO	!s   -I%8I%)G;GF:+G9G
F=+G7GF?5GG	GGAG.G/G3I%:G=G?GGGGI"I%G(&<I"H%#I;H><II%I""I%c                l    V ^8  d   QhR\         R\        R\        \        \        3,          R,          /# )r   r   r3   r    N)r   r!   rW   r   )r"   s   "r#   r$   r$      s.     & &L &# &$sCx.4:O &r%   c                   "    \        V4       T P	                  \        R4      RT/4      G R j  xL
 P                  4       P                  4       pT'       d   \        T4      # R #   \        \        \        3 d     R # i ; i LR5i)NzSELECT id::text, nipc, irn_publication_id, act_type, act_date,       entity_name, listing_json  FROM registry_acts WHERE id = CAST(:aid AS UUID)aid)	r   
ValueErrorAttributeError	TypeErrorexecuter   mappingsfirstrW   )r   r3   rows   && r#   rm   rm      s     V ooE
 FO
 	
 hj  49%% 	2 	
s7   BA%  BB'BB%A?;B>A??B)N)3__doc__loggingr+   typingr   r   uuidr   fastapir   r   r   r   r	   r
   pydanticr   r   
sqlalchemyr   sqlalchemy.ext.asyncior   app.dbr   app.servicesr   app.services.registry_sweepr   r   r   r   app.services.registry_syncr   r   r   router	getLoggerr<   rp   r)   r/   r1   rE   postra   rv   rx   r~   r   r   rm   r;   r%   r#   <module>r      ss  (   !  L L %  /  %   
+\N	;			8	$ $Ty I	 I XW-?%@$AB 1r" C( Zw/A'B&CD) E)X9 MI M ]'2D*E)FG 1r"Z HZ _G4F,G+HI. J.b&r%   