Nous parlons à quelqu'un qui débute manifestement, et il n'a pas été fait mention que l'application serait publique. Sous réserve de confirmation par Ziburudebian, j'ai l'impression qu'il essaie de se bidouiller un outil d'administration à usage personnel, voir local. Dans tous les cas, débuter rails et devoir commencer par sidekiq, action_cable, une configuration de redis, etc est un tue-l'amour pour les débutants. Clairement, nous ne ferions pas de la gestion de process à l'arrache comme ça dans des applications at scale destinées au public. Mais est-ce bien la question ici?
Tu as raison cependant, ça ne ferait pas de mal de faire un check de l'existence d'un process en cours. Étant donné qu'il y a un pidfile, c'est assez simple ça faire: ``` def start raise "Process is already running" if File.exists? "./app.pid" process = spawn( "ruby ./app.rb" ) # tu lances ton process Process.detach( process ) # tu le détaches de ton process web end ``` En cas de coupure brutale du système, il suffit de supprimer le pidfile (c'est assez courant avec les architectures à base de lockfile). Cette solution, aussi peu élégante soit elle, à l'avantage d'être abordable pour un débutant qui essaie d'accomplir quelque chose à son usage. Les architectures plus complexes viendront avec l'envie et l'expérience. Ziburudebian, à bon entendeur : tu peux faire quelque chose aussi simple à ton usage personnel pour débuter, mais c'est un peu plus complexe que ça si tu veux faire une application business / publique :) On Friday, September 2, 2016 at 8:27:21 PM UTC+2, Florian Dutey wrote: > > Je pense tres honnetement que ce procede est mauvais. Tu controlles pas > qui lance (et combien) de process. C'est un coup a te retrouver avec plein > de process orphelins et a obtenir un deni de service de la part de ton OS. > > Le cas d'utilisation est plutot simple ici. T'as une base de donnees qui > est updatee regulierement. > Dans ce cas la, tu as 2 options tres simples: > > 1) Tu fais du polling. Toutes les 10 minutes, ton frontend (javascript) > fait une requete (ajax) au backend (rails) pour recuperer le nouveau data. > 2) tu utilises des websockets (action cable avec rails 5). C'est le > serveur qui va pousser les donnees vers le client chaque fois qu'il y en a > des nouvelles. Donc ca evite de faire des requetes en boucle vers le > serveur. > > Quand au boutton start stop, dans le premier cas, start demarre le cycle > de requetes ajax toutes les 10 minutes (avec setTimeout en vanilla JS). Et > le boutton stop detruit cette boucle (clearTimeout en vanilla JS). > > Dans le second cas, les bouttons start et stop mettent juste a jour un > boolean dans les etats de ta vue. Boolean qui sera evalue pour savoir si tu > dois ignorer ou non les evenements qui sont pousses par le serveur. > > Pas besoin de jobs, pas besoin de daemon, pas besoin de boucle infinie > cote serveur dans ce cas la. C'est un cas tres classique d'affichage de > data "en temps reel". > > 2016-09-02 18:14 GMT+08:00 Olivier El Mekki <oelm...@gmail.com > <javascript:>>: > >> Hello, >> >> Dans le cas que tu décris, je partirais sur quelque chose de plus simple >> que d'utiliser daemon (qui n'est probablement pas pensé pour être utilisé >> avec rails): lancer ton app en commande shell, lui faire stocker son pid >> dans un pidfile, puis faire un kill sur le contenu de ce fichier. Voici un >> example: >> >> La partie web: >> >> ``` >> # Ce fichier est en plain ruby, mais l'idée est de reproduire le contenu >> # des methodes #start et #stop dans tes controllers >> def start >> process = spawn( "ruby ./app.rb" ) # tu lances ton process >> Process.detach( process ) # tu le détaches de ton process web >> end >> >> def stop >> %x(kill $(cat ./app.pid)) if File.exists? "./app.pid" # tu killes ton >> process, s'il n'est pas déjà mort >> end >> >> puts "starting" >> start >> sleep 5 >> puts "stopping" >> stop >> ``` >> >> Dans ton cas, tu voudras probablement utiliser des path absolus plutôt >> que relatifs. >> >> La partie system: >> >> ``` >> # tu stock le pid de ton process >> File.open( "./app.pid", "w" ){ |f| f.puts Process.pid } >> >> # tu t'assures de supprimer le pidfile quand ton process meurt >> Kernel.at_exit do >> File.unlink( "./app.pid" ) >> end >> >> >> # Code >> >> sleep 50 # juste pour executer cet example, tu n'en as pas besoin dans >> ton code >> ``` >> >> >> >> On Friday, September 2, 2016 at 11:35:14 AM UTC+2, ziburudebian wrote: >>> >>> Merci florian pour tes explications, c'est vrai que fournir du code >>> ainsi peut paraître complexe, mais au bout d'un moment tout seul dans mon >>> coin à coder, je craque... >>> tu as raison, j'aurai du commencer par expliquer ce que je veux faire : >>> >>> sur mon formulaire j'ai 2 boutons START et STOP comme tu l'as compris >>> dans mon code; >>> le but lorsque je clique sur START est de lancer un programme qui à >>> partir d'options choisies sur ma page web, analyse les données dans la base >>> et affiche le résultat sur ma page web et le STOP arrête cette analyse; >>> les données (que j'analyse) qui alimente ma base sont mises à jour par >>> un programme externe toutes les 10 minutes, c'est pour cela que j'ai pensé >>> à un boucle infinie qui démarre sur le bouton START >>> >>> >>> Le jeudi 1 septembre 2016 19:14:26 UTC+2, Florian Dutey a écrit : >>>> >>>> Si tu veux utiliser daemon et rails en meme temps, il faut que tu >>>> ecrives dans une queue intermediaire (par exemple redis). Le daemon >>>> monitor >>>> la queue (boucle infinie), quand ya des nouveaux messages dedans, il les >>>> depiles et les traite. Ton controller ne doit jamais inclure la gem daemon >>>> et tu ne dois jamais appeler des scrips depuis ton controller, sinon la >>>> gem >>>> daemon ne sert a rien en fait, tu peux appeler le script directement avec >>>> system() et c'est degueulasse. >>>> >>>> Quand a ton probleme courant, ce qu'on voit dans ton exemple, c'est que >>>> tu passes tes ids client en mode "1-2-3-4" depuis le controller et en mode >>>> "1 2 3" depuis le shell. >>>> >>>> Quand au script lui meme, pourquoi lui filer une loop alors que ca sert >>>> a rien? C'est pas daemon, c'est un script shell ca >>>> C'est aussi plus clean de faire un truc genre >>>> Client.find(*client_ids).each { } plutot que client_ids.each { |id| c = >>>> Client.find(id) #... } Dans un cas t'as un seul call SQL et dans l'autre, >>>> t'as autant de calls que d'ids. >>>> >>>> Le code de ton daemon est tres confus. On ne demarre pas un daemon >>>> depuis un controller. Le daemon doit tourner tout le temps et recevoir des >>>> signaux. La tu ne controlles pas combien de daemon seront demarres en >>>> parallele. Il suffit de spammer ton serveur pour demarrer des tonnes de >>>> daemon et faire peter l'OS qui sera perdu dans les millions de process >>>> crees par le serveur. Le fait de stopper quand ton utilisateur veut bien >>>> penser a cliquer sur stop (ce qu'il ne fera jamais) me permet de te >>>> predire >>>> que tu vas devoir redemarrer tes serveurs souvent, et que ton app ne >>>> serait >>>> jamais disponible. >>>> >>>> En fait, si tu decrivais ce que tu cherches reellement a faire, ca >>>> permettrait probablement de t'aiguiller un peu mieux. Mais la, le code, >>>> y'a >>>> tellement de fondamentaux qui manquent que personne peut prendre le temps >>>> de te donner la solution. >>>> >>>> 2016-09-01 17:52 GMT+08:00 Philippe Creux <pcr...@gmail.com>: >>>> >>>>> Bonjour, >>>>> >>>>> Rails et daemon ne doivent pas faire bon ménage. >>>>> >>>>> Pour faire tourner des tâches de manière asynchrone dans une >>>>> application Ruby on Rails, je te conseille d'utiliser ActiveJob ( >>>>> http://guides.rubyonrails.org/active_job_basics.html) et Sidekiq. >>>>> >>>>> Bon courage! >>>>> >>>>> -- >>>>> φ <http://pcreux.com> >>>>> >>>>> >>>>> 2016-08-31 16:06 GMT+02:00 ziburudebian <devm...@gmail.com>: >>>>> >>>>>> Bonjour à tous >>>>>> >>>>>> J'utilise la gem *daemon *mais mon programme ne lit pas toutes les >>>>>> données de ma table client : il y a 5 enregistrements, il s'arrête au >>>>>> deuxième !!! ça fait trois jours que je cherche, j'en peux plus .... >>>>>> Voici mon code : >>>>>> >>>>>> *runexecution *est la fonction que je lance depuis le bouton de mon >>>>>> formulaire; elle est décrite dans >>>>>> *app/controllers/executions_controller.rb* >>>>>> >>>>>> class ExecutionsController < ApplicationController >>>>>> >>>>>> def runexecution >>>>>> # >>>>>> ============================================================================================================ >>>>>> # DESCRIPTION : Permet de demarrer ou arreter l'execution d'un >>>>>> script (action=start ou stop) >>>>>> # >>>>>> ============================================================================================================ >>>>>> require 'daemons' >>>>>> # ---------------------------- >>>>>> # traitement des parametres >>>>>> # ---------------------------- >>>>>> return "" if params.nil? # ce test permet de ne pas rentrer >>>>>> dans la fonction lors de l'appel via le menu >>>>>> action = "" >>>>>> params.each do |key,value| >>>>>> action = "start" if (key.index("loopstart") != nil) >>>>>> action = "stop" if (key.index("loopstop") != nil) >>>>>> end >>>>>> logger.info("******************action="+action) >>>>>> case action >>>>>> when "start" >>>>>> exedate = "2015-10-03 08:30" >>>>>> frequence = "0.05" >>>>>> listclientselectionne = "1-2-3-4-5" >>>>>> paramopt = "" >>>>>> options = {:ARGV => [action, paramopt, '--', exedate, >>>>>> frequence, listclientselectionne], >>>>>> :dir_mode => :script, >>>>>> :dir => 'tmp/pids', >>>>>> :multiple => true, >>>>>> :ontop => true, >>>>>> :mode => :load, >>>>>> :backtrace => true, >>>>>> :monitor => true, >>>>>> :log_output => true >>>>>> } >>>>>> logger.info("******************options="+options.to_s) >>>>>> Daemons.run('myserver.rb', options) >>>>>> logger.info("******************FIN") >>>>>> >>>>>> when "stop" >>>>>> logger.info("******************loopstop") >>>>>> else >>>>>> redirect_to executions_execution_path >>>>>> end # case action >>>>>> >>>>>> end # runexecution >>>>>> >>>>>> end #class >>>>>> >>>>>> le programme qui tourne en boucle est* myserver.rb* qui est à la >>>>>> racine de mon site : >>>>>> >>>>>> #!/usr/bin/env ruby >>>>>> ENV['RAILS_ENV'] ||= 'production' >>>>>> require File.expand_path('../config/environment', __FILE__) >>>>>> print "\nParametres= " + ARGV[0].to_s + "****" + ARGV[1] + "****" + >>>>>> ARGV[2] + "\n" >>>>>> exedate = ARGV[0] >>>>>> frequence = ARGV[1] >>>>>> listclientselectionne = ARGV[2] >>>>>> delai = frequence.to_f * 60 >>>>>> listclientselectionne = listclientselectionne.split("-") >>>>>> print "Nbclient=" + listclientselectionne.count.to_s + "\n" >>>>>> loop do >>>>>> print Time.now.to_s + "\n" >>>>>> listclientselectionne.each do |idcl| >>>>>> print idcl + "\n" >>>>>> begin >>>>>> print "avant\n" >>>>>> objclient = Client.find(idcl) >>>>>> print "apres\n" >>>>>> if (!objclient.nil?) >>>>>> print objclient.lastname.to_s + "\n" >>>>>> # print objclient.name + "\n" >>>>>> else >>>>>> print "Erreur sur " + idcl + "\n" >>>>>> end >>>>>> rescue ActiveRecord::RecordNotFound => e >>>>>> objclient = nil >>>>>> print "Erreur \n" >>>>>> end >>>>>> end >>>>>> sleep(delai) >>>>>> end >>>>>> >>>>>> et voici les résultat à 'écran >>>>>> >>>>>> => Booting Thin >>>>>> => Rails 4.1.7 application starting in production on >>>>>> http://0.0.0.0:3000 >>>>>> => Run `rails server -h` for more startup options >>>>>> => Notice: server is listening on all interfaces (0.0.0.0). Consider >>>>>> using 127.0.0.1 (--binding option) >>>>>> => Ctrl-C to shutdown server >>>>>> Thin web server (v1.6.4 codename Gob Bluth) >>>>>> Maximum connections set to 1024 >>>>>> Listening on 0.0.0.0:3000, CTRL+C to stop >>>>>> myserver.rb: process with pid 28318 started. >>>>>> >>>>>> Parametres= 2015-10-03 08:30****0.05****5-1-6-2 >>>>>> Nbclient=5 >>>>>> 2016-08-31 15:47:56 +0200 >>>>>> 1 >>>>>> avant >>>>>> apres >>>>>> DURANTON >>>>>> 2 >>>>>> avant >>>>>> apres >>>>>> VALENT >>>>>> 3 >>>>>> avant >>>>>> log writing failed. closed stream >>>>>> log writing failed. closed stream >>>>>> log writing failed. closed stream >>>>>> >>>>>> >>>>>> Si j'exécute le programme *myserver.rb* depuis la console avec *ruby >>>>>> myserver.rb 1 2 3 : *tout se passe bien; voici le stdout >>>>>> >>>>>> # ruby myserver.rb 1 2 3 >>>>>> Parametres= 1****2****3 >>>>>> Nbclient=5 >>>>>> 2016-08-31 16:04:10 +0200 >>>>>> 1 >>>>>> avant >>>>>> apres >>>>>> DURANTON888 >>>>>> 2 >>>>>> avant >>>>>> apres >>>>>> VALENT >>>>>> 3 >>>>>> avant >>>>>> apres >>>>>> VIGILE1AA >>>>>> 4 >>>>>> avant >>>>>> apres >>>>>> VIGILE2 >>>>>> 5 >>>>>> avant >>>>>> apres >>>>>> DURANDTON >>>>>> >>>>>> >>>>>> >>>>>> Si vous avez une idée >>>>>> >>>>>> Merci beaucoup >>>>>> >>>>>> *Ma config* >>>>>> >>>>>> - Debian GNU/Linux 7 >>>>>> - Rails 4.17 >>>>>> - Ruby 1.91 >>>>>> >>>>>> -- >>>>>> -- >>>>>> Vous avez reçu ce message, car vous êtes abonné au groupe >>>>>> "Railsfrance" de Google Groups. >>>>>> Pour transmettre des messages à ce groupe, envoyez un e-mail à >>>>>> l'adresse rails...@googlegroups.com >>>>>> Pour résilier votre abonnement envoyez un e-mail à l'adresse >>>>>> railsfrance...@googlegroups.com >>>>>> --- >>>>>> Vous recevez ce message, car vous êtes abonné au groupe >>>>>> Google Groupes "Railsfrance". >>>>>> Pour vous désabonner de ce groupe et ne plus recevoir d'e-mails le >>>>>> concernant, envoyez un e-mail à l'adresse >>>>>> railsfrance...@googlegroups.com. >>>>>> Pour obtenir davantage d'options, consultez la page >>>>>> https://groups.google.com/d/optout. >>>>>> >>>>> >>>>> -- >>>>> -- >>>>> Vous avez reçu ce message, car vous êtes abonné au groupe >>>>> "Railsfrance" de Google Groups. >>>>> Pour transmettre des messages à ce groupe, envoyez un e-mail à >>>>> l'adresse rails...@googlegroups.com >>>>> Pour résilier votre abonnement envoyez un e-mail à l'adresse >>>>> railsfrance...@googlegroups.com >>>>> --- >>>>> Vous recevez ce message, car vous êtes abonné au groupe Google Groupes >>>>> "Railsfrance". >>>>> Pour vous désabonner de ce groupe et ne plus recevoir d'e-mails le >>>>> concernant, envoyez un e-mail à l'adresse >>>>> railsfrance...@googlegroups.com. >>>>> Pour obtenir davantage d'options, consultez la page >>>>> https://groups.google.com/d/optout. >>>>> >>>> >>>> -- >> -- >> Vous avez reçu ce message, car vous êtes abonné au groupe "Railsfrance" >> de Google Groups. >> Pour transmettre des messages à ce groupe, envoyez un e-mail à l'adresse >> rails...@googlegroups.com <javascript:> >> Pour résilier votre abonnement envoyez un e-mail à l'adresse >> railsfrance...@googlegroups.com <javascript:> >> --- >> Vous recevez ce message, car vous êtes abonné au groupe Google Groupes >> "Railsfrance". >> Pour vous désabonner de ce groupe et ne plus recevoir d'e-mails le >> concernant, envoyez un e-mail à l'adresse railsfrance...@googlegroups.com >> <javascript:>. >> Pour obtenir davantage d'options, consultez la page >> https://groups.google.com/d/optout. >> > > -- -- Vous avez reçu ce message, car vous êtes abonné au groupe "Railsfrance" de Google Groups. Pour transmettre des messages à ce groupe, envoyez un e-mail à l'adresse railsfrance@googlegroups.com Pour résilier votre abonnement envoyez un e-mail à l'adresse railsfrance-unsubscr...@googlegroups.com --- Vous recevez ce message, car vous êtes abonné au groupe Google Groupes Railsfrance. Pour vous désabonner de ce groupe et ne plus recevoir d'e-mails le concernant, envoyez un e-mail à l'adresse railsfrance+unsubscr...@googlegroups.com. Pour plus d'options, visitez le site https://groups.google.com/d/optout .