Title: RE: [Nant-users] Transactionality in NAnt

I'm afraid this isn't working for me.

Our system is structured like this:

default.build is our bootstrapper. It sets up shared properties for all of the builds and loops through a CSV file calling the specified targets against ProjectTemplate.build for each line in the CSV file with the <nant> task.  This calls each Target in a separate instance of nant against ProjectTemplate.build.  If I include the Rollback.xml in ProjectTemplate.build, then it can only rollback in the scope of the current targets and the stack is useless.  If I include Rollback.xml in default.build, then the stack is always lost at the end of each <nant> task.

This gets back to my earlier point that this needs to be transitory between nested calls to the <nant> task.  This obviously is possible for nant.onfailure to exist and function, but there needs to be a way to build a stack between n number of calls to the <nant> task. 

Now, thinking about this also makes me realize that not only does rollback need to call the targets, but they need to call the targets with the correct parameters to recreate the environment that existed when the rollback action was added to the stack. To me this implies maybe it's not going to be feasible to implement such a feature without building the transactionality directly into NAnt because the complete project state must be stored on the stack to allow the rollback action to have complete knowledge of the state at the time of pushing to the transaction stack.  I understand this could be a rather large memory overhead, but we could also write an xml document in a temp file to describe the stack and modify it on the fly.  Using a file to represent the stack allows the <nant> task to be spawned to a new thread or processes.

Payton Byrd
Trane eBusiness
QED Team
Phone: 931-905-5386
Fax: 931-648-5901

-----Original Message-----
From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED]] On Behalf Of Troy Laurin
Sent: Tuesday, January 25, 2005 11:14 PM
To: [EMAIL PROTECTED] Sourceforge. Net
Subject: Re: [Nant-users] Transactionality in NAnt

Merrill Cornish wrote:
> Bevan,
>
>
>>>>every task needs to have built in "smarts" to support rollback.
>
>
> Perhaps you have suggested an elegant way of providing
 > transaction-like operation while not putting undue stress
 > on Charlie.
>
> What if each <target> definition could include an OPTIONAL
 > error recovery <target>.  As long as you can get by with
 > target-level rollback (rather than task-level), it should
 > give most of the hooks you need while not being a huge,
 > buggy burden to implement.
>
> Merrill

May I suggest a solution that provides full reverse-rollback
functionality with out-of-the-box NAnt 0.85?
Completely flexible, configurable, and not spaghetti code.  Well, IMHO.
  Comments welcome and invited.

Features:
  * Arbitrary level of rollback control.  You can specify rollback
blocks per task, per target, or per set of tasks.
  * 100% control over rollback behaviour.  The person who knows best
what needs to be done to roll a particular action back is you.

Drawbacks:
  * This is all-or-nothing rollback.  There's no way to specify
checkpoints, or to continue processing after rolling back and recovering.
  * Somewhat fragile.  If anyone messes with any of the magic
properties, then rollback will fail.

If someone really wanted a more robust rollback mechanism, then the idea
behind what's going on below can be translated into a set of tasks with
little difficulty... register a build listener to react to onfailure (or
onsuccess, if you want commit support!) events and trigger rollback, you
could also offer explicit rollback (and commit) tasks, as well as nested
or grouped transactions.  There's no need to go messing with the NAnt
core to do something which is 100% process.


The solution itself!  Tested to work in 0.85 rc1.  Play around with the
failure in the test script... move it around, and confirm that it will
only roll back tasks that have been performed.


File 1: General include file "rollback.xml"
<project name="Rollback">
     <property name="nant.rollback.onfailure.chain"
         value="${nant.onfailure}"
             if="${property::exists('nant.onfailure')}" />
     <property name="nant.rollback.onfailure.chain"
         value=""
         unless="${property::exists('nant.onfailure')}" />
     <!-- If nant.onfailure is already set, set up an onfailure
          chain so all onfail targets are called -->

     <property name="nant.onfailure" value="rollback" />
     <property name="rollback.stack" value="" />
     <!-- Initialise the rollback stack -->

     <target name="rollback">
         <echo level="Debug"
             message="Rollback stack = &quot;${rollback.stack}&quot;" />
         <foreach item="String" in="${rollback.stack}" delim=" "
             property="rollback.target">
             <if test="${string::get-length(rollback.target) > 0}">
                 <!-- Skip empty targets, presumably from extra
                      delimiters -->
                 <call target="${rollback.target}"
                     if="${target::exists(rollback.target)}" />
                 <echo level="Warning"
                     message="Rollback target ${rollback.target} unknown"
                     unless="${target::exists(rollback.target)}" />
             </if>
         </foreach>
         <if test="${target::exists(nant.rollback.onfailure.chain)}">
             <!-- Continue the onfailure chain -->
             <call target="${nant.rollback.onfailure.chain" />
         </if>
     </target>
</project>

File 2: Specific build file "rollback-test.xml"
<project name="RollbackTest" default="all">
     <include buildfile="rollback.xml" />

     <target name="foo.perform">
         <echo message="Performing foo..." />
         <property name="rollback.stack"
             value="${rollback.stack} foo.rollback" />
     </target>
     <target name="foo.rollback">
         <echo message="Rolling back foo!" />
     </target>

     <target name="bah.perform">
         <echo message="Performing bah step 1..." />
         <property name="rollback.stack"
             value="${rollback.stack} bah.rollback.1" />
         <fail message="Failed!" />
         <echo message="Performing bah step 2..." />
         <property name="rollback.stack"
             value="${rollback.stack} bah.rollback.2" />
     </target>

     <target name="bah.rollback.1">
         <echo message="Rolling back bah step 1!" />
     </target>
     <target name="bah.rollback.2">
         <echo message="Rolling back bah step 2!" />
     </target>

     <target name="all" depends="foo.perform, bah.perform" />
</project>


-T


-------------------------------------------------------
This SF.Net email is sponsored by: IntelliVIEW -- Interactive Reporting
Tool for open source databases. Create drag-&-drop reports. Save time
by over 75%! Publish reports on the web. Export to DOC, XLS, RTF, etc.
Download a FREE copy at http://www.intelliview.com/go/osdn_nl
_______________________________________________
Nant-users mailing list
Nant-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/nant-users

Reply via email to