Nov/090
rush, un peu plus d’OOP dans les scripts
Problématique
Le lancement de l’application se fait par une tâche Rake, comme décrit précédemment dans le premier article concernant les builds.
task :start => :build do ...
La tâche de lancement est dépendante d’un build
complet.
Cependant, on ne prend pas en compte l’environnement, et différents processus doivent être lancés avant de démarrer l’application. Il s’agit d’une dépendance sur des processus externes, et cela est généralement réalisé par des appels système.
Rush
Cependant, les commandes à créer sont un peu complexes et lourdes à maintenir. Pour cela, nous utiliserons donc une application Ruby
qui s’inscrit dans la direction des shell
basés sur de la programmation objet, comme le powershell
de Microsoft.
Bienvenue à Rush. Rush a été créé pour les tâches d’administration liées au projet Heroku comme expliqué dans un article de l’auteur.
Vous pouvez également consulter une présentation de rush, qui expliquera bien mieux que moi les intérêts d’une telle technologie.
On l’installe comme tout autre gem
:
gem install rush
A noter que je suis passé à gemcutter pour la gestion des modules (nouveau site officiel de gestion des gems
).
ATTENTION ! Rake
n’est pas vraiment compatible avec les systèmes de shell
(et ceci m’a coûté beauuucoup de temps). En effet Rake
redéfini les entrées et sorties standard, ce qui fait qu’il n’est plus possible de lire sur l’entrée standard, et donc qu’il est impossible de rediriger des commandes par pipe
. C’est pourquoi les commandes shell
seront écrites dans un fichier séparé.
Si vous insistez, vous vous retrouverez avec cette erreur peu compréhensible :
rake aborted!
Broken pipe
Start
On peut étendre la tâche de démarrage pour ajouter une dépendance à l’environnement :
task :start => [ :build, 'init:env' ] do end
et créer une tâche dans l’espace init
:
require 'rush' namespace 'init' do desc "Init servers" task :env do app = Rush[ROOT] app["*.dump"].each{ |f| f.destroy } app["*.swp"].each{ |f| f.destroy } system "#{ROOT}/process.sh" end end
Ici, on efface des fichiers temporaires à chaque nouveau démarrage en utilisant la syntaxe rush
(ROOT
est une constante qui représente le chemin racine du projet).
Un point important, comme indiqué précédemment, c’est que la gestion des processus est délélguée à un fichier externe, et lancée dans un shell
externe par la commande ruby
directement. Ceci car rake
et la gem
session
ne sont pas compatibles.
En tout cas, il n’est pas possible de démarrer une session bash
dans une tâche rake
, l’inverse étant sûrement possible.
Gestion des processus
La tâche d’initialisation a pour but de vérifier que les processus serveurs sont lancés, et si non de les lancer. Les serveurs sont actuellement Nginx et CouchDB.
On peut écrire le code ainsi (dans process.sh
) :
#!/usr/bin/ruby -rubygems require "rush" if Rush::box.processes.filter(:cmdline => /nginx/).empty? puts "Starting nginx" Rush.box.bash "nginx", :user => "root" end if Rush::box.processes.filter(:cmdline => /couchdb/).empty? puts "Starting couchdb" Rush.box.bash "couchdb -b", :user => "root" end
Et les processus ne seront démarrés que s’ils n’existent pas.
La commande indiquée dans le site est la suivante :
if Rush::box.processes.filter(:cmdline => /nginx/).alive?
Malheureusement, cela ne fonctionne pas du fait que les processus sont lancés en tant que root
, et je n’ai pas trouvé comment contourner ce problème.