Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

215
Vistas
¿Cómo cancelar la consulta costosa de Postgresql de Rails?

En mi aplicación Rails tengo el controlador que se encarga de generar los informes. Algunos de esos informes tardan mucho tiempo en generarse y superan el límite de 30 segundos en Heroku. En tal caso, quiero mostrar una notificación al usuario después de 25 segundos y también cancelar la consulta de la base de datos. Mi idea inicial era usar Timeout .

 class ReportsController < ApplicationController def expensive_report Timeout.timeout(25) do @results = ExpensiveQuery.new(params).results end rescue Timeout::Error render action: "timeout" end end

El tiempo de espera funciona bien, pero la consulta respectiva no se cancela. Es fácil de reproducir en la consola de Rails.

 begin Timeout.timeout(1) do ActiveRecord::Base.connection.execute("SELECT pg_sleep(10)") end rescue Timeout::Error puts "Timeout" end result = ActiveRecord::Base.connection.execute("SELECT 1 AS value") puts result[0]["value"]

Este código generará "Tiempo de espera" y luego bloqueará el result = ActiveRecord::Base.connection.execute("SELECT 1 AS value") hasta que finalice la consulta pg_sleep .

¿Cómo puedo cancelar dicha consulta desde Rails? Alojo mi aplicación en Heroku, por lo que los privilegios se limitan a ejecutar comandos como pg_cancel_backend o pg_terminate_backend .

over 4 years ago · Santiago Trujillo
3 Respuestas
Responde la pregunta

0

puede configurar statement_timeout en el nivel de sesión (sin transacción y omitiendo local ).

o transacción:

 t=# begin; set local statement_timeout to 1; select pg_sleep(3);end; BEGIN Time: 0.096 ms SET Time: 0.098 ms ERROR: canceling statement due to statement timeout Time: 1.768 ms ROLLBACK Time: 0.066 ms

o por defecto para el usuario:

 alter user no_long_qries set statement_timeout to 1;
over 4 years ago · Santiago Trujillo Denunciar

0

Puede hacer que ese tiempo de espera se aplique a todas las solicitudes de la base de datos agregando esto a config/database.yml :

 default: &default adapter: postgresql ... variables: statement_timeout: 25000

O esto hasta el final de config/environment.rb :

 ActiveRecord::Base.connection.execute('set statement_timeout to 25000')
over 4 years ago · Santiago Trujillo Denunciar

0

Encontré una solución genial que no requiere modificaciones a las consultas actuales.

 class ReportsController < ApplicationController def expensive_report Timeout.timeout(25) do @results = ExpensiveQuery.new(params).results end rescue Timeout::Error ActiveRecord::Base.connection.raw_connection.cancel render action: "timeout" end end

Cuando se ejecuta en la consola, necesito agregar verificar si la conexión está activa.

 begin Timeout.timeout(1) do ActiveRecord::Base.connection.execute("SELECT pg_sleep(10)") end rescue Timeout::Error ActiveRecord::Base.connection.raw_connection.cancel ActiveRecord::Base.connection.active? puts "Timeout" end result = ActiveRecord::Base.connection.execute("SELECT 1 AS value") puts result[0]["value"]

Sin llamar a ActiveRecord::Base.connection.active? generará ActiveRecord::StatementInvalid: PG::QueryCanceled .

Esto funciona bastante bien, pero todavía estoy seguro de si hay algún problema oculto con eso.

over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda