Обработка переходных ошибок с использованием SQL Azure с использованием платформы Entity Framework - программирование

Обработка переходных ошибок с использованием SQL Azure с использованием платформы Entity Framework

В настоящее время я использую SQL Azure и Entity SQL в своем приложении.

например.

Entities model = new Entities();
db_Item item = model.db_Item.First();

Теперь я хочу использовать обработку переходных ошибок из Enterprise Library, но нет никаких примеров или решений, которые я могу найти, что позволило бы мне сделать что-то вроде переопределения класса Entities, поэтому мне не нужно обновлять мои код в сотнях мест.

Может ли кто-нибудь предоставить дополнительную информацию о том, как это можно сделать?

4b9b3361

Ответ 1

Пройдя через то, что у меня есть до сих пор.

  • Entity Framework не предоставляет доступ к открытому соединению и разделу, где SQL отправляется на сервер, поэтому в настоящее время невозможно обеспечить повторную логику в этой области.

  • Команда EF знает об этом недостатке и планирует фактически интегрировать логику повтора в EF для возможной версии 6.

  • В соответствии с № 3 из [1] вы можете отправить команду SQL в базу данных OnContextCreated. Это, однако, означает для КАЖДОГО одного вызова БД, которое вы делаете в БД, вам придется сделать 2. Я бы не рекомендовал это ни в какой ситуации, если вы не заботитесь о производительности.

  • Единственный жизнеспособный вариант до сих пор реализует логику повтора в виде блока приложений для обработки заявок на переходный процесс Enterprise Library [2] вокруг каждого вызова, который вы делаете в базе данных. В существующих приложениях это очень утомительно.

  • Когда я получаю время, я смотрю дальше в исходный код EF, чтобы узнать, можно ли что-то сделать дальше, пока мы ждем EF 6. Я буду следить за [3]

  • Некоторая надежда, в настоящее время она пересматривается командой EF. [4]

Обновление: 2013-11-14

Просто подумал, что я бы обновил этот пост, чтобы все знали, что EF6 выпущен и поддерживает отказоустойчивость. https://www.nuget.org/packages/EntityFramework/

Нет необходимости в обходных решениях.

Обновление: 2013-03-23 ​​

EF 6 Alpha 3, выпущенный с отказоустойчивостью соединения - http://entityframework.codeplex.com/wikipage?title=Connection%20Resiliency%20Spec

Обновление: 2012-11-04

Команда EF официально объявила, что она запланирована для EF 6. [4]

[1] http://blogs.msdn.com/b/appfabriccat/archive/2010/12/11/sql-azure-and-entity-framework-connection-fault-handling.aspx

[2] http://msdn.microsoft.com/en-us/library/hh680934(v=pandp.50).aspx

[3] http://entityframework.codeplex.com/wikipage?title=Roadmap

[4] http://data.uservoice.com/forums/72025-entity-framework-feature-suggestions/suggestions/2426525-automatically-perform-retry-logic-for-sql-azure

Ответ 2

К счастью, это довольно просто с новым блоком Application Transaction Fault Handling. Все, что вам нужно, можно найти здесь:

http://geekswithblogs.net/ScottKlein/archive/2012/01/27/understanding-sql-azure-throttling-and-implementing-retry-logic.aspx

и в виде видео:

http://channel9.msdn.com/Shows/Cloud+Cover/Episode-68-Throttling-in-SQL-Azure-with-Scott-Klein

Пример из приведенных выше ссылок:

using (NorthwindEntities dc = new NorthwindEntities())
{
    RetryPolicy myPolicy = new RetryPolicy<SqlAzureTransientErrorDetectionStrategy>(3);
    Employee e1 = myPolicy.ExecuteAction<Employee>(() =>
        (from x in dc.Employees
            where x.LastName == "King"
            select x).First());
}

Как вы можете видеть, все, что вам нужно сделать, это создать RetryPolicy и вызвать функцию ExecuteAction с запросом, заключенным в действие.

* * EDIT

Пример переопределения контекста:

private RetryPolicy m_RetryPolicy = new RetryPolicy<SqlAzureTransientErrorDetectionStrategy>(....

public override int SaveChanges()
{
    return m_RetryPolicy.ExecuteAction<int>(() =>
    {
        return base.SaveChanges();
    });
}

// Pass anonymous query func in here
public T AutoRetryQuery<T>(Func<T> query)
{
    return m_RetryPolicy.ExecuteAction<T>(query);
}

Ответ 3

Так как это кажется одним из самых популярных вопросов о SO о обработке переходных процессов Azure, я добавлю здесь этот ответ.

У Entity Framework действительно есть код отказоустойчивости, встроенный (на ответ от Адама)

НО:

1) Вы должны добавить код для его активации вручную

public class MyConfiguration : DbConfiguration
{
    public MyConfiguration()
    {
        this.SetExecutionStrategy(
            "System.Data.SqlClient",
            () => new SqlAzureExecutionStrategy());

        this.SetTransactionHandler(
            SqlProviderServices.ProviderInvariantName, 
            () => new CommitFailureHandler()); 
    }
...

Первый вызов метода активирует повторы, второй вызов устанавливает обработчик, чтобы избежать дублирования обновлений при повторных попытках.

Примечание. Этот класс будет найден и создан автоматически, как описано здесь: https://msdn.microsoft.com/en-us/library/jj680699(v=vs.113).aspx. Просто убедитесь, что класс находится в той же сборке, что и ваш класс DbContext, и имеет открытый конструктор без параметров.

2) Встроенная SqlAzureExecutionStrategy недостаточно хороша. Он не охватывает все временные ошибки. Это неудивительно, если учесть, что команда SQL Server работает независимо от Entity Framework, поэтому они вряд ли когда-либо будут полностью синхронизированы с возможными временными ошибками. Это также трудно понять.

