web-dev-qa-db-fra.com

Rails 3 et Heroku: automatiquement "rake db: migrate" sur push?

J'ai un léger ennui avec mon processus heroku Push/deploy, qui a été autrement une joie à découvrir et à utiliser. 

Si j'ajoute une nouvelle migration à mon application, la seule façon de l'obtenir sur le serveur heroku est d'effectuer un Push vers la télécommande heroku. Cette télécharge et redémarre l'application. Mais il ne lance pas la migration, donc je dois faire heroku rake db:migrate --app myapp, puis heroku restart --app myapp. Dans l'intervalle, l'application est endommagée car elle n'a pas exécuté les migrations et le code fait référence à des champs/tables, etc., dans la migration.

Il doit y avoir un moyen de changer le processus de déploiement pour exécuter le rake db:migrate automatiquement dans le cadre du processus de déploiement, mais je ne peux pas le résoudre. 

Est-ce quelque chose que je mets dans un Herpan Cpanel? Est-ce une option que je passe à heroku à partir de la ligne de commande? Est-ce un crochet git? Quelqu'un peut-il me remettre en ordre? merci max

61
Max Williams

Voici une tâche de rake qui résume tout dans une ligne (et prend également en charge la restauration):

https://Gist.github.com/362873

Vous pouvez toujours vous retrouver à déployer en plus de la démo de votre patron, mais au moins vous ne perdez pas de temps à taper entre le git Push et le rake db:migrate.

29
Paul A Jungwirth

Qu'en est-il de cette solution de chaînage de commande simple:

git Push heroku master && heroku run rake db:migrate

Il exécutera automatiquement la migration dès que le premier se terminera avec succès. C'est typiquement 1-2 secondes de retard ou moins.

32
Cristian

Heroku a maintenant la capacité de gérer cela dans le cadre de sa fonction de "phase de publication".

Vous pouvez ajouter un processus appelé release à votre Procfile et qui sera exécuté à chaque déploiement.

Rails> = 5 Exemple

release: bundle exec Rails db:migrate

Exemple de rails <5

release: bundle exec rake db:migrate

32
Max Woolf

J'ai créé un buildpack personnalisé qui permet à Heroku d'exécuter rake db:migrate pour vous automatiquement lors du déploiement. C'est juste une branche du buildpack Ruby par défaut de Heroku, mais avec la tâche rake db:migrate ajoutée.

Pour l'utiliser avec votre application, procédez comme suit:

heroku config:set BUILDPACK_URL=https://github.com/dtao/rake-db-migrate-buildpack

Notez également que pour que cela fonctionne, vous devez activer la fonctionnalité user-env-compile Heroku Labs. Voici comment vous faites cela:

heroku labs:enable user-env-compile

Et voici ma preuve que cela fonctionne:

rake db:migrate on Heroku deployment

14
Dan Tao

Vous pourriez peut-être essayer de séparer vos commits de schéma (migrations, etc.) des commits de code (modèles, validations, etc.).

(Notez que ce qui suit suppose que vos modifications de migration ne sont PAS destructives, car vous avez indiqué qu'elles couvraient la plupart de vos cas d'utilisation.)

Votre processus de déploiement pourrait alors être:

  1. Transférer les modifications de schéma dans Heroku
  2. émigrer
  3. Envoyer le code de l'application à Heroku

Ceci est bien sûr optimal, mais constitue un moyen efficace d’éviter les temps morts dans la situation que vous avez décrite: au moment où l’application reçoit le code pour les champs dynamiques, la base de données aura déjà migré.

(Bien entendu, la solution la plus simple serait simplement de pousser et de migrer pendant que votre patron est en train de déjeuner ;-D)

Sinon, même si les modifications de schéma étaient effectuées automatiquement, vous courriez le risque de voir une demande transiter juste avant que les migrations aient été exécutées.

9
David Sulc

Juste pour ces gens googler comme moi, je veux donner une solution simple ici.

J'utilise Rails 4 et j'avais besoin d'ajouter une tâche simple de rake au déploiement sur heroku. Comme j'utilise le bouton 'deploy to heroku' dans github, il n'y a aucune chance de lancer "heroku run ..." immédiatement après le déploiement.

Ce que j'ai fait: J'ai étendu les ressources standard de la tâche de rake 'nettoyage:' qui est automatiquement exécuté lors d'un déploiement sur heroku. La tâche se déroule toujours normalement mais j'ai attaché mes propres données à la fin. Ceci est fait avec la méthode 'enhancement' . Dans l'exemple ci-dessous, j'ajoute une base de données: migrate car c'est probablement ce que la plupart des gens veulent:

# in lib/tasks/assets_clean_enhance.rake
Rake::Task['assets:clean'].enhance do
  Rake::Task['db:migrate'].invoke
end

