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

Let's say you want to write an innocent Perl script called main.pl, which when called as main.pl -f FILENAME does the following:
  • makes a system call to encrypt the file
  • ftps the encrypted file to a server
  • waits for the encrypted file to disappear from the server
  • downloads a file called xfer.asc
  • decrypts xfer.asc to xfer.rtp

    Now, for the gotcha: this program is transferring precious military data from the US to Switzerland, and if it fails at any point in the process, millions of dollars will be at stake, not to mention your head will be on a stake.

    The goal then, is not just to execute the program, but to perform each step, announcing the entry into the step, execution of the step, and completion of the step. If completion is successful, we move on to the next step. If it is not successful we send email notification of its failure. and try again. Even if the failure is due to the machine going down, the script must take a look at what it tried and continue its efforts from just where it was when the script went down.

    • Comment on Mechanisms for Fault-Tolerant Perl Scripting
  • Replies are listed 'Best First'.
    Re (tilly) 1: Mechanisms for Fault-Tolerant Perl Scripting
    by tilly (Archbishop) on Oct 09, 2000 at 20:34 UTC
      This calls for a database and transactions.

      Seriously.

      Keep a small table of open jobs in a database table. For each step open a transaction, select a job, and attempt to do one step. If you succeed update the table with the new information about what comes next and commit the transaction. If you fail send email and rollback the transaction. Should you crash unexpectedly, it is up to the database to ensure that there is a reliable record of your current state.

      Just be sure that each of your labelled steps is one which from the time you open a transaction to the time you commit it, can be restarted from scratch without penalty.

      Should you wish to create a log of your actions, that log can be kept in the database as well.

        I think two things about my question are implicit that I will now make explicit:
      • I like the database idea. The only catch is state preservation. In a language like Lisp, where data and function are interchangeable and all data and function has a unique printed representation, executable "codelets" can be written and positions and the "codelets" stores in a tilly-esque transaction. In perl, code blocks do not have a printed and re-executable representation unless you break down to string manipulations to create and eval your code, which is highly unstructured and error-prone.
      • What we have hear is what Douglas Hofstadter defined as GOD in "Goedel, Escher, Bach, the Eternal Golden Braid." GOD == God Over Djinn. So each god has a higher God ad infinitum. Once you have the database serving as a god for the simple perl code, you have to ask who is the God for the database code? And then God for that?

        And then we conclude that linear thinking leads to the unreal, impossible, and irrational concept known as infinity --- scientfic man's attempt to justify a day-to-day practical form of reasoning (linear) when cyclical reasoning is actually a bit more suited to reasoning about Universal truths.

          I would make state an enumerated type. There is no need to have the database know the details of how a step is to happen or what language it is implemented in. Conversely there are significant security issues in trusting such information from a database machine. Should your database be spoofed or compromised, it is better to just have your process fail rather than giving the attacker a chance to compromise your machine as well!

          The God for the database code is the fact that it is designed to properly log all transactions and be in a position where at all times it is in a consistent state on disk. Even if there is hardware failure. And if you have a hot backup, you may even be protected from that.

          Getting failover, etc right is a hard problem. Databases already solve it, so leverage off of what they do rather than rolling your own.

          Note that this basic transaction-oriented strategy scales to very complex problems, and gives you systems that are robust by default. (One I dealt with got nicknamed "accidentally robust" because of how many unexpected error conditions came up, had never been considered, and didn't cause serious problems.) Normally when you rely on certain things having just worked and others being about to, when something goes wrong (eg a done file doesn't get written) things careen off-course into a nightmare. But with this strategy you automatically stop at a point where minimal damage has happened, other parts of the process can continue, and when the underlying problem is fixed, you are generally in an easily recoverable state...

    Re: Mechanisms for Fault-Tolerant Perl Scripting
    by merlyn (Sage) on Oct 09, 2000 at 20:32 UTC
      I'd not use FTP then. Why not HTTP over SSL? Then you have immediate feedback about the success, and encryption is built-in!

      -- Randal L. Schwartz, Perl hacker

    Re: Mechanisms for Fault-Tolerant Perl Scripting
    by lhoward (Vicar) on Oct 09, 2000 at 20:41 UTC
      Also you have to consider :

      If there's a failure, you're relying on e-mail to deliver your failure notification... e-mail isn't exactly the most reliable mechanism out there.

    Re: Mechanisms for Fault-Tolerant Perl Scripting
    by extremely (Priest) on Oct 10, 2000 at 01:18 UTC

      You are talking about a stage queue. Something like journalling filesystems do. Stage Queuing needs to be tuned to the individual app. I did this once for signup data at an ISP. The CGI wrote a file in a queue directory and then tried to go send the request. If it succeeded, it wiped the file. A cron job swept thru every minute and looked for files who were older than 5 minutes, killed their cgi and tried it itself. Any file older than 1 minute with no cgi got tried too.

      It's a royal pain in the butt and you have to do all kinds of forward and back checks to make sure you don't flood yourself with duplicates, lose important data and more. Worse, your front line interaction system needs to understand all of that and sniff what stage it's at if the user disconnects and comes back.

      And after all that; it maybe fixed two customers automatically in 6 months. You need this almost never. =) It better be real improtant or it just ain't worth it.

      --
      $you = new YOU;
      honk() if $you->love(perl)