2012-06-28 9 views
13

Estoy usando rufus-scheduler para ejecutar una serie de trabajos frecuentes que realizan varias tareas con objetos ActiveRecord. Si hay algún tipo de error de red o postgresql, incluso después de la recuperación, todos los hilos arrojarán el siguiente error hasta que se reinicie el proceso:Problema de grupo de conexión con objetos ActiveRecord en rufus-scheduler

ActiveRecord :: ConnectionTimeoutError (no se pudo obtener una conexión de base de datos en 5 segundos (esperado 5.000122687) segundos). El tamaño máximo de la agrupación actualmente es de 5; considere aumentarlo.

El error se puede reproducir fácilmente reiniciando postgres. He intentado jugar (hasta 15) con el tamaño de la agrupación, pero no tuve suerte.

Eso me lleva a creer que las conexiones están en un estado obsoleto, lo que pensé que se solucionaría con la llamada al clear_stale_cached_connections!.

¿Existe un patrón más confiable para hacer esto?

El bloque que se pasa es una simple llamada de registro de selección y actualización, y pasa a ser importante para el objeto AR.

El trabajo rufus:

scheduler.every '5s' do 
    db do 
    DataFeed.update #standard AR select/update 
    end 
end 

envoltorio:

def db(&block) 
    begin 
     ActiveRecord::Base.connection_pool.clear_stale_cached_connections! 
     #ActiveRecord::Base.establish_connection # this didn't help either way 
     yield block 
    rescue Exception => e 
     raise e 
    ensure 
     ActiveRecord::Base.connection.close if ActiveRecord::Base.connection 
     ActiveRecord::Base.clear_active_connections! 
    end 
    end 
+0

alguna actualización sobre él? – jbmyid

+0

También estoy enfrentando el mismo problema, intenté arriba e incluso 'ActiveRecord :: Base.connection_pool.with_connection' pero no funciona – jbmyid

Respuesta

-1

Realmente no sé de rufus-programador, pero tengo algunas ideas.

El primer problema podría ser un error en rufus-scheduler que no comprueba correctamente la conexión de la base de datos. Si es el caso, la única solución es borrar las conexiones obsoletas manualmente como lo hace ya e informar al autor de rufus-scheduler sobre su problema.

Otro problema que podría ocurrir es que su operación DataFeed lleva mucho tiempo y porque se realiza cada 5 segundos Rails se está quedando sin conexiones de base de datos, pero es bastante improbable.

1

La razón puede ser que tiene muchos hilos que usan todas las conexiones, si el método DataFeed.update tarda más de 5 segundos, entonces su bloque puede superponerse.

tratar

scheduler.every("5s", :allow_overlapping => false) do 
#... 
end 

Proveedores liberación de la conexión en lugar de cerrarlo.

ActiveRecord::Base.connection_pool.release_connection 
11

Rufus scheduler inicia un nuevo hilo para cada trabajo. ActiveRecord, por otro lado, no puede compartir conexiones entre subprocesos, por lo que debe asignar una conexión a un subproceso específico.

Cuando el hilo aún no tenga una conexión, obtendrá uno del grupo. (Si todas las conexiones de la agrupación están en uso, esperará una hasta el se devuelve desde otro hilo. Con el tiempo se agote el tiempo y tirar ConnectionTimeoutError)

es su responsabilidad para volver de nuevo a la piscina cuando haya terminado con esto, en una aplicación de Rails, esto se hace automáticamente. Pero si estás administrando tus propios hilos (como rufus lo hace), tienes que hacer esto tú mismo.

Lucklily, hay una API para esto: Si coloca el código dentro de un bloque de with_connection, se obtendrá una conexión forman la piscina, y lo liberan cuando se hace

ActiveRecord::Base.connection_pool.with_connection do 
    #your code here 
end 

En su caso :

def db 
    ActiveRecord::Base.connection_pool.with_connection do 
    yield 
    end 
end 

debe hacer el truco ....

http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/ConnectionPool.html#method-i-with_connection

Cuestiones relacionadas