Durante una revisión de harvesting en DSpace-CRIS 8 (2024.02.03 / base DSpace 8.0.1) nos encontramos con un comportamiento interesante al configurar una colección para recolectar metadatos desde un proveedor OAI-PMH externo.
El escenario era el siguiente:
dc / oai_dc).Al ejecutar la recolección, DSpace-CRIS terminaba en estado RETRY y mostraba:
Not recoverable error occurs:
OAI server response contains the following error codes:
[noSetHierarchy]
noSetHierarchy?Para comprobar el comportamiento del proveedor realizamos las consultas OAI-PMH directamente.
Por ejemplo:
curl -sv 'https://servidor/oai?verb=Identify'
La operación Identify respondía correctamente.
También verificamos:
curl -sv 'https://servidor/oai?verb=ListRecords&metadataPrefix=oai_dc'
y el proveedor entregaba los registros correctamente.
Sin embargo:
curl -sv 'https://servidor/oai?verb=ListSets'
respondía:
<error code="noSetHierarchy">
This repository does not support sets
</error>
Esto, por sí mismo, no constituye una falla del proveedor OAI-PMH. Simplemente significa que el repositorio no organiza sus registros mediante Sets OAI.
Si queremos cosechar todos sus registros, no necesitamos especificar un Set.
Para diagnosticar el problema comparamos dos instalaciones de desarrollo de DSpace-CRIS 8 con prácticamente la misma configuración.
En el primer ambiente, la recolección funcionaba correctamente:
Estado: READY
Imported 18 records with success
En el segundo ambiente, utilizando el mismo proveedor OAI y el mismo formato de metadatos, obteníamos:
Not recoverable error occurs:
OAI server response contains the following error codes:
[noSetHierarchy]
Inicialmente verificamos si existían diferencias de versión.
En ambos servidores encontramos:
dspace-api-lang-8.0.1.jar
dspace-api-cris-2024.02.03.jar
Por lo tanto, no estábamos simplemente ante dos versiones diferentes de DSpace-CRIS.
También probamos directamente las operaciones OAI-PMH desde ambos servidores.
El proveedor respondía correctamente a Identify y ListRecords, mientras que ListSets devolvía noSetHierarchy, como correspondía a un repositorio que no implementa Sets.
La diferencia, por lo tanto, debía estar en otro lugar.
DSpace mantiene la configuración de harvesting de las colecciones en la tabla:
harvested_collection
Podemos localizarla con:
sudo -u postgres psql -d dspace -c "\dt *harvest*"
En nuestro caso aparecieron:
harvested_collection
harvested_item
La estructura de harvested_collection incluye, entre otros, los campos:
harvest_type
oai_source
oai_set_id
harvest_message
metadata_config_id
harvest_status
harvest_start_time
last_harvested
collection_id
Al comparar los registros encontramos finalmente la diferencia.
En el ambiente que funcionaba correctamente:
oai_source = https://servidor/oai
oai_set_id = ''
metadata_config_id = dc
harvest_type = 1
harvest_status = 0
Mientras que en el ambiente que fallaba:
oai_source = https://servidor/oai
oai_set_id = all
metadata_config_id = dc
harvest_type = 1
harvest_status = 4
El mensaje asociado era:
Not recoverable error occurs:
OAI server response contains the following error codes:
[noSetHierarchy]
NULL, '' y 'all' no son equivalentesEsta terminó siendo la parte más importante del diagnóstico.
Probamos inicialmente reemplazar all por NULL.
El resultado fue otro error:
Not recoverable error occurs:
Provided collection is not set up for harvesting
Por lo tanto, NULL tampoco representaba correctamente el escenario.
Para comprobar exactamente qué contenía el ambiente funcional ejecutamos:
SELECT
id,
quote_nullable(oai_set_id) AS valor,
length(oai_set_id) AS longitud,
octet_length(oai_set_id) AS bytes,
encode(convert_to(oai_set_id,'UTF8'),'hex') AS hex
FROM harvested_collection;
En el DSpace-CRIS que funcionaba obtuvimos:
valor | longitud | bytes | hex
------+----------+-------+-----
'' | 0 | 0 |
Es decir, no era NULL.
Era una cadena vacía real.
En cambio, en el ambiente con problemas:
valor | longitud | bytes | hex
------+----------+-------+--------
'all' | 3 | 3 | 616c6c
Con esto pudimos identificar claramente tres comportamientos diferentes:
oai_set_id = NULL
→ DSpace considera que la colección no está correctamente
configurada para harvesting.
oai_set_id = 'all'
→ se produce una operación relacionada con Sets.
→ el proveedor responde noSetHierarchy.
→ la recolección falla.
oai_set_id = ''
→ no existe un Set OAI específico.
→ DSpace puede recolectar el repositorio completo.
Para dejar la colección problemática con el mismo comportamiento del ambiente funcional, corregimos oai_set_id utilizando una cadena vacía:
UPDATE harvested_collection
SET oai_set_id = '',
harvest_status = 0,
harvest_message = NULL,
harvest_start_time = NULL
WHERE id = 1;
Posteriormente verificamos:
SELECT
id,
oai_source,
quote_nullable(oai_set_id) AS oai_set_id,
length(oai_set_id) AS longitud,
metadata_config_id,
harvest_type,
harvest_status,
harvest_message
FROM harvested_collection;
Para una colección que debe recolectar todo el repositorio y cuyo proveedor no utiliza Sets, el resultado esperado es:
oai_set_id = ''
length = 0
Este caso también demuestra por qué no siempre basta con revisar la interfaz administrativa.
Visualmente, el campo:
ID de set específico de OAI
podía aparecer vacío.
Sin embargo, en PostgreSQL el ambiente problemático contenía:
'all'
mientras que el ambiente funcional contenía:
''
Para el administrador ambos escenarios pueden parecer iguales desde la interfaz, pero para el backend son valores diferentes y pueden producir comportamientos completamente distintos.
Por eso, cuando un harvesting OAI-PMH presenta errores aparentemente inconsistentes, resulta útil revisar directamente:
harvested_collection.oai_source
harvested_collection.oai_set_id
harvested_collection.metadata_config_id
harvested_collection.harvest_type
harvested_collection.harvest_status
harvested_collection.harvest_message
Durante el diagnóstico encontramos además un error como:
Couldn't connect to host, port:
smtp.example.com, 25
seguido de:
java.net.UnknownHostException: smtp.example.com
Este error no era la causa original del fallo OAI-PMH.
La secuencia era:
Harvesting falla
↓
DSpace intenta notificar el fallo
↓
OAIHarvesterEmailSender intenta enviar correo
↓
SMTP sigue configurado como smtp.example.com
↓
también falla la notificación
Es importante separar ambos problemas, porque un stacktrace extenso relacionado con SMTP puede llevar a pensar que el harvesting está fallando por correo, cuando en realidad el correo solamente está intentando informar de un error producido anteriormente.
Cuando DSpace-CRIS 8 devuelve:
OAI server response contains the following error codes:
[noSetHierarchy]
no debemos asumir inmediatamente que el proveedor OAI-PMH está defectuoso.
Primero conviene comprobar:
curl 'https://servidor/oai?verb=Identify'
curl 'https://servidor/oai?verb=ListSets'
curl 'https://servidor/oai?verb=ListRecords&metadataPrefix=oai_dc'
Si Identify y ListRecords funcionan, pero ListSets responde:
noSetHierarchy
el proveedor simplemente puede no implementar Sets.
En DSpace-CRIS 8 también es recomendable inspeccionar directamente harvested_collection y, particularmente, distinguir entre:
NULL
''
'all'
porque no necesariamente representan el mismo estado para el harvesting.
En nuestro caso, la comparación entre dos instalaciones DSpace-CRIS 8 permitió aislar la diferencia:
Ambiente funcional
oai_set_id = ''
Ambiente con error
oai_set_id = 'all'
Una diferencia de apenas tres caracteres que desde la interfaz prácticamente no era visible, pero que terminaba determinando si la cosecha OAI-PMH podía completarse o finalizaba con noSetHierarchy.
Este tipo de diagnóstico comparativo entre ambientes equivalentes resulta especialmente útil en DSpace: antes de atribuir el problema al proveedor OAI, a la red, a Cloudflare o a la versión de DSpace, vale la pena comparar el estado real persistido en PostgreSQL.