J'avoue que ce n'est pas une solution parfaite. Mais le heroku Ruby Buildpack ne supporte toujours pas d’autre manière. Et écrire mon propre buildback semblait un peu exagéré pour une chose aussi simple.

5
Kari

J'ai écrit SmartMigrate buildpack qui est un package de construction Heroku simple pour avertir des migrations en attente après la construction de Ruby à chaque fois que de nouvelles migrations sont détectées. Ce buildpack est destiné à faire partie d’un Multipack qui possède un buildpack Ruby précédent.

En respectant les autres solutions proposées ici, ce buildpack présente 3 avantages par rapport à ceux-ci:

  1. Pas besoin de mode maintenance
  2. Plus besoin de fourches obsolètes pour le buildpack Ruby qui insèrent simplement la migration à la fin
  3. Pas besoin d'exécuter les migrations TOUT LE TEMPS, un avertissement s'affiche uniquement si de nouvelles migrations sont détectées depuis le dernier déploiement.
2
hammady

J'utilise une tâche de rake pour mettre l'application en mode maintenance, Push, migrer et la déplacer hors du mode maintenance.

2
Aditya Sanghi

Je pense que l'approche de David Sulc est la seule qui garantisse que vous évitez que les demandes soient traitées lorsque l'application est en panne.

C'est un peu pénible, mais peut être nécessaire dans certaines circonstances.

Comme il l'a dit, cela nécessite que les migrations de la base de données soient non destructives. 

Cependant, il peut s'avérer difficile de forcer vos migrations et vos modifications de schéma avant le reste du code, car l'approche évidente ('git Push heroku {revnum}') repose sur le fait que vous avez vérifié les migrations avant le reste du code.

Si vous ne l'avez pas déjà fait, il est toujours possible de le faire en utilisant une branche temporaire:

  • Créez une branche, basée sur la révision git que vous avez récemment poussée à heroku:

    git branch <branchname> <revnum-or-tag>
    
  • Découvrez cette branche:

    git checkout <branchname>
    
  • Si vos validations de migration de base de données ne contenaient que des migrations et qu'aucun changement de code n'était effectué, sélectionnez les validations contenant les modifications apportées à la base de données:

    git cherry-pick <revnum1> <revnum2>...
    
  • Si vous avez validé vos modifications de base de données dans des révisions contenant également des modifications de code, vous pouvez utiliser 'git cherry-pick -n' qui ne se commettra pas automatiquement; utilisez 'git reset HEAD' pour supprimer les fichiers qui ne sont pas des modifications de la base de données de l'ensemble des éléments à valider. Une fois que vous avez juste les modifications de la base de données, validez-les dans votre branche temporaire.

    git cherry-pick -n <revnum1> <revnum2>...
    git reset HEAD <everything that's modified except db/>
    git status
    ... check that everything looks ok ...
    git commit
    
  • Poussez cette branche temporaire vers heroku (idéalement vers une application de mise en scène pour vérifier que vous avez bien compris la situation, car éviter les temps morts est le point essentiel pour sauter dans ces cerceaux).

    git Push heroku <branchname>:master
    
  • Exécuter les migrations

    heroku run rake db:migrate
    
  • À ce stade, vous pourriez penser que vous pourriez simplement pousser «maître» vers heroku pour obtenir les modifications de code. Cependant, vous ne pouvez pas, car ce n'est pas une fusion à avance rapide. La façon de procéder consiste à fusionner le reste de 'maître' dans votre branche temporaire, puis à le fusionner avec le maître, ce qui recombine les historiques de validation des deux branches:

    git checkout <branchname>
    git merge master
    git diff <branchname> master
    ... shouldn't show any differences, but just check to be careful ...
    git checkout master
    git merge <branchname>
    
  • Vous pouvez maintenant transmettre le fichier maître à heroku comme d'habitude, ce qui entraînera le reste de vos modifications de code.

Dans l'avant-dernière étape, je ne suis pas sûr à 100% de la nécessité de fusionner le maître avec {branchname}. En procédant ainsi, vous obtiendrez une fusion rapide, ce qui rend git heureux lorsque vous appuyez sur heroku, mais il serait peut-être possible d'obtenir le même résultat en fusionnant simplement {nom de la branche} avec master sans cette étape.

Bien sûr, si vous n'utilisez pas «maître», remplacez le nom de la branche appropriée aux endroits appropriés ci-dessus.

1
sheltond

J'utilise le heroku_san gem comme outil de déploiement depuis un certain temps. C'est un outil simple et ciblé de Nice pour la migration Push +. Il ajoute quelques autres commandes de rake qui facilitent l’accès à d’autres fonctions (comme la console). En plus de ne pas avoir à me souvenir des migrations de base de données, ma fonction préférée est son fichier de configuration Heroku - ainsi je peux nommer tous mes serveurs (production, mise en scène, playground4, shirley) comme je le veux - et les garder dans ma tête. 

0
slothbear