http://www.perlmonks.org?node_id=1015757

ambrus has asked for the wisdom of the Perl Monks concerning the following question:

Suppose I have a CGI script running on a public webserver. This script consists of a top-level script and multiple perl module source files. From time to time I improve the script and then I install new versions of all the files. I'd like to make sure that no running instance of the script can see an inconsistent state of the install if it's running at the same time as I'm doing the install.

Currently my install command just copies all the files to the place where they're used from. This means that the CGI script could be started before the install, but load a module later, after the install. This and other races are what I'd like to stop.

I don't care if I have to temporarily make the webpage unavailable for a short period during the install, that is, if a user tries to use the CGI during such an unfortunate time, it's okay if they get a 403 error or a broken connection. It's also okay if the install has to wait for a short time until all already started instances of the CGI exit. It is not okay however to have to stop the whole Apache webserver for the installation (the webserver serves webpages other than this CGI), reboot the machine, or otherwise break some functionality on the host.

I'd like to know if there's an existing good practice to solve this. If there isn't, I can probably invent some new solution, but that would probably be ugly.

  • Comment on Install updated version of script such that running instances cannot use an inconsistent state

Replies are listed 'Best First'.
Re: Install updated version of script such that running instances cannot use an inconsistent state
by Corion (Patriarch) on Jan 28, 2013 at 21:03 UTC

    My approach is to have the following directory layout:

    /corion/App-0.01/ /corion/App-0.02/ /corion/App-0.03/ /corion/App/ -> /corion/App-0.03 # a symlink

    Then, when I'm staging App v0.04, I will copy all the files from 0.03 (plus the changes that make 0.04 0.04), stop the server for App v0.03, copy its database (most often, SQLite) to 0.04, and then move the symlink to point to 0.04 and start the (0.04) server again.

    That way, I can easily fall back to using 0.03, should my testing have gone wrong or the database migration have gone wrong in some way. I also have now written me a shell script that shows me a diff between the new version directory and the current symlink before it copies the database, so I can do a final review of what changes go live.

Re: Install updated version of script such that running instances cannot use an inconsistent state
by LanX (Saint) on Jan 28, 2013 at 21:03 UTC
    > I'd like to make sure that no running instance of the script can see an inconsistent state of the install if it's running at the same time as I'm doing the install.

    Just an idea and not any proven best practice:

    Could you work with two alternate install paths in @INC? Like having a topdir with a timestamp or version or so?

    The old CGI would still be using the old path it was started with, and as soon all old instances are gone you can delete the old paths.

    Should also be good strategy for fall back if anything goes wrong...

    Cheers Rolf

Re: Install updated version of script such that running instances cannot use an inconsistent state
by BrowserUk (Patriarch) on Jan 28, 2013 at 22:14 UTC

    'scuse me for talking about thing I know little of, but if ...

    1. You replace the top level cgi with one that just produces a 403...
    2. delay
    3. replace all the things used by the top level cgi
    4. replace the temporary TL with the new one.

    The only question is how long should the delay be.

    And that comes down to a) are any of the resources conditionally required or autoused rather than used; b) are you using a persistent environment.


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Install updated version of script such that running instances cannot use an inconsistent state
by tobyink (Canon) on Jan 28, 2013 at 21:19 UTC

    Write your installation script so that it does things in the following order:

    1. Deletes the existing CGI scripts
    2. Pause for one second
    3. Deletes the existing modules
    4. Installs replacement modules
    5. Installs replacement CGI scripts
    package Cow { use Moo; has name => (is => 'lazy', default => sub { 'Mooington' }) } say Cow->new->name

      How do you know that one second is enough? A CGI script could run for longer than that sometimes.

        True, but I'd generally expect it to have at least finished compiling.

        package Cow { use Moo; has name => (is => 'lazy', default => sub { 'Mooington' }) } say Cow->new->name
Re: Install updated version of script such that running instances cannot use an inconsistent state
by Anonymous Monk on Jan 29, 2013 at 00:11 UTC
    You've got to stop the web server. There's no other way. Especially if something like mod_perl could be involved.
Re: Install updated version of script such that running instances cannot use an inconsistent state
by karlgoethebier (Abbot) on Jan 29, 2013 at 11:02 UTC

    Imho best (and most save) practice: scheduled downtime or whatever you like to call it. Perhaps you can manage it do be down < 60s ( practicising before on a test system, at job early in the morning... )?

    Regards, Karl

    «The Crux of the Biscuit is the Apostrophe»