eval { TX: { # step 1: database $dbh->do("CREATE DATABASE foo"); push @undo, sub { $dbh->do("DROP DATABASE foo"); }; # step 2a: filesystem mkdir "/path/foo" or last TX; push @undo, sub { rmdir "/path/foo" }; # step 2b push @undo, sub { remove_tree "/path/foo" }; create_a_bunch_of_files_in("/path/foo") or last TX; # step 3: logger (usually also on filesystem) write_log("Database and files setup") or last TX; # step 4: email (it's okay to fail this step) send_email('foo@bar.com'); # mark success @undo = (); } # rollback, we force each step even though it dies for (reverse @undo) { eval { $_->() }; } };