15

I was a bit remiss to find that Octopus, as amazing as it is, doesn't do anything cute or clever about shutting down your web app before it is upgraded.

In our solution we have two web apps (a website and a separate API web app) that rely on the same database, so while one is being upgraded the other is still live and there is potential that web or API requests are still being serviced while the database is being upgraded.

Not clean!

Clean would be for Octopus to shut down the web apps, wait until they are shut-down and then go ahead with the upgrade, bring the app pools back online once complete.

How can that be achieved?

Ian Robinson
  • 16,892
  • 8
  • 47
  • 61
Jason Glover
  • 618
  • 5
  • 13

4 Answers4

17

Selfie-answer!

It is easy to make Octopus-deploy take a little extra care with your deployments, all you need is a couple of extra Execute-Powershell steps in your deployment routine.

Add a new first step to stop the app pool:

# Settings
#---------------
$appPoolName = "PushpayApi" # Or we could set this from an Octopus environment setting.

# Installation
#---------------
Import-Module WebAdministration     
       # see http://technet.microsoft.com/en-us/library/ee790588.aspx

cd IIS:\


if ( (Get-WebAppPoolState -Name $appPoolName).Value -eq "Stopped" )
{
    Write-Host "AppPool already stopped: " + $appPoolName
}

Write-Host "Shutting down the AppPool: " + $appPoolName
Write-Host (Get-WebAppPoolState $appPoolName).Value

# Signal to stop.
Stop-WebAppPool -Name $appPoolName

do
{
    Write-Host (Get-WebAppPoolState $appPoolName).Value
    Start-Sleep -Seconds 1
}
until ( (Get-WebAppPoolState -Name $appPoolName).Value -eq "Stopped" )
# Wait for the apppool to shut down.

And then add another step at the end to restart the app pool:

# Settings
#---------------
$appPoolName = "PushpayApi"

# Installation
#---------------
Import-Module WebAdministration     
       # see http://technet.microsoft.com/en-us/library/ee790588.aspx

cd IIS:\

if ( (Get-WebAppPoolState -Name $appPoolName).Value -eq "Started" )
{
    Write-Host "AppPool already started: " + $appPoolName
}

Write-Host "Starting the AppPool: " + $appPoolName
Write-Host (Get-WebAppPoolState $appPoolName).Value

# To restart the app pool ... 
Start-WebAppPool -Name $appPoolName

Get-WebAppPoolState -Name $appPoolName
Jason Glover
  • 618
  • 5
  • 13
11

The approach we took was to deploy an _app_offline.htm (App Offline) file with the application. That way we get a nice message explaining why the site is down.

Then when it is time for deployment we use Mircrosofts Webdeploy to rename the it to app_offline.htm. We put the code for the rename in a powershell script that runs as the first step of our Octopus Deployment.

write-host "Website: $WebSiteName"

# Take Website Offline
$path = "$WebDeployPath";
$path

$verb = "-verb:sync";
$verb

# Take root Website offline
$src = "-source:contentPath=```"$WebSiteName/_app_offline.htm```"";
$src

$dest = "-dest:contentPath=```"$WebSiteName/app_offline.htm```"";
$dest
Invoke-Expression "&'$path' $verb $src $dest"; 


# Take Sub Website 1 offline
$src = "-source:contentPath=```"$WebSiteName/WebApp1/_app_offline.htm```"";
$dest = "-dest:contentPath=```"$WebSiteName/WebApp1/app_offline.htm```"";
Invoke-Expression "&'$path' $verb $src $dest"; 

$WebSiteName is usually "Default Web Site". Also note that the ` are not single quotes but actually the backtick character (usually found with the tilda on your keyboard).

Now if octopus is deploying your web site to a new location, your web site will come back online automatically. If you don't want that, you can deploy the new website with the app_offline file allready in place. Then you can use the following script to remove it.

write-host $WebSiteName

# & "c:\Program Files (x86)\IIS\Microsoft Web Deploy V2\msdeploy.exe" -verb:delete -dest:contentPath="$WebSiteName/app_offline.htm"
# those arn't QUOTES!!!!, they are the back accent thing.  

write-host "Website: $WebSiteName"

# Put Web app Online.
$path = "$WebDeployPath";
$path

$verb = "-verb:delete";
$verb

$dest = "-dest:contentPath=```"$WebSiteName/app_offline.htm```"";
$dest
Invoke-Expression "&'$path' $verb $dest"; 

# Put Sub Website Online
$dest = "-dest:contentPath=```"$WebSiteName/WebApp1/app_offline.htm```"";
Invoke-Expression "&'$path' $verb $dest";
RMK
  • 877
  • 1
  • 9
  • 16
  • 1
    I played around with that approach too, but when your website has background threads you can't be sure they have completed their work before the next Octopus step begins. – Jason Glover Nov 19 '13 at 18:32
  • 2
    So it sounds like the ideal approach is to use both? – The Muffin Man Jul 13 '14 at 05:39
  • Could create a temp app pool to host the `app_offline.htm`. Remap the application to use that app pool for the time of deployment, shutdown the actual application pool and then in the end do reverse steps. – Alex M Jun 10 '15 at 12:47
2

Stopping apppool and/or setting App_Offline file is not enough for me. Both didn't give proper explanation to clients why site is down. Especially App_Offline. I need to clean up bin folder and this causes YSOD (http://blog.kurtschindler.net/more-app_offline-htm-woes/).

My solution: First task redirects deployed site to different folder containing only index.html with proper message. Last task brings back original folder.

DecimalTurn
  • 3,243
  • 3
  • 16
  • 36
dariol
  • 1,959
  • 17
  • 26
0

A better solution would be to use a network load balancer such as the f5 LTM. You can set up multiple servers to receive traffic for your site and then, when you are deploying, you can just disable the one node in the NLB so all the other traffic goes to the other machine.

I like the f5 because it is very scriptable. When we deploy to our websites we take no outage whatsoever. all traffic to the site is just pointed to the server that is not currently being upgraded.

There are caveats:

You must script the downing disable of the pool member in the NLM so that it works with your site. If your site requires sessions (such as depending on session state or shared objects) then you have to bleed the traffic from the NLB nodes. in f5 you can just disable them and then watch for the connection count to go to zero (also scriptable).

You must enforce a policy with your deveopers / dbas that states that all database changes MUST NOT cause degradation or failure in the existing code. This means that you have to be very careful with the databases and configurations. That way you can do your database updates before you even start deploying to the first pool of your website.

Ian
  • 1