Actualmente estoy creando un plugin relacionado con meritmoot.com (que está en desarrollo y en versiones de lanzamiento continuo). Debido a su uso de datos externos, estoy utilizando un trabajo de Sidekiq de larga duración. Por alguna razón, el trabajo sigue reiniciando el código interno sin fallar ni mostrar salida de error. ¿Hay algo en Sidekiq que pueda estar causando este reinicio?
En mi último trabajo (que debería ejecutarse solo una vez al día), relacionado con los llamados, el trabajo se reinició en los siguientes intervalos sin mostrar error:
0h-58m-42s (inicio de la primera iteración)
1h-30m-12s (primer reinicio)
2h-1m-1s (segundo reinicio)
3h-46m-49s
4h-17m-11s
4h-47m-33s
El trabajo no terminó y todo el progreso se reinició. Cabe mencionar que tengo mi propio proceso de registro que redirige stderr y stdout para mi código interno, aunque dudo que interfiera con Sidekiq (puedes pedirme que te lo muestre si quieres, ¡es muy útil para el desarrollo!).
Es posible guardar el progreso realizado dentro del código, pero preferiría un proceso más sencillo, ya que eso genera sobrecarga. ¿Hay algo en Sidekiq que pueda estar causando que mi código se reinicie?
Estoy procesando una gran cantidad de datos externos y almacenándolos internamente en mi sitio web. Los datos se refieren a información del Congreso de los Estados Unidos.
edición: como proyectos de ley públicos, votaciones por llamado nominal y miembros.
¿Se te está acabando la memoria? En nuestro hosting, hemos configurado Sidekiq para que se reinicie automáticamente si comienza a usar demasiada memoria.
¿Memoria en el sentido de memoria de base de datos o disco duro? Sí, estoy utilizando bastante de esa. Actualmente estoy considerando una sugerencia ligeramente modificada de @pfaffman, donde bifurco el proceso, permitiendo que el hilo principal termine, pero generando un proceso hijo que tenga el mismo contexto (esencialmente un script externo en relación con Sidekiq).
En lugar de hacer esto, ¿por qué no enseñas a tu trabajo a funcionar en trozos más pequeños? ¿Realmente necesita tomar 4 horas? Sincroniza 10 temas, luego otros 10… y así sucesivamente.
Sidekiq no tiene nada que termine trabajos de larga duración; las reconstrucciones de la aplicación harán eso, e incluso las actualizaciones a través de la interfaz web.
Al final decidí eliminar el código del proceso, ya que no era efectivo. El trabajo de reinicio solo estaba enmascarando un problema subyacente de ineficiencia real . En su lugar, he estado:
Escribiendo código SQL por lotes (que es mucho más rápido que el secuencial), detectando cuándo realmente necesita actualizar y permitiéndome omitir el uso de la clase PostRevisor para volver a actualizar elementos que no han cambiado.
Aumentando la eficiencia en la recuperación de datos a través de HTTP utilizando conexiones persistentes y otros puntos de datos que incluyen elementos comprimidos (cuando es posible).
He descubierto que escribir comandos SQL por lotes ofrece una gran aceleración. Lo que estoy actualizando es:
Tabla post: columnas cooked, last_updated
Tabla topic: columnas title, last_updated
Mi próxima idea es omitir PostRevisor por completo haciendo algo como:
1 - Mover los datos a una tabla temporal
2 - UPDATE topics FROM temp_table
SET topics.title = temp_table.title, topics.last_updated = temp_table.last_updated
WHERE topics.id = temp_table.id AND topics.title != temp_table.title
3 - UPDATE posts FROM temp_table
SET posts.raw = temp_table.raw, posts.last_updated = temp_table.last_updated
WHERE posts.id = temp_table.id AND posts.raw != temp_table.raw
4 - Y luego activar el trabajo de reindexación de búsqueda ya que el título y el contenido han cambiado.
¿Hay algo que estoy pasando por alto? Discourse es complejo, y al omitir PostRevisor siento que podría estar tocando tablas con las que no tengo experiencia (post_stats, post_timings, post_uploads, quoted_posts son algunas que veo en la base de datos). Sin embargo, tampoco necesito toda la validación que proporciona PostRevisor, ya que el sistema recibe estas revisiones de una fuente confiable y predecible. Parece una solución bastante incierta.
Actualización: Estaba realizando algunas verificaciones de código, ya que hubo una cantidad extraña de actualizaciones a lo largo del tiempo, y descubrí que hay algo que provoca actualizaciones injustificadas en elementos de datos que en realidad no han cambiado en su formato JSON bruto. Una vez que se resuelva este error, lo anterior probablemente no será necesario Debería haber hecho pruebas… me habría ahorrado muchísimo de tiempo. Creo que aún podría probar lo anterior, aunque no será prioritario. Ayudará para actualizaciones rápidas cuando cambie el formato de cómo se presentan los datos. Además, ya está escrito, solo que no se ha probado.
He terminado el código de actualización masiva. ¿Estarías interesado en que lo suba a una rama específica una vez que sea más estable? Su caso de uso es bastante específico, pero para lo que hace, puede actualizar miles de registros rápidamente, incluidas las etiquetas. Está diseñado para extender TopicsBulkAction. Aquí está el README que escribí si deseas información más detallada:
# entrada
# - lista de hashes que contienen cooked, post_id, topic_id, title, updated_at, tags (raw apuntará a cooked)
# [{post_id: #, cooked: "", topic_id: #, title: "", updated_at: fecha_hora, tags: [{tag: "", tagGroup: ""}, ... ] } , ... ]
# - category_name, el nombre de la categoría que se actualizará. Esto se usa para la indexación de búsqueda.
# atributos de hash opcionales para incluir en los elementos de la lista:
# - raw, si no se incluye, será igual a cooked.
# - fancy_title, si no se incluye, será igual a title.
# - slug, si no se incluye, se procesará a partir de title (esto está relacionado con su URL).
# caso de uso: actualizar temas regularmente desde una fuente de datos externa a Discourse que cambia, de manera eficiente
# para reflejar la actualización de la información. Ten en cuenta que esto no está diseñado para la publicación general de temas o posts, sino para actualizar
# el título del tema y el POST PRINCIPAL del tema. Para la revisión general de posts, ve a PostRevisor en lib/post_revisor.rb.
# - Asume contenido ya cocinado (cooked), cocinado de forma personalizada o visto tal cual. Los datos no se validan.
# - Los posts deben tener (cook_methods: Post.cook_methods[:raw_html]) establecido al crearse si tu raw == cooked.
# Harías esto si estás escribiendo HTML personalizado para mostrar dentro del post.
# De lo contrario, Discourse podría volver a cocinarlo en el futuro, lo cual sería problemático. Asegúrate de que la fuente de información
# sea confiable y que su contenido esté escapado.
# - Si lo anterior no es ideal, asegúrate de incluir raw, establece el método de cocinado correcto al crear el post
# (en caso de que el sistema lo vuelva a cocinar), pasa raw a través del método de cocinado elegido e incluye tanto raw como el cooked resultante
# en tus hashes.
# - Rastrea el word_count notando las diferencias en las conteos de palabras antes y después del post y pasando eso
# al tema.
# - Rastrea la cantidad de etiquetas de manera similar.