Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rolling back to previous release #9

Closed
ghost opened this issue Jun 12, 2012 · 26 comments
Closed

Rolling back to previous release #9

ghost opened this issue Jun 12, 2012 · 26 comments

Comments

@ghost
Copy link

ghost commented Jun 12, 2012

I am currently using Vlad and Mina looks like a much cleaner alternative as Vlad isn't maintained much anymore.

I might be missing something obvious but is there a way to roll back to a previous release?

@mikong
Copy link
Member

mikong commented Jun 13, 2012

Not yet. But it's next in our list:

https://trello.com/c/tdnUZtqL

@ghost
Copy link
Author

ghost commented Jun 13, 2012

Great, thanks.

I must say, I've just switched my first project to Mina from Vlad which was largely painless and the deployment is much simpler all in all. Many thanks for a great project.

One other problem I ran into was when some existing Vlad releases existed and I ran mina deploy:cleanup, it completely blitzed my current release, leaving no current release... this was a bit of a showstopper and deploys wouldn't work until I manually cleaned up the releases directory.

One other small niggle is that I'm not keen on the to :launch etc. syntax, it's not entirely clear what is going on... maybe just an explicit method that excepts a block would be better e.g.

task :deploy do
  deploy do
    # Put things that prepare the empty release folder here.
    # Commands queued here will be ran on a new release directory.
    invoke :'git:clone'
    invoke :'bundle:install'

    # These are instructions to start the app after it's been prepared.
    restart do
      queue 'touch tmp/restart.txt'
    end

    # This optional block defines how a broken release should be cleaned up.
    clean do
      queue 'log "failed deployment"'
    end
  end
end

@rstacruz
Copy link
Member

re: the :launch syntax:

that's my invention and I hate it myself! we've been toying with the idea of changing it to simply:

task :deploy do
  deploy do
    invoke :'git:clone'
    invoke :'other:things:here'
  end
end

task :restart do
  queue "sudo service myapp restart"
end

... that is, simply assuming that the :restart task is the way to restart it. This way, you also get a bonus of getting to implement mina restart in a nice, conveniently DRY manner.

Comments and suggestions welcome.

@ghost
Copy link
Author

ghost commented Jul 19, 2012

Yes, much prefer that. I guess the same could be true for the "clean" block i.e. this could also become it's own task?

I'm trying to think of a way to remove the "deploy" block also to save on the additional nesting as essentially all it does it run the "deploy.sh.erb" stuff after yielding the block. Maybe the stuff in "deploy.sh.erb" could be made into another standard task (I'm thinking "update" like Vlad does), it could then use the queue method etc. to run all those bits. Just a thought.

Once everything is a standard task, the "deploy" task could be as simple as:

task :deploy => [:'git:clone', :'bundle:install', :'rails:db_migrate', :'other:stuff', :update, :restart]

I would actually like to see simpler task names as whichever scm you are using, there will be a clone/checkout stage, some kind of database migration is usually needed whichever language/framework you are using (could be blank task by default) and the "bundle:install" task could be the default for the "bundle" namespace... we would end up with something like:

task :deploy => [:clone, :bundle, :migrate, :update, :restart]

Much cleaner... most or if not all of this can be achieved without breaking the existing functionality, what do you think? I'm happy to have a crack at this if you are in agreement.

I will be writing a blog post on Mina soon over at http://thelucid.com as I'm loving it compared to Vlad or Capistrano so might hold off for a few days if there are likely to be implementation changes.

@rstacruz
Copy link
Member

task :deploy => [:'git:clone', :'bundle:install', :'rails:db_migrate', :'other:stuff', :update, :restart]

This Cap/Vlad-like syntax is not going to happen, sorry. Let me explain, though... it's part of what makes Mina special.

Right now, you can chain tasks in that way. For instance, you may do the following, which makes mina slow_deploy work the same as doing mina local:test deploy remote:test.

task :slow_deploy => [:'local:test', :deploy, :'remote:test']

However, deploying is something different. Most Mina tasks are merely used to queue lines of Bash code in. This concept is incredibly simple:

task :tail do
  queue "echo Checking error logs"
  queue "tail -f /var/www/error.log"
end

# invoking "mina tail" simply runs the following bash script remotely.
# You can verify this with "mina --simulate":
#
#     echo Checking error logs
#     tail -f /var/www/error.log
#

In a deployment, you have to wrap your invokes and queues inside a deploy do ... end block. This certain deploy script below illustrates the point:

task :deploy do
  deploy do
    queue "wget http://foo.com/my_latest_code.tgz"
    queue "tar xvf my_latest_code.tgz"
  end
end

Running this via --simulate tells you that it concatenates the code very differently:

#!/usr/bin/env sh
cd /var/www/myproject.com
echo "-----> Creating build path..."
mkdir -p tmp/build-283943
echo "-----> Doing deploys..."
cd tmp/build-283943 &&
(
  wget http://foo.com/my_latest_code.tgz
) && (
  tar xvf my_latest_code.tgz
) && (
  echo "----> Deploy succeeded!"
) || (
  echo "! Deploy failed, rolling back"
  rm -rf tmp/build-283943
  exit 256
)

...of course, the actual script is much longer, but I've shorted it to illustrate the point.

What happened here? The deploy do...end block captured your queued items and put them together differently by placing it into a deploy script boilerplate.

You will not be able to do this simply by task :deploy => [:one, :two, :three].

@rstacruz
Copy link
Member

Also, I would say no on the shortening of task names. It provides no value and makes the abstraction deeper than it actually should be. Can you just swap SCM addons (from git to svn, for instance) and expect everything to work? Can you make another "app framework" addon that implements its own migrate + bundle (and so on) and swap them out at will? Probably not.

Renaming them to generic names (eg, migrate meaning to simply invoke any migrations it should do, versus rails:db_migrate which specifically invokes database migrations for rails projects) only gives us another layer of abstraction that's not necessary. Today, one glance at a deploy block lets you somewhat figure out what a deploy script actually does, whereas if they were generic names, you would have to look up the definitions for each name to figure out what each would do.

@ghost
Copy link
Author

ghost commented Oct 10, 2012

Fair enough.

Did you go with assuming a restart task instead of the launch block in the end? If so what about the clean block, couldn't this assume a clean task also?

@clodeindustrie
Copy link

Hi there,

Has any work been started regarding the rollback feature?

@nicolai86
Copy link

👍 for this feature! But it's quite easy to just DIY, right?

@NARKOZ
Copy link

NARKOZ commented Nov 1, 2013

@rstacruz is there any ETA for this feature?

@nathanbertram
Copy link
Contributor

+1

1 similar comment
@gabskoro
Copy link
Member

+1

@v9n
Copy link

v9n commented Jan 27, 2014

Bump this up. It's over 2 years and seems nobody put it a good care.
I think we should make this a simple

mina rollback

what it does it simply remove the last releast, re-point symlink to the previous releas.

And move on.

@mbahar
Copy link

mbahar commented Feb 19, 2014

you can use this to roll back;

but be carefull; if you rollback more than the number of deployed releases; you will get NIL

desc "Roll backs the lates release"
task :rollback => :environment do

queue! %[echo "-----> Rolling back to previous release for instance: #{domain}"]

remove latest release folder (active release)

queue %[echo "-----> Deleting active release : "]
queue %[ls "#{deploy_to}/releases" -Art | sort | tail -n 1]
queue! %[ls "#{deploy_to}/releases" -Art | sort | tail -n 1 | xargs -I active sudo rm -rf "#{deploy_to}/releases/active"]

delete existing sym link and create a new symlink pointing to the previous release

queue %[echo "-----> Creating new symlink from the previous release: "]
queue %[ls "#{deploy_to}/releases" -Art | sort | tail -n 1]
queue! %[sudo rm "#{deploy_to}/current"]
queue! %[ls -Art "#{deploy_to}/releases" | sort | tail -n 1 | xargs -I active sudo ln -s "#{deploy_to}/releases/active" "#{deploy_to}/current"]

