[PYTHON] Rollback processing when an error occurs with fabric

By the way, the other day, I had the opportunity to have a friend see my post. "Kimoi, the picture is disgusting. Really disgusting? Has anyone ever pointed out?" I received a highly acclaimed comment.

fabric is a simple and very powerful tool.

However, it is also a dangerous tool depending on how it is used. You need to be very careful, especially when used by human debris like me.

Would I like to deploy something strange in the production environment today? Strange people (bosses and others) are watching the handcuffs jerky.

You have to be careful.

However, no matter how careful you are, an error will occur. Therefore, you have to give proper error handling so as not to break various things. If you get an error somewhere after editing the config file, The daemon never started again because I changed only the file, You have to roll back so that it doesn't happen.

Then, they return to their original state and leave as if nothing had happened. It's as if a human like me didn't exist from the beginning.

The irrelevant preface is the worst long, but it's a fabric rollback approach.

Basic way

The basis of rollback processing when an error occurs in fabric is to wrap it in ʻenv.warn_only = True`. Try not to abort suddenly, and if an error occurs, roll back carefully. That's the one.

with settings(warn_only=True):

    backup_important_file()

    run('sed -e "s/foo/bar/g" important_file > tmp_file')
    run('mv tmp_file important_file')

    result = do_something_bad()

    if result.return_code != 0:
        # Rollbacking…
        restore_important_file()

However, there are often multiple tasks performed by fabric.

If the rollback processing required for each task error is common, If you implement it obediently, it looks like this, for example.

env.warn_only=True

def task1():
    result = run('run command1')
    if result.return_code != 0:
        rollback()

def task2():
    result = run('run command2')
    if result.return_code != 0:
        rollback()

def task3():
    result = run('run command3')
    if result.return_code != 0:
        rollback()

def rollback():
    # Rollbacking...
    restore_everything()

@task
def do_it():
    task1()
    task2()
    task3()

This is often sufficient, but a slightly clearer method is possible.

How to prepare a wrapper

By preparing a wrapper function and utilizing the context manager, It is possible to combine the rollback processing of multiple tasks.

If the rollback process is common to multiple tasks, This is cleaner.

env.warn_only=False

def task1():
    run('run command1')

def task2():
    run('run command2')

def task3():
    run('run command3')

def rollback():
    # Rollbacking...
    restore_everything()

@contextmanager
def rollbackwrap():
    try:
        yield
    except SystemExit:
        rollback()
        abort("Error has occurred while running task!")

@task
def do_it():
    with rollbackwrap():
        task1()
        task2()
        task3()
        task4()

Where you want to handle errors individually

with settings(warn_only=True):

It would be good to use.

reference

I have referred to the following articles very much. http://awaseroot.wordpress.com/2012/06/05/fabric-wrappers-and-more-error-handling/

Recommended Posts

Rollback processing when an error occurs with fabric
A memorandum when an error occurs with pip install
What to do when an error occurs with import _ssl
When I get an error with PyInstaller
[Beanstalk] What to do when an error occurs with import uuid
Solution when an error occurs when hiding the console screen with PyInstaller
I got an error when saving with OpenCV
What to do if an error occurs when importing numpy with VScode
An error occurs when importing japandas (problem unsolved)
An error occurs when trying to import scikit-learn after connecting to Oracle with SQLAlchemy
I got an error when using Tensorboard with Pytorch
Error when playing with python
When coverage fails with _sqlite3 error
When I get an error with Pylint in Atom on Windows
I get an error when trying to install maec 4.0.1.0 with pip
I get an error with import pandas.
Create an image processing viewer with PySimpleGUI
Note when creating an environment with python
When doing sam build with AWS Lambda Layers, the file hierarchy changes and an import error occurs.
[Arch linux] Solution when package-query error occurs
[OSX] [pyenv] What to do when an SSL error occurs in pip
[AWS] How to deal with WordPress "An error occurred when cropping an image."
What to do if an error occurs when loading a python project created with poetry into VS Code
Workaround if you get an error when trying to install PySide with pip
[Python] I want to know the variables in the function when an error occurs!
I got an error when I put opencv in python3 with Raspberry Pi [Remedy]
[python] What to do when an error occurs in send_keys of headless chrome
What to do if you get an error when installing python with pyenv
If you get a long error when tabbing an interactive shell with Anaconda
Error when installing a module with Python pip
Let's write FizzBuzz with an error: Python Version
Error when entering virtual environment with workon command
I get an error with all yum commands
[Python] Type Error:'WebElement' object is not iterable What to do when an error occurs
What to do if you get an OpenSSL error when installing Python 2 with pyenv
Investigate the cause when an error is thrown when python3.8 is not found when using lambda-uploader with python3.8
What to do if you get an Import Error when importing matplotlib with Jupyter
I got an error when pip install pandas on Mac, so I dealt with it
A story about an error when loading a TensorFlow model created with Google Colab locally
An introduction to Python distributed parallel processing with Ray
I get an error when I put opencv in pyautoGUI
Building an environment for natural language processing with Python
When writing an if statement with a regular expression
When you get an error in python scraping (requests)
I got an error when pip install tweepy on macOS Sierra, so I dealt with it
(Vagrant) Handling of Permission denied (publickey, gssapi-keyex, gssapi-with-mic) error that occurs when connecting with SSH
What to do if you get an Undefined error when trying to use pip with pyenv