На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! В разделе обсуждаются следующие темы:
1) Процесс разработки программного обеспечения.
2) Определение требований к программному обеспечению.
3) Составные части и процесс проектирования (см. Шаблоны проектирования).
4) Документирование программного продукта(проекта).
5) Руководство разработкой программного обеспечения.
6) Проектирование пользовательского интерфейса.
7) Контроль версий проекта (см. Управление версиями в Subversion, Стратегии использования svn).
Модераторы: ElcnU
  
> Транзакционная безопасность в общем виде
    Привет!

    Расскажите пожалуйста про транзакционную безопасность. В проекте есть утилитка, которая:
    1. Читает файлы, базу и некий сторонний сервис.
    2. Применяет высокотехнологичную интеллектуальную логику.
    3. Пишет в файлы, в базу и в некий сторонний сервис.

    Почти в каждой операции с большой вероятностью может произойти ошибка. Что, собственно, и происходит. Ситуация усугубляется тем, что утилитка эта очень аджайловая: очень часто требуется поменять логику. Реже меняется схема базы. "Никогда" не меняются файлы и интерфейс стороннего сервиса. Основная проблема - логика. Если натыкать много обработки исключений, логика сильно размазывается и возникают сложности с её модификациями. Если обработки исключений натыкать мало, получается что некоторые операции, которые семантически хотелось бы видеть атомарными, ведут себя не очень атомарно. Есть очень большое желание иметь логику оформленной достаточно концентрированно - вот чтобы логика и никакого мусора вокруг.

    (если пока ничего не понятно, в простейшем случае задача звучит так: написать "процедуру" копирования папки с файлами из одного места в другое, процедура должна вести себя атомарно - или всё копируется и все счастливы, или, если не удалось прочитать хотя бы один файл, не копируется ничего).

    Подскажите, пожалуйста, варианты решений. Вот что сейчас крутится в голове:

    1. Возможно, есть какой-то секретный фреймворк, который поможет такого добиться (да, речь, кстати, про .NET 2.0)
    2. Нужно сделать фреймворк, который будет реализовывать концепции Atomic Action (Do/Undo) и Transaction (Commit/Rollback), все операции переписать через эти концепции, логику абстрагировать. В голове крутятся паттерны Command/Memento/Interpreter. Больная фантазия где-то на фоне требует полноценный DSL, но пока удаётся её сдерживать. Даже без DSL можно добиться приемлемого результата.
    3. Забить и по-тупому работать с исключениями - этого не хочется.

    Поругайте-похвалите мысли, поделитесь своими :-)

    Заранее спасибо.
      Черт его знает. Звучит заумно.
      В С++ это всё без особых хлопот решается реализацией RAII, например (условный С++ код):
      ExpandedWrap disabled
        class TransactionCtrl
        {
            SomeDBCtrl& m_db;
            bool m_committed;
         
        public:
            TransactionCtrl(SomeDBCtrl& db) : m_db(db), m_committed(false)
            {
                m_db.start_transaction();
            }
         
            ~TransactionCtrl()
            {
                if( !m_committed )
                    m_db.rollback();
            }
         
            commit()
            {
                m_db.commit();
                m_committed = true;
            }
        };
         
        some_db_updates()
        {
            TransactionCtrl tc(db);
         
            update ...
            update ...
            update ...
         
            tc.commit();
        }
      А вот как обстоят дела с реализацией идиомы RAII в .NET - :-? Судя по возникшему вопросу - не очень хорошо?
        Ну, по поводу RAII скажем так... он есть, но некрасивый. Вот я о чём говорил:
        ExpandedWrap disabled
              ...
              public interface IAction
              {
                  void Do(IContext context);
                  void Undo(IContext context);
              }
                  ...
                  // фейковые экшены
                  // GoodAction - действие которое всегда хорошо коммитится и роллбэчится
                  // CustomAction - это такой тул, чтобы описывать экшены прямо инплэйс
                  ...
                  static void Main()
                  {
                      var transaction1 = new Transaction("read 3 files");
                      
                      // TreatExceptionAsWarningActionDecorator - волшебный декоратор, который трактует эксепшны как ворнинги
                      transaction1.Add(new TreatExceptionAsWarningActionDecorator(new GoodActionWithBadRollback("that will crash on rollback")));
                      transaction1.Add(new GoodAction("read file 1"));
                      transaction1.Add(new GoodAction("read file 2"));
                      transaction1.Add(new GoodAction("read file 3"));
                      
                      var transaction2 = new Transaction("import data");
                      transaction2.Add(new GoodAction("create package"));
                      transaction2.Add(transaction1);
                      transaction2.Add(new GoodAction("write to db"));
                      
                      // вот делаем инплэйс экшн
                      transaction2.Add(new CustomAction(
                          "do some stuff 1",
                          delegate // ду
                          {
                              Console.WriteLine("DOING SOME STUFF 1");
                              throw new InvalidOperationException();
                          },
                          delegate // анду
                          {
                              Console.WriteLine("UNDOING SOME STUFF 1");                    
                          }
                          ));
           
                      transaction2.Add(new CustomAction(
                          "do some stuff 2",
                          ctx => Console.WriteLine("DOING SOME STUFF 2"),
                          ctx => Console.WriteLine("UNDOING SOME STUFF 2")
                          ));
           
                      var rootContext = new RootContext(new ConsoleNotifiable());
                      try
                      {
                          rootContext.Do(transaction2); // коммитим транзакцию
                          Console.WriteLine("DONE!"); // если попали сюда, значит коммит прошёл
                          rootContext.Undo(transaction2); // пытаемся её откатить (просто отменить всё)
                      }
                      catch (TransactionFailedAndThenRollbackFailed)
                      {
                          // транзакция сломалась где-то посередине. начали откатывать, а откат тоже сломался :-(
                          Console.WriteLine("ERROR: transaction failed and then rollback failed");
                      }
                      catch (TransactionRollbackFailedException)
                      {
                          // пытались откатить успешную транзакцию, а оно не вышло :-(
                          Console.WriteLine("ERROR: transaction rollback failed");
                      }
                      catch (TransactionFailedExceptionButRollbackSucceeded)
                      {
                          // транзакция прошла нормально, решили сделать роллбэк, но не сложилось :-(
                          Console.WriteLine("ERROR: transaction failed, but rollback succeeded");
                      }
                  }

        И вот такая трассировка:
        ExpandedWrap disabled
           trying to import data
           trying to create package
           create package info: good action
           create package succeeded
           trying to read 3 files
           trying to ~that will crash on rollback
           trying to that will crash on rollback
           that will crash on rollback succeeded
           ~that will crash on rollback succeeded
           trying to read file 1
           read file 1 info: good action
           read file 1 succeeded
           trying to read file 2
           read file 2 info: good action
           read file 2 succeeded
           trying to read file 3
           read file 3 info: good action
           read file 3 succeeded
           read 3 files succeeded
           trying to write to db
           write to db info: good action
           write to db succeeded
           trying to do some stuff 1
          DOING SOME STUFF 1
           do some stuff 1 failed: Operation is not valid due to the current state of the object.
           trying to revert write to db
           revert write to db succeeded
           trying to revert read 3 files
           trying to revert read file 3
           revert read file 3 succeeded
           trying to revert read file 2
           revert read file 2 succeeded
           trying to revert read file 1
           revert read file 1 succeeded
           trying to revert ~that will crash on rollback
           trying to revert that will crash on rollback
           revert that will crash on rollback warn: Operation is not valid due to the current state of the object.
           revert ~that will crash on rollback succeeded
           revert read 3 files succeeded
           trying to revert create package
           revert create package succeeded
           import data failed: Exception of type 'ACID.TransactionFailedExceptionButRollbackSucceeded' was thrown.
          ERROR: transaction failed, but rollback succeeded


        Хреново?
          А разве это
          ExpandedWrap disabled
            public class Smth : IDisposable
            {
              public bool IsCommited { get; set; }
              public Smth() { IsCommited = false; }
             
              public void Commit() { IsCommited = true; }
             
              public void Dispose()
              {
                 if (!IsCommited) { .. }
              }
            }
             
            using (var smth = new Smth())
            {
               smth.Commit();
            }


          не подходит?
            Это подходит если у тебя одна операция. 2 операции - 2 юзинга писать? 10 операций? Я немного уточню. Есть некий алгоритм, который состоит из последовательности обращений к разным ресурсам. Обращения бывают на запись и на чтение. Что там на чтение - пофиг, но для записи хочется иметь возможность делать откат типа: сделал файл - снёс файл, или снёс файл - вернул файл (типа не удалять, а копировать в секретное место и только потом удалять исходный, а если откат делать - просто копировать обратно). Т.е. буквально нужна штука, которая будет следить сколько пунктов из алгоритма отработало и при необходимости делать откат. Это можно либо руками написать - много кода, либо небольшой фреймворк сделать - меньше кода, но писать немного извращённо придётся. Других вариантов я пока не вижу.
              Я хз :whistle:
              System.Transactions не из этой области? Я в свое время читал-читал, но так ничего и не понял..
                Выглядит реально страшно, попробую посмотреть что это. Спасибо.
                  Из моих знакомых это никто так и не осилил :lol:
                  0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                  0 пользователей:


                  Рейтинг@Mail.ru
                  [ Script execution time: 0,0392 ]   [ 15 queries used ]   [ Generated: 27.04.24, 09:30 GMT ]