синхронизация между двумя приложениями, объединяющими таблицу SQL - PullRequest
0 голосов
/ 21 июня 2019

У меня есть 2 экземпляра приложения VB.NET, каждое из которых работает на своих собственных выделенных серверах.Указанное приложение запускает цикл While true с 5-секундным сном на IDLE (IDLE - это когда в таблице нет обработанного ProcessQuery).На каждой итерации приложение ставит под сомнение таблицу в базе данных SQL, чтобы узнать, может ли она что-либо обработать.

Проблема в том, что я иногда сталкиваюсь с проблемой, когда оба экземпляра "берут" один и тот же ProcessQuery.

Я использую EntityFramework6.Я посмотрел в EntityState, но я не думаю, что он делает именно то, что я пытаюсь достичь.

Мне было интересно, каким было бы мое решение для создания идеальных параллельных экземпляров.Это не невозможно в какой-то момент у меня 12 экземпляров, работающих на 12 машинах.

Спасибо!

 Dim conn As New Info_IndusEntities()
    Dim DemandeWilma As WilmaDemandes =  conn.WilmaDemandes.Where(Function(x) x.Site = 'LONDON' AndAlso x.Statut = 'toProcess').OrderBy(Function(x) x.RequestDate).FirstOrDefault

            If Not IsNothing(DemandeWilma) Then
                DemandeWilma.Statut = Statuts.EnTraitement.ToString
                DemandeWilma.ServerName = Environment.MachineName
                DemandeWilma.ProcessDate = DateTime.Now
                conn.SaveChanges()
                Return DemandeWilma
            end if 

ОБНОВЛЕНИЕ (21/06/19)

Я нашел статья что я нахожу интересным.

Я начал с добавления столбца в мою таблицу: enter image description here

ОБНОВЛЕНО (21/06/19)

Затем я обновил свою модель и изменил свойство Проверка параллелизма столбца RowVersion в моем ORM:

enter image description here

Когда я тестировалобновите, вот журнал EF6:

ОБНОВЛЕНИЕ [dbo]. [WilmaDemandes] SET [Statut] = @ 0, [ServerName] = @ 1, [DateDebut] = @ 2 WHERE (([ID] = @ 3) И ([RowVersion] = @ 4)) ВЫБРАТЬ [RowVersion] ОТ [dbo]. [WilmaDemandes] ГДЕ @@ ROWCOUNT> 0 И [ID] = @ 3

- @0: «EnTraitement» (тип = строка, размер = 20)

- @ 1: «TRB5995» (тип = строка, размер = 20)

- @ 2: '2019-06-25 7:31:01 AM '(Type = DateTime2)

- @ 3:' 124373 '(Type = Int32)

- @ 4:' System.Byte[] '(Тип = Двоичный, Размер = 8)

- Выполнено в 2019-06-25 7:31:24 AM -04: 00

- Завершено за 95 мс срезультат: SqlDataReader

Закрытое соединениеt 2019-06-25 7:31:24 AM -04: 00

Возникло исключение: 'System.Data.Entity.Infrastructure.DbUpdateConcurrencyException' в EntityFramework.dll

ОБНОВЛЕНО (25/06/19)

Проблемы, описанные в в этом посте , начинаются, когда вы используете DB-First вместо Code-First.Ваша собственность будет перезаписана без вывода сообщений , как только вы обновите модель.Некоторые люди тогда закодировали обходной путь консольного приложения, которое они запускают перед сборкой.Я не уверен, что я вполне готов принять это решение как окончательное решение.

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

1 Ответ

1 голос
/ 21 июня 2019
  1. Добавление столбца «владелец» в таблицу очередей
  2. Ваше приложение обновляет одну запись (TOP 1) и устанавливает значение владельца для их идентификатора (WHERE Owner IS NULL)
  3. Теперь ваше приложение возвращается и читает принадлежащие им строки и обрабатывает их

Это простой шаблон, и он прекрасно работает.Если какие-либо процессы вступают во владение «одновременно», только один фактически получит резервирование.

Я не очень хорош в LINQ, поэтому вот метод грубой силы, многострочный для ясности:

// First try reserving a row
conn.Database.ExecuteSqlCommand(
  "WITH UpdateTop1 AS 
   (SELECT TOP 1 * FROM WilmaDemandes
    WHERE Owner IS NULL 
    AND Site = 'LONDON'
    ORDER BY RequestDate) 

    UPDATE UpdateTop1 SET Owner='ThisApplication'"
);

// See if we got one 
Dim DemandeWilma As WilmaDemandes =  
conn.WilmaDemandes.
Where(x => x.Owner=='ThisApplication').FirstOrDefault

// If we got a row, process it. Otherwise Idle and repeat

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

Лично я бы реорганизовал ваш столбец состояния и сделал бы его пустым для новых записей, готовых к обработке, в противном случае зарезервировал его идентификатор работника.

Это также помогает добавлять такие вещи, как столбцы меток времени для записи, когда строка была зарезервирована и т. Д.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...