Timout::Error avec open-uri

Bonjour,

Je voudrais récupérer des flux RSS à partir d’un URL. Après quelques
recherches sur Internet, je suis tombé sur une librairie très simple que
voici :

lib/rss_parser.rb

class RssParser
require ‘rexml/document’
require ‘open-uri’
def self.run(url)
xml = REXML::Document.new(open(url))
data = {
:title => xml.root.elements[‘channel/title’].text,
:home_url => xml.root.elements[‘channel/link’].text,
:rss_url => url,
:items => []
}
xml.elements.each ‘//item’ do |item|
new_items = {} and item.elements.each do |e|
new_items[e.name.gsub(/^dc:(\w)/,"\1").to_sym] = e.text
end
data[:items] << new_items
end
data
end
end

En console, tout fonctionne, mais lorsque je l’utilise dans mon
application, j’ai une erreur Timeout::Error :

Timeout::Error (execution expired):
/usr/lib/ruby/1.8/timeout.rb:54:in rbuf_fill' /usr/lib/ruby/1.8/timeout.rb:56:intimeout’
/usr/lib/ruby/1.8/timeout.rb:76:in timeout' /usr/lib/ruby/1.8/net/protocol.rb:132:inrbuf_fill’
/usr/lib/ruby/1.8/net/protocol.rb:116:in readuntil' /usr/lib/ruby/1.8/net/protocol.rb:126:inreadline’
/usr/lib/ruby/1.8/net/http.rb:2020:in read_status_line' /usr/lib/ruby/1.8/net/http.rb:2009:inread_new’
/usr/lib/ruby/1.8/net/http.rb:1050:in request' /usr/lib/ruby/1.8/open-uri.rb:248:inopen_http’
/usr/lib/ruby/1.8/net/http.rb:543:in start' /usr/lib/ruby/1.8/open-uri.rb:242:inopen_http’
/usr/lib/ruby/1.8/open-uri.rb:616:in buffer_open' /usr/lib/ruby/1.8/open-uri.rb:164:inopen_loop’
/usr/lib/ruby/1.8/open-uri.rb:162:in catch' /usr/lib/ruby/1.8/open-uri.rb:162:inopen_loop’
/usr/lib/ruby/1.8/open-uri.rb:132:in open_uri' /usr/lib/ruby/1.8/open-uri.rb:518:inopen’
/usr/lib/ruby/1.8/open-uri.rb:30:in open' /lib/rss_parser.rb:7:inrun’
/app/controllers/pages_controller.rb:155:in `rss’
(…)

Quelqu’un aurait-il une idée d’où cela pourrait-il venir?

J’utilise Rails 2.1.0, et j’ai effectué des tests en environement de
développement et de production.

Merci

Comme te le dis l’erreur, c’est un timeout. Apparemment, ton application
a
mis trop de temps à faire quelque chose, apparemment à tenter d’ouvrir
l’uri
de ta cible je dirais (sans certitude). Si c’est le cas, ca peut se
produire
quand :

  • le serveur où tu cherche à piocher le flux RSS est en panne
  • le serveur met trops de temps à répondre
  • le serveur blacklist tes requêtes
  • et j’en oublie

Vu que tu n’as pas le problème en ligne de commande, je me hasarderai Ã
penser que ton serveur (à toi) surveille le temps d’exécution des
requêtes
qui lui sont soumises et kicke les requêtes qui s’éternisent (tout en
restant plus tolérant pour les manipulations console par exemple). Comme
tu
es tributaire du temps de chargement de cette ressource externe, c’est
probablement parce que le serveur distant met trops de temps à répondre.

Le 8 octobre 2008 15:23, Céd B. [email protected] a écrit :

require ‘rexml/document’
new_items = {} and item.elements.each do |e|

/usr/lib/ruby/1.8/open-uri.rb:248:in open_http' /app/controllers/pages_controller.rb:155:in rss’


Michel B.

Merci de ta réponse Michel.

Comme je l’ai dis dans mon premier message, j’ai fais des test en
production (sur un serveur de production distant) et en développement
(sur ma machine, en local).

La cause éventuelle que tu proposes me parraît un peu étrange, parce que
j’ai effectué mes tests de différentes manières : à la fois en local
(console et application) et en ligne (console et application), avec des
flux RSS distants et locaux.

La librairie fonctionnait, dans tous les cas, lorsque j’utilisais la
console, par contre, elle n’a jamais fonctionné quand je l’appelle via
mon application.

En production, j’utilise Webrick, et en production, Mongrel. J’ai le
même problème, quelque soit la solution de déploiement.

J’ai testé la classe dans Rails (dans mon application), et c’est la
quelle ne fonctionne pas. Hors de Rails, en console, tout fonctionne
parfaitement.

La machine de développement tourne sous Ubuntu, et le serveur, sous
Debian, il y a donc peu de chance que le problème vienne de là .

Enfin, je suis certain que le timeout est une erreur, puisque j’ai testé
pas loin de 10 flux RSS, dont un dont je peux etre absolument certain
puisqu’il émane de l’application elle-même.

Voilà , j’espère que ces précisions pourront vous éclaircir :slight_smile:

Le 8 octobre 2008 16:03, Céd B. a écrit :

La cause éventuelle que tu proposes me parraît un peu étrange, parce que
j’ai effectué mes tests de différentes manières : à la fois en local
(console et application) et en ligne (console et application), avec des
flux RSS distants et locaux.

La librairie fonctionnait, dans tous les cas, lorsque j’utilisais la
console, par contre, elle n’a jamais fonctionné quand je l’appelle via
mon application.

Là comme ça, je vois pas trop, mais il y a toujours la solution
d’être méthodique (+ grille sur feuille de papier) ou rigoureux.

Tu n’as pas dit quelle solution de déploiement tu utilisais ?
Tu utilises mongrel ? Bon, ben change.

Autre paramètre : dans Rails ou hors Rails. ta classe RssParser,
tu peux l’essayer hors Rails.

C’est quoi les différences entre machines de dev et de production ?
OS ?

Autre remarque : si tu veux faire ton traitement dans ton action
de ton contrôleur, tu dois traiter les pbs (impossible d’accéder au
feed…) ie les échecs, pas uniquement le cas où tout marche.

Deuxièmement, c’est ptêtre préférable de traiter ta tâche de
manière asynchrone (ce qui évite que son action déclenche un
Timeout, ce qui ne signifie pas pour autant qu’il n’y ait pas
de pb de Timeout pour RssParser.run car le fichier que tu
veux récupérer peux être inaccessible, etc.).

-- Jean-François.


Les 50 ans du Lisp : http://www.lisp50.org

http://twitter.com/underflow_

Le 8 octobre 2008 17:48, Céd B. a écrit :

En production, j’utilise Webrick, et en production, Mongrel. J’ai le
même problème, quelque soit la solution de déploiement.

Raccourci pour le moins rapide. Il y a d’autres solutions de déploiement
Litespeed, FastCGI, Glassfish, Thin, CGI (j’ai pas dit forcément
efficace),
ebb, EventedMongrel, Phusion Passenger et j’en oublie… où
ton problème se reproduit. Ou pas.

J’ai testé la classe dans Rails (dans mon application), et c’est la
quelle ne fonctionne pas. Hors de Rails, en console, tout fonctionne
parfaitement.

Il y a d’autres paramètres sur lesquels jouer, tu n’as pas fini
tes investigations au peigne fin, script/console en mode dev ou
production ; depuis une application Rails from scratch (= sans
le reste de ton code + plugins) ; utilisation de net/http directement…
Chaque fois, mode dev/mode production.

Tu peux même voir si ActiveResource marche, il utilise net/http.

La machine de développement tourne sous Ubuntu, et le serveur, sous
Debian, il y a donc peu de chance que le problème vienne de là.

On ne sait jamais. Déjà qu’on ne peut plus faire confiance à Debian…

Enfin, je suis certain que le timeout est une erreur, puisque j’ai testé
pas loin de 10 flux RSS, dont un dont je peux etre absolument certain
puisqu’il émane de l’application elle-même.

c’est pas tant qu’il y ait des timeouts, comme on l’a déjà dit, il faut
que tu gères ça dans ton code, c’est qu’il y ait systématiquement
des timeouts.

Voilà, j’espère que ces précisions pourront vous éclaircir :slight_smile:

Pour l’instant, j’ai du mal à voir où est le coupable. La 2e série
d’investigations citée ci-dessus pourrait apporter des éclaircissements…

– Jean-François.


Les 50 ans du Lisp : http://www.lisp50.org

http://twitter.com/underflow_

  1. 9.9 chances sur 10 que ce soit un “problème” réseau|firewall|dns.

Test dans ton environement de prod wget #{url} si tu recois la page,
la tu peux commencer à t’inquiéter, sinon c’est juste le système qui
n’autorise pas cela ou est mal
configuré.
2) comme on te l’a déjà dit, cette erreur doit être intercepté, et
j’irais plus loin il faut cacher agressivement le résultat car c’est
infiniment lent de faire ca en synchrone.