end

@tmandry
Copy link

tmandry commented Mar 13, 2014

Here's an improved version of the above script. It switches the release atomically and doesn't use sudo.

desc "Rolls back the latest release"
task :rollback => :environment do
  queue! %[echo "-----> Rolling back to previous release for instance: #{domain}"]

  # Delete existing sym link and create a new symlink pointing to the previous release
  queue %[echo -n "-----> Creating new symlink from the previous release: "]
  queue %[ls "#{deploy_to}/releases" -Art | sort | tail -n 2 | head -n 1]
  queue! %[ls -Art "#{deploy_to}/releases" | sort | tail -n 2 | head -n 1 | xargs -I active ln -nfs "#{deploy_to}/releases/active" "#{deploy_to}/current"]

  # Remove latest release folder (active release)
  queue %[echo -n "-----> Deleting active release: "]
  queue %[ls "#{deploy_to}/releases" -Art | sort | tail -n 1]
  queue! %[ls "#{deploy_to}/releases" -Art | sort | tail -n 1 | xargs -I active rm -rf "#{deploy_to}/releases/active"]
end

@reicheltd
Copy link

+1 would be a great addition for using mina/rails. Ive been using mina for 1.5 years now for sinatra apps. the first time now with rails. capistrano is a pain

@AnatoliiD
Copy link

what about migrations?

@jerefrer
Copy link

jerefrer commented Nov 2, 2014

+1 for integrating it in mina. Anyway, thanks for the task @tmandry :)

@jmuheim
Copy link

jmuheim commented Jan 27, 2015

+1

@born4new
Copy link

+1, Thanks @tmandry !

@mcescalante
Copy link

+1 @tmandry nice task to take care of it for the time being!

@jerefrer
Copy link

jerefrer commented Mar 9, 2015

For @d4be4st ... HURRAY \o/

@jmuheim
Copy link

jmuheim commented Mar 9, 2015

👍 💃

@d4be4st
Copy link
Member

d4be4st commented Mar 10, 2015

Mina v0.3.3 released with rollback feature

@elfuego
Copy link

elfuego commented May 7, 2015

In #9 (comment) use for sort sort -n to make sure the release numbers are not sorted as strings but as numbers.

@dmersiowsky
Copy link

Improvement for #9 (comment), #9 (comment), also using #9 (comment):

First: Tank you for sharing, I'd have gone nuts without the existing examples.
@elfuego @tmandry @mbahar

New feature: This one checks if a release to possibly roll back to does even exist.
If not, it does not execute the rollback.

Since

mina deploy:rollback

does not do this, I'm afraid it's useless for me.

Code:

    desc "Rolls back the latest release"
    task :rollback => :environment do
        queue %[echo "-----> Rolling back to previous release for instance: #{domain}"]

        # ls command below must return two rows. first of the two contains the 2nd latest version.
        queue! %[last=`ls "#{deploy_to}/releases" -Art | sort -n | tail -n 2 | sed -n '1p'`]
        queue! %[current=`ls "#{deploy_to}/releases" -Art | sort -n | tail -n 2 | sed -n '2p'`]

        # sanity check: are both versions actual numbers? is the target folder available?
        queue! %[
            if [ ! -n "$last" ] || [ ! -n "$current" ] || [ ! -d "#{deploy_to}/releases/$last" ];
            then
                echo "ERROR: No version to roll back to!";
                exit 1;
            fi
          ]

        queue %[echo "Moving from $current to $last"]

        # remove latest release folder (active release)
        queue! %[ls "#{deploy_to}/releases" -Art | sort -n | tail -n 1 | xargs -I active rm -rf "#{deploy_to}/releases/active"]

        # delete existing sym link and create a new symlink pointing to the previous release
        queue! %[rm "#{deploy_to}/current"]
        queue! %[ls -Art "#{deploy_to}/releases" | sort -n | tail -n 1 | xargs -I active ln -s "#{deploy_to}/releases/active" "#{deploy_to}/current"]
    end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests