How to deploy an ASP.NET Application with zero downtime

35,068

Solution 1

You need 2 servers and a load balancer. Here's in steps:

  1. Turn all traffic on Server 2
  2. Deploy on Server 1
  3. Test Server 1
  4. Turn all traffic on Server 1
  5. Deploy on Server 2
  6. Test Server 2
  7. Turn traffic on both servers

Thing is, even in this case you will still have application restarts and loss of sessions if you are using "sticky sessions". If you have database sessions or a state server, then everything should be fine.

Solution 2

The Microsoft Web Deployment Tool supports this to some degree:

Enables Windows Transactional File System (TxF) support. When TxF support is enabled, file operations are atomic; that is, they either succeed or fail completely. This ensures data integrity and prevents data or files from existing in a "half-way" or corrupted state. In MS Deploy, TxF is disabled by default.

It seems the transaction is for the entire sync. Also, TxF is a feature of Windows Server 2008, so this transaction feature will not work with earlier versions.

I believe it's possible to modify your script for 0-downtime using folders as versions and the IIS metabase:

  • for an existing path/url:
  • Copy new (or modified) website to server under
    • \web\app\v2.1\
  • Modify IIS metabase to change the website path
    • from \web\app\2.0\
    • to \web\app\v2.1\

This method offers the following benefits:

  • In the event new version has a problem, you can easily rollback to v2.0
  • To deploy to multiple physical or virtual servers, you could use your script for file deployment. Once all servers have the new version, you can simultaneously change all servers' metabases using the Microsoft Web Deployment Tool.

Solution 3

You can achieve zero downtime deployment on a single server by utilizing Application Request Routing in IIS as a software load balancer between two local IIS sites on different ports. This is known as a blue green deployment strategy where only one of the two sites is available in the load balancer at any given time. Deploy to the site that is "down", warm it up, and bring it into the load balancer (usually by passing a Application Request Routing health check), then take the original site that was up, out of the "pool" (again by making its health check fail).

A full tutorial can be found here.

Solution 4

I went through this recently and the solution I came up with was to have two sites set up in IIS and to switch between them.

For my configuration, I had a web directory for each A and B site like this: c:\Intranet\Live A\Interface c:\Intranet\Live B\Interface

In IIS, I have two identical sites (same ports, authentication etc) each with their own application pool. One of the sites is running (A) and the other is stopped (B). the live one also has the live host header.

When it comes to deploy to live, I simply publish to the STOPPED site's location. Because I can access the B site using its port, I can pre-warm the site so the first user doesn't cause an application start. Then using a batch file I copy the live host header to B, stop A and start B.

Solution 5

OK so since everyone is downvoting the answer I wrote way back in 2008*...

I will tell you how we do it now in 2014. We no longer use Web Sites because we are using ASP.NET MVC now.

We certainly do not need a load balancer and two servers to do it, that's fine if you have 3 servers for every website you maintain but it's total overkill for most websites.

Also, we don't rely on the latest wizard from Microsoft - too slow, and too much hidden magic, and too prone to changing its name.

Here's how we do it:

  1. We have a post build step that copies generated DLLs into a 'bin-pub' folder.

  2. We use Beyond Compare (which is excellent**) to verify and sync changed files (over FTP because that is widely supported) up to the production server

  3. We have a secure URL on the website containing a button which copies everything in 'bin-pub' to 'bin' (taking a backup first to enable quick rollback). At this point the app restarts itself. Then our ORM checks if there are any tables or columns that need to be added and creates them.

That is only milliseconds downtime. The app restart can take a second or two but during the restart requests are buffered so there is effectively zero downtime.

The whole deployment process takes anywhere from 5 seconds to 30 minutes, depending how many files are changed and how many changes to review.

This way you do not have to copy an entire website to a different directory but just the bin folder. You also have complete control over the process and know exactly what is changing.

**We always do a quick eyeball of the changes we are deploying - as a last minute double check, so we know what to test and if anything breaks we ready. We use Beyond Compare because it lets you easily diff files over FTP. I would never do this without BC, you have no idea what you are overwriting.

*Scroll to the bottom to see it :( BTW I would no longer recommend Web Sites because they are slower to build and can crash badly with half compiled temp files. We used them in the past because they allowed more agile file-by-file deployment. Very quick to fix a minor issue and you can see exactly what you are deploying (if using Beyond Compare of course - otherwise forget it).

Share:
35,068
Karl Glennon
Author by

Karl Glennon

Co-founder and CTO of Roomex.com @karlroomex

Updated on November 26, 2021

Comments

  • Karl Glennon
    Karl Glennon over 2 years

    To deploy a new version of our website we do the following:

    1. Zip up the new code, and upload it to the server.
    2. On the live server, delete all the live code from the IIS website directory.
    3. Extract the new code zipfile into the now empty IIS directory

    This process is all scripted, and happens quite quickly, but there can still be a 10-20 second downtime when the old files are being deleted, and the new files being deployed.

    Any suggestions on a 0 second downtime method?

    • Daniel Rodriguez
      Daniel Rodriguez over 14 years
      Shouldn't this be on ServerFault?
    • Karl Glennon
      Karl Glennon about 14 years
      Perhaps, but ServerFault didn't exist in Sep '08
    • Neil McGuigan
      Neil McGuigan about 12 years
      Can IIS point to a symlink folder? Will changing the symlink cause IIS process to recycle?
    • Kiquenet
      Kiquenet over 11 years
      any final solution with full source code script sample?
    • Luke
      Luke over 8 years
      Isn't it possible to have multiple app pools and switch the traffic from one app pool to another?
  • Admin
    Admin over 14 years
    You can also configure the load balancer so that it services existing sessions for a given server, but doesn't accept new ones. That allows you to avoid dropping sessions. This technique however requires waiting for the sessions to end, and in general you'll want to script this.
  • EBarr
    EBarr over 13 years
    This method tends to fall down when the code roll has structural changes to the database. Once you upgrade the DB for Server 1, server 2 will explode. Now you can backup/restore the database for testing on server 1, but then you have the issue of sorting out the data that changed in the live DB while while the parallel copy was running.
  • EBarr
    EBarr over 13 years
    Same issue as @Sklivvz -- This method falls down as soon as the code roll has structural changes to the database.
  • EBarr
    EBarr over 13 years
    This helps with downtime due to file copy, but has the same issue as @Sklivvz -- as soon as the code roll has structural changes to the database the site goes boom.
  • EBarr
    EBarr over 13 years
    Unfortunately, this method doesn't account for structural changes to the DB. Once you upgrade the DB for v2.1 then v.2.0 explodes.
  • RickNZ
    RickNZ over 13 years
    That's why I said it was more involved when there are DB changes... Rolling out code with structural changes to the DB is not just a deployment issue; there also has to be support in the code, and probably in the DB too.
  • RickNZ
    RickNZ over 13 years
    Using TxF is overkill here, IMO. It doesn't hurt anything to have both v2.0 and v2.1 in the filesystem at the same time. The big change happens when v2.1 goes online, and by that time, the TxF transaction has been committed. The zero downtime really happens because of the way IIS moves from an old AppPool to a new one, not because of TxF.
  • Andrei Rînea
    Andrei Rînea over 13 years
    @EBarr : Have version 2 point to a different DB altogether. This way you can keep server 2 on version 1 while upgrading server 1.
  • EBarr
    EBarr over 13 years
    @AndreiRinea -- how do you suppose this would work in an high volume OLTP system? Either the system goes out of sync and you loose data when you cut over, or you need to pause data entry and write a script to identify & migrate the transitory data to the new DB structure.
  • Andrei Rînea
    Andrei Rînea over 13 years
    @EBarr : In cases of a high-volume OLTP system you will need to take down for maintenance the whole system, after you warn well in advance users and prohibit logins after a certain moment.
  • EBarr
    EBarr over 13 years
    @Andrei Rinea --- exactly my point! Look at my first comment ....the method above fails. Which begs the question posed by @Recursieve --"how to deploy an asp.net application with zero down time?"
  • Sklivvz
    Sklivvz over 13 years
    @EBarr: Unless you plan your db changes for zero downtime, forget about it. If you use stored procedures this is always possible (maybe involving the use of mirroring with a witness).
  • Sklivvz
    Sklivvz over 13 years
    @EBarr: and in any case technically you still have zero downtime on the ASP.NET app -- the question isn't "how to deploy to a sql server db with zero downtime".
  • Kenny Evitt
    Kenny Evitt over 12 years
    Another problem with this is if a large amount of user data is stored in subfolders of the app folders.
  • Petrus Theron
    Petrus Theron about 12 years
    This seemed like the intuitive way to me as well, but why isn't there an easy, built-in way to do this?
  • Jack
    Jack over 11 years
    won't work when there are dependencies outside of the web app (like a db) because IIS processes old and new requests IN PARALLEL
  • Jack
    Jack over 11 years
    This can work if your load balancer (or webserver) has the ability to temporarily "hold" http requests ... but I don't know of any
  • Kiquenet
    Kiquenet over 11 years
    any full source code script sample about it? Powershell maybe
  • Kiquenet
    Kiquenet over 11 years
    @sklivvz, any full source code script sample about it? is it possible, Powershell maybe
  • Akira Yamamoto
    Akira Yamamoto over 11 years
    @Kenny Evitt you can avoid putting user data inside app folders and subfolders and then put outside the app folder. You can use a Web.config app key to manage between different environments =)
  • Yosoyadri
    Yosoyadri about 11 years
    Powershell script for zero downtime deployment using ARR in a single machine: github.com/yosoyadri/IIS-ARR-Zero-Downtime/blob/master/…
  • Sam
    Sam almost 11 years
    When this causes an app-restart, will it forcefully stop any existing requests, or will it gracefully do so?
  • Bealer
    Bealer over 10 years
    They key is to develop in a way that your sql changes aren't destructive. You often have to do any destructive sql changes in the following release once it's no longer used. It's not hard to do with practise.
  • Sklivvz
    Sklivvz over 10 years
    @Bealer that issue is relevant in any configuration: if you depend on more than one component each change should be backwards compatible to interop with the rest.
  • Bealer
    Bealer over 10 years
    @Ebarr then don't roll out destructive sql changes. For example, if you need to remove a column, do so in the next release when it's no longer used by A or B.
  • EBarr
    EBarr over 10 years
    @Bealer -- agreed (with caveat).There is a whole series of these questions on "downtime during code roles". I have yet to find one that really discusses the realities of evolving a DB schema. Caveat - there are a variety of complications that come along with two-phase changes to schema. One example -- many of the ORMs barf if the table definition differs from the definition as it understand it (new or missing columns).
  • Andrew Gee
    Andrew Gee over 10 years
    @Rob how can you "pre-warm" the site if it is stopped?
  • George Tsiokos
    George Tsiokos about 10 years
    @Quandary session should always be out of process - never use <sessionState mode="InProc" in production
  • arni
    arni over 9 years
    Can anyone comment on TxF support in MsDeploy and how to enable it? I cannot seem to find any information on this.
  • usr
    usr over 9 years
    This is not 0 second deployment because the new app needs to start up.
  • testpattern
    testpattern over 8 years
    I like this approach for a single-server setup. It may not be up to you what the infrastructure looks like.
  • testpattern
    testpattern over 8 years
    But, you will still get downtime because the app pool recycles.
  • mike nelson
    mike nelson over 8 years
    Nope, no downtime because requests are buffered automatically by IIS during the app restart
  • Sklivvz
    Sklivvz over 8 years
    @AminM buy or rent another? :-) Apart from jokes, you can have two version running on the same server, but you'd still need a load balancer to direct the traffic, acting as a reverse proxy as well in this case.
  • Justin J Stark
    Justin J Stark about 6 years
    @Rob "copy the live host header to B" Can you explain this?