Чистый и эффективный способ обработки операций отмены файловой системы в контекстном менеджере - PullRequest
0 голосов
/ 19 февраля 2019

Я работаю над системой управления активами для личного проекта.Мой вопрос заключается в том, как аккуратно и эффективно обрабатывать операции с файловой системой в python, чтобы я мог откатывать или отменять изменения, если что-то пойдет не так.

Типичная операция может выглядеть примерно так

 try
   file system operation(s)
   update database
 except Exceptions
   undo file system operations already performed
   rollback database transaction
   handle exceptions

Операциями с файловой системой могут быть такие вещи, как создание, копирование, связывание и удаление файлов / каталогов

Моя идея заключалась в том, чтобы иметь диспетчер контекста как для операций с файловой системой, так и для управления базой данных.Выполнение будет примерно таким:

# create new asset
with FileSystemCM as fs, DatabaseCM as db:

    fs.create_dir(path_to_asset)
    fs.create_file(path_to_a_file_this_asset_needs)
    db.insert('Asset_Table', asset_name)

Теперь, если, например, db.insert завершается неудачно, FileSystemCM удаляет вновь созданный файл и вновь созданный каталог, а DatabaseCM откатывает транзакцию db

Простой подход к моей реализации FileSystemCM будет выглядеть примерно так:

class FileSystemCM(object):
    """ File System Context Manager """

    def __init__(self):

        self.undo_stack = [] # list of (fn, args, kwargs)

    def __enter__(self):

        return self

    def __exit__(self, exception_type, exception_val, traceback):

        if exception_type:
            # pop undo actions off the stack and execute
            while self.undo_stack:
                undo_fn, args, kwargs = self.undo_stack.pop()
                undo_fn(*args, **kwargs)

    def create_dir(self, dir_path):

        create_file(dir_path)
        self.undo_stack.append((remove_dir, [dir_path], {'force': True}))

    def create_file(self, file_path):

        create_file(file_path)
        self.undo_stack.append((remove_file, [file_path], {'force': True}))

Есть ли лучший подход к этому?Существуют обстоятельства, при которых эта реализация не справляется, и я мог бы использовать обратную связь при удалении файлов

  • .Мои мысли состоят в том, чтобы переместить файлы для удаления во временную папку (или создать жесткую ссылку tmp), если все пойдет нормально, удалите временные файлы или ссылки, в противном случае верните их обратно.Но это может привести к следующей ситуации.

  • код __exit__, вызывающий исключение и не завершающий операции отмены, возможно, я оставляю файл журнала, чтобы, по крайней мере, что-то можно было почистить вручную?

1 Ответ

0 голосов
/ 20 февраля 2019

Я имел в виду это как комментарий, но это слишком долго, чтобы поместиться в разделе комментариев.Позвольте мне начать с того, что это звучит как очень интересный проект (по крайней мере, на мой вкус).

Некоторое время назад (я не могу вспомнить, где) я прочитал статью о реализации функциональности Undo / Redo,и что они делают, это поддерживают два отдельных стека (один для отмены и один для повторения).Когда пользователь выполняет действие, пара action / its-reverse со своими аргументами помещается в стек отмены действий.Всякий раз, когда пользователь выполняет действие отмены, выполняется обратное действие из пары, и затем пара перемещается в стек повторного выполнения, и когда действие повторения выполняется, выполняется действие из пары, и пара возвращается в стек отмены.,

Всякий раз, когда пользователь выполняет новое действие, стек повторных операций очищается.Единственный недостаток этого подхода - необратимые действия.Один из способов, который я могу придумать для преодоления этого, - это использовать какие-то шаблоны Event-Sourcing, где вы сохраняете все состояние системы и ее различия.Это может показаться очень неэффективным, но обычно используется в программном обеспечении.

...