Решение, которое мы использовали, подкрепленное предложением другой компании-производителя программного обеспечения, заключается в создании нашей собственной стратегии выполнения, которая повторяет каждый SqlException и TimeoutException, за исключением нескольких, которые мы белым списком, поскольку не стоит повторять попытку (например, разрешение отклонено).

public class WhiteListSqlAzureExecutionStrategy : DbExecutionStrategy
{
    public WhiteListSqlAzureExecutionStrategy()
    {
    }

    protected override bool ShouldRetryOn(Exception exception)
    {  
        var sqlException = exception as SqlException;

        // If this is an SqlException then we want to always retry
        // Unless the all the exception types are in the white list. 
        // With those errors there is no point in retrying.
        if (sqlException != null)
        {
            var retry = false;
            foreach (SqlError err in sqlException.Errors)
            {
                // Exception white list.
                switch (err.Number)
                {
                    // Primary Key violation
                    // https://msdn.microsoft.com/en-us/library/ms151757(v=sql.100).aspx
                    case 2627:

                    // Constraint violation
                    case 547:

                    // Invalid column name, We have seen this happen when the Snapshot helper runs for a column 'CreatedOn'
                    // This is not one of our columns and it appears to be using our execution strategy.
                    // An invalid column is also something that probably doesn't get resolved by retries.
                    case 207:
                        break;

                    // The server principal "username" is not able to access the database "dbname" under the current security context
                    // May occur when using restricted user - Entity Framework wants to access master for something
                    // probably not transient
                    case 916:
                        break;

                    // XXX permission denied on object. (XXX = select, etc)
                    // Should not occur if db access is correct, but occurred when using restricted user - EF accessing __MigrationHistory
                    case 229:
                        break;

                    // Invalid object name 'xxx'.
                    // Occurs at startup because Entity Framework looks for EdmMetadata, an old table
                    // (Perhaps only if it can't access __MigrationHistory?)
                    case 208:
                        break;

                    default:
                        retry = true;
                        break;
                }
            }
            return retry;
        }

        if (exception is TimeoutException)
        {
            return true;
        }

        return false;
    }       
}

3) Существует некоторая ошибка, в которой EF запускает повторы N ^ 2 раза вместо N, что делает намного более длительные задержки, чем вы ожидали. Предполагается, что он займет около 26 секунд, но ошибка заставит вас потратить минуты. Однако это не так уж плохо, потому что на самом деле SQL Azure регулярно недоступны больше минуты:( https://entityframework.codeplex.com/workitem/2849

4) Если вы этого еще не делали, вам действительно нужно избавиться от своего DbContext после его использования. Похоже, это то, что CommitFailureHandler запускает его очистку, чтобы привести в порядок таблицу __TransactionHistory; если вы не распоряжаетесь, эта таблица будет расти вечно (хотя см. следующий пункт).

5) Вероятно, вы должны вызвать ClearTransactionHistory где-нибудь в своем запуске или в фоновом потоке, чтобы очистить все остатки в __TransactionHistory.

Ответ 4

У меня также была такая же проблема. В моем случае я использую LINQ-To-SQL (я считаю, что это относится и к инфраструктуре Entity), и это то, что я планирую делать.

Проанализируйте запросы Linq-to-sql, используя шаблон репозитория и завершите код Linq-to-sql, который генерирует запрос базы данных с помощью механизма повтора,

Для этого я предложил бы создать метод под названием ExecuteWithRetry(Action action), а затем вы вызовете этот метод следующим образом: ExecuteWithRetry(()=> { db_Item item = model.db_Item.First(); });

Метод может быть реализован таким образом

private void  ExecuteWithRetry(Action action)
{
  var retryStrategy = new Incremental(5, TimeSpan.FromSeconds(1), 
  TimeSpan.FromSeconds(2));

  // Define your retry policy using the retry strategy and the Windows Azure storage
  // transient fault detection strategy.
  var retryPolicy =
  new RetryPolicy<StorageTransientErrorDetectionStrategy>(retryStrategy);

  // Receive notifications about retries.
  retryPolicy.Retrying += (sender, args) =>
  {
    // Log details of the retry.
    var msg = String.Format("Retry - Count:{0}, Delay:{1}, Exception:{2}",
        args.CurrentRetryCount, args.Delay, args.LastException);
    Trace.WriteLine(msg, "Information");
  };

  try
  {
    this.retryPolicy.ExecuteAction(action);
  }
  catch (Exception ex)
  {
     Trace.TraceError(ex.TraceInformation());
    throw;
  }
 }

Я также попытаюсь использовать этот подход, надеясь, что он будет работать

Ответ 5

На самом деле вы хотите использовать методы расширения, предоставляемые MS. Ссылка: http://msdn.microsoft.com/en-us/library/hh680906(v=pandp.50).aspx

"Кроме того, классы SqlCommandExtensions и SqlConnectionExtensions предоставляют набор методов расширения, которые позволяют разработчикам .NET открывать соединения базы данных SQL Azure и вызывать команды SQL. методы расширения полезны в том случае, если вы не можете адаптировать свой код, чтобы воспользоваться классом ReliableSqlConnection. Например, вы можете использовать блок приложений доступа к данным Enterprise Library или Entity Framework, которые используют внутренние экземпляры SqlConnection. В В этом случае методы расширения помогут вам добавить возможности повтора, предлагаемые блоком приложений для обработки переходных ошибок, к существующему коду без серьезной повторной работы.

"