Теперь наблюдаются проблемы со стабильностью.
1. Какое-то время служба работает нормально и обрабатывает сообщения, потом перестаёт (при этом сообщения из очереди брокера пропадают).
2. После запуска службы сообщения не обрабатываются (при этом сообщения из очереди брокера пропадают), но при помощи перезапуска службы сообщения вдруг начинают приниматься, но вскоре всё равно всё упирается в п.1.
Нет ли каких-либо идей на этот счёт?
Найдено 18 результатов
- Вт 29 мар 2016 14:14
- Форум: SQL Server Data Access Components
- Тема: TMSServiceBroker перестал работать в составе службы Windows
- Ответы: 7
- Просмотры: 17686
- Чт 03 мар 2016 13:07
- Форум: SQL Server Data Access Components
- Тема: TMSServiceBroker перестал работать в составе службы Windows
- Ответы: 7
- Просмотры: 17686
Re: TMSServiceBroker перестал работать в составе службы Windows
Подскажите пожалуйста, в каком событии (в какой момент) необходимо вызывать этот метод?
- Ср 02 мар 2016 17:10
- Форум: SQL Server Data Access Components
- Тема: TMSServiceBroker перестал работать в составе службы Windows
- Ответы: 7
- Просмотры: 17686
Re: TMSServiceBroker перестал работать в составе службы Windows
Обновился до версии SDAC 7.2.10 в ожидании исправления обсуждаемой ситуации (в описании версии 7.2.9 увидел "Bug with using TMSServiceBroker in Windows service is fixed").
По факту - снова не работает. Подскажите, что нужно сделать, чтобы сообщения начали обрабатываться.
Есть подозрение, что метод StartAsyncEventProcessor в модуле CRThread.pas как-то с этим связан, не даром вы к нему добавили параметр "Force: Boolean". Только вот метод этот нигде не используется. В документации найти упоминания о нём не удалось. Мне нужно его вызывать при запуске windows-службы или что?
По факту - снова не работает. Подскажите, что нужно сделать, чтобы сообщения начали обрабатываться.
Есть подозрение, что метод StartAsyncEventProcessor в модуле CRThread.pas как-то с этим связан, не даром вы к нему добавили параметр "Force: Boolean". Только вот метод этот нигде не используется. В документации найти упоминания о нём не удалось. Мне нужно его вызывать при запуске windows-службы или что?
- Пн 19 окт 2015 09:33
- Форум: SQL Server Data Access Components
- Тема: TMSServiceBroker перестал работать в составе службы Windows
- Ответы: 7
- Просмотры: 17686
TMSServiceBroker перестал работать в составе службы Windows
Здравствуйте!
Пытаюсь перейти на SDAC версии 7.2.8 с версии 6.11.23. Использую Delphi XE6.
Существует служба Windows (TService), которая с помощью компоненты TMSServiceBroker отслеживает сообщения в очереди брокера, отправляемые туда по расписанию заданиями SQL-сервера.
При компиляции этой службы на SDAC v7 сообщения из очереди забираются, но их обработка не выполняется (событие MSServiceBrokerBeginConversation не вызывается).
Поизучал ваши исходники и выяснил, что перестал работать таймер, по которому обрабатывались полученные сообщения из очереди. TMSServiceBroker использует отдельный поток для обработки полученных сообщений - класс TCRThreadWrapper.
1. В методе TCRThreadWrapper.SetTimer таймер теперь активируется только при условии выполнения в главном потоке (используется функция IsMainThread)! В случае службы Windows таймер не запускается никогда:
2. Собственно, метод SetTimer также не вызывается. В конструкторе используется та же проверка IsMainThread:
Но список NeedToSetTimerList обрабатывается только в методе DoTimer, который вызывается по таймеру, создаваемому в методе SetTimer. Вот так круг замкнулся.
Помогите, пожалуйста. Как теперь использовать ваш компонент в службе Windows?
Пытаюсь перейти на SDAC версии 7.2.8 с версии 6.11.23. Использую Delphi XE6.
Существует служба Windows (TService), которая с помощью компоненты TMSServiceBroker отслеживает сообщения в очереди брокера, отправляемые туда по расписанию заданиями SQL-сервера.
При компиляции этой службы на SDAC v7 сообщения из очереди забираются, но их обработка не выполняется (событие MSServiceBrokerBeginConversation не вызывается).
Поизучал ваши исходники и выяснил, что перестал работать таймер, по которому обрабатывались полученные сообщения из очереди. TMSServiceBroker использует отдельный поток для обработки полученных сообщений - класс TCRThreadWrapper.
1. В методе TCRThreadWrapper.SetTimer таймер теперь активируется только при условии выполнения в главном потоке (используется функция IsMainThread)! В случае службы Windows таймер не запускается никогда:
Код: Выделить всё
procedure TCRThreadWrapper.SetTimer;
const
USER_TIMER_MINIMUM = $A;
begin
if FTimer = nil then begin
FTimer := TCRTimer.Create(nil);
FTimer.Enabled := False;
FTimer.Interval := USER_TIMER_MINIMUM;
FTimer.OnTimer := DoTimer;
end;
Assert(not FTimer.Enabled);
if IsMainThread then
FTimer.Enabled := True;
end;
Код: Выделить всё
constructor TCRThreadWrapper.Create;
begin
inherited Create;
FLockState := {$IFDEF FPC}SyncObjs.{$ENDIF}TCriticalSection.Create;
FThreadState := tsSuspended;
FEvents := TThreadList.Create;
FSendEventProcessed := TEvent.Create(nil, True, False, '');
FThread := TCRThread.Create(Self);
if IsMainThread then
SetTimer
else
NeedToSetTimerList.Add(Self);
end;
Помогите, пожалуйста. Как теперь использовать ваш компонент в службе Windows?
- Ср 08 окт 2014 13:55
- Форум: SQL Server Data Access Components
- Тема: TMSScript и обобщённые табличные выражения
- Ответы: 1
- Просмотры: 4640
TMSScript и обобщённые табличные выражения
Здравствуйте!
Часто в проекте использую рекурсивные запросы (обобщённые табличные выражения), в частности для выборки данных из иерархических справочников (записи с полями ID, ID_PARENT, NAME - каждая запись ссылается на родительскую запись, аналог - стуктура файловой системы с каталогами и файлами). Начиная с SQL Server 2005 такие запросы можно строить с помощью конструкции WITH (Common table expression или обобщённые табличные выражения). Но обязательно требуется наличие символа ";" перед этим ключевым словом (как правило, везде пишут так ";WITH ...", но можно оставлять ";" и в конце предыдущей строки).
Для выполнения скриптов в программе используется компонент TMSScript, который считает символ ";" разделителем, из-за чего пакет SQL-команд разбивается на "ДО WITH" и "ПОСЛЕ WITH". Если в пакете перед WITH декларируются локальные переменные, то в самом WITH и после него эти переменные уже не видимы. Очистка свойства Delimiter у TMSScript не помогает.
Пример простейшего скрипта с применением WITH, полностью валидного с точки зрения SQL сервера:
При выполнении получаем ошибку:
Исправьте, пожалуйста.
Часто в проекте использую рекурсивные запросы (обобщённые табличные выражения), в частности для выборки данных из иерархических справочников (записи с полями ID, ID_PARENT, NAME - каждая запись ссылается на родительскую запись, аналог - стуктура файловой системы с каталогами и файлами). Начиная с SQL Server 2005 такие запросы можно строить с помощью конструкции WITH (Common table expression или обобщённые табличные выражения). Но обязательно требуется наличие символа ";" перед этим ключевым словом (как правило, везде пишут так ";WITH ...", но можно оставлять ";" и в конце предыдущей строки).
Для выполнения скриптов в программе используется компонент TMSScript, который считает символ ";" разделителем, из-за чего пакет SQL-команд разбивается на "ДО WITH" и "ПОСЛЕ WITH". Если в пакете перед WITH декларируются локальные переменные, то в самом WITH и после него эти переменные уже не видимы. Очистка свойства Delimiter у TMSScript не помогает.
Пример простейшего скрипта с применением WITH, полностью валидного с точки зрения SQL сервера:
Код: Выделить всё
procedure TForm1.Button6Click(Sender: TObject);
begin
MSScript2.SQL.Text := 'DECLARE @I SMALLINT ' +
'SELECT @I = 1 ' +
';WITH TAB (M) AS ( ' +
'SELECT @I ' +
'UNION ALL ' +
'SELECT CAST(T.M + 1 AS SMALLINT) ' +
'FROM TAB T ' +
'WHERE T.M < 10 ' +
') ' +
'SELECT * FROM TAB ' +
'GO';
MSScript2.Execute;
end;
При этом имеется такое наблюдение: если скрипт содержит ";WITH" в теле хранимой процедуры, то ";" игнорируется, и всё выполняется хорошо. Т.е. вы всё-таки производите какой-то анализ запроса, а не тупо разбиваете скрипт на выполняемые пакеты по символу ";".Неправильный синтаксис около конструкции ")".
Необходимо объявить скалярную переменную "@I".
Исправьте, пожалуйста.
- Пн 14 июл 2014 08:47
- Форум: SQL Server Data Access Components
- Тема: TMSQuery.Options.DescribeParams и Integer Overflow
- Ответы: 1
- Просмотры: 4272
TMSQuery.Options.DescribeParams и Integer Overflow
Здравствуйте!
В debug-сборке своего проекта я включаю опции "Runtime errors" компилятора (Overflow checking, Range checking).
Если в TMSQuery используется простейший SELECT-запрос без параметров (например, "select * from sys.objects"), и включено свойство Options.DescribeParams, то в модуле OLEDBAccess, в методе TOLEDBCommand.GetParameterInfo происходит "классическое" переполнение в вычислении границы цикла при использовании беззнакового типа:
Исправьте, пожалуйста.
В debug-сборке своего проекта я включаю опции "Runtime errors" компилятора (Overflow checking, Range checking).
Если в TMSQuery используется простейший SELECT-запрос без параметров (например, "select * from sys.objects"), и включено свойство Options.DescribeParams, то в модуле OLEDBAccess, в методе TOLEDBCommand.GetParameterInfo происходит "классическое" переполнение в вычислении границы цикла при использовании беззнакового типа:
Код: Выделить всё
var
...
cParams: NativeUInt;
...
begin
...
// cParams = 0, и вычитать из беззнакового числа ничего нельзя.
for i := 0 to cParams - 1 do begin
...
end;
- Чт 10 июл 2014 07:34
- Форум: SQL Server Data Access Components
- Тема: TMSQuery.Open портит память
- Ответы: 17
- Просмотры: 20758
Re: TMSQuery.Open портит память
Хотелось бы уточнить ещё один момент: если я использую TMSQuеry только для получения данных, без необходимости редактирования (устанавливаю свойство ReadOnly := True), то нет никакого смысла в UniqueRecords = True? И для отключения лишних действий будет даже лучше отключать UniqueRecords для только читающих наборов данных (независимо от наличия конструкции WITH)?
Вообще странная ситуация с WITH. У меня редактируемые наборы данных с WITH (все, что я проверял) - работают нормально. А вот набор данных с WITH и ReadOnly = True, где никакого редактирования и не планировалось, приводит к ситуации из первого поста.
Вообще странная ситуация с WITH. У меня редактируемые наборы данных с WITH (все, что я проверял) - работают нормально. А вот набор данных с WITH и ReadOnly = True, где никакого редактирования и не планировалось, приводит к ситуации из первого поста.
- Пт 04 июл 2014 06:48
- Форум: SQL Server Data Access Components
- Тема: TMSQuery.Open портит память
- Ответы: 17
- Просмотры: 20758
Re: TMSQuery.Open портит память
Я оценил это как временное решение, а не постоянный костыльAndreyZ писал(а):Мы отвечали на этот вопрос: http://forums.devart.com/viewtopic.php?t=29501#p101103
Т.е. для этого случая, чтобы вернуть старое поведение новой версии SDAC необходимо установить опцию TMSQuery.Options.UniqueRecords в False.
К тому же были проблемы с UniqueRecords = False и вызовом метода Prepare.
Сейчас проблема с Prepare вроде бы отсутствует.
И тогда такой вопрос. Раз вы знаете в чём проблема, расскажите, пожалуйста, по каким критериям можно определить _не_возможность использования режима UniqueRecords = True?
В своей программе я наткнулся пока только на один проблемный запрос, но запросов в программе тысячи, есть довольно редко используемые и со сложными кейсами, на тестирование которых уйдёт уйма времени.
Или проще сразу всем Query проставить UniqueRecords = False, и в дальнейшей разработке для новых Query отключать этот режим? Зачем он тогда нужен по умолчанию, если его работа так непредсказуема?
- Ср 02 июл 2014 06:41
- Форум: SQL Server Data Access Components
- Тема: TMSQuery.Open портит память
- Ответы: 17
- Просмотры: 20758
Re: TMSQuery.Open портит память
Да, в реальных SQL-скриптах, как правило, используются отступы в коде. И получается перед "/" несколько пробелов. В таком случае, конечно, всё работает.AndreyZ писал(а):В версии SDAC версии 5.10.0.8 корректно работал скрипт, указанный вами в паралельном топике, или следующий скрипт:Мы не можем изменить поведение, когда единственный символ '/' идет в начале строки, так как это повлечет изменения для множества наших пользователей.Код: Выделить всё
MSScript.SQL.Text := 'SELECT (10'#10#13 + ' / '#10#13 + '2) AS RES'; MSScript.Execute;
Не думал, что в этом будет какая-то принципиальная разница. Спасибо за уточнение.
- Ср 02 июл 2014 06:16
- Форум: SQL Server Data Access Components
- Тема: TMSQuery.Open портит память
- Ответы: 17
- Просмотры: 20758
Re: TMSQuery.Open портит память
По-прежнему ситуация такая же, как и в первом посте:
saupg писал(а): ...
Для этого запроса я получаю такое исключение: "Exception class EOLEDBError with message 'Ошибка протокола в потоке TDS'.".
Любое небольшое изменение текста запроса может как изменить поведение процесса, так и исправить ошибку.
Например, если в последней строке запроса изменить "LEFT JOIN" на "FULL JOIN", то получаем ошибку: "Exception class EOLEDBError with message 'Соединение больше нельзя использовать, так как ответ сервера на выполнявшуюся ранее инструкцию имел неправильный формат.'".
А если там же использовать "INNER JOIN", то ошибки нет. Так же ошибка пропадает при изменении таблицы, например, достаточно из первичного ключа исключить один из столбцов.
- Вт 01 июл 2014 14:18
- Форум: SQL Server Data Access Components
- Тема: TMSQuery.Open портит память
- Ответы: 17
- Просмотры: 20758
Re: TMSQuery.Open портит память
Эх, проверил и почистил всё ещё раз, полностью уверен что тестовый проект компилируется из исходников SDAC версии 6.10.20. Работаю с Delphi с 98-го года, все подлянки с dcu знаю.
Сравнил исходники 6.10.19 и 6.10.20.
Да, вижу сделанные вами изменения, например, в модуле DAScript.pas по поводу разделителя '/'. Вижу новую функцию SlashIsDelimiter и место её использования (547-ая строка), пошагово отлаживаю это место.
При встрече с символом '/' флаг BlankLine получается равным True, и затем TempCode равно lcBlank. В итоге флаг Ready получается True, и цикл разбора выражения прерывается, хотя в скрипте на следующей строке идёт продолжение (значение-делитель).
Тестовый скрипт всё тот же:
Далее, не могу точно знать, куда смотреть в исходниках по поводу основной проблемы, изменений довольно много. В том фикс-билде, что вы передавали мне по почте, я вижу изменения в модуле DBAccess.pas (в функции TDADataSetService.GetDBKeyList). Но в билде 6.10.20 этих изменений почему-то нет... Хотя и фикс-билд на тестовом примере тоже даёт такие же ошибки.
Из всего вышесказанного я всё-таки делаю вывод, что по одному вопросу исправлено что-то не до конца, а по другому исправлено что-то не то. Прошу проверить работоспособность на предоставленных мной тестовых примерах.
Спасибо за терпение.
Сравнил исходники 6.10.19 и 6.10.20.
Да, вижу сделанные вами изменения, например, в модуле DAScript.pas по поводу разделителя '/'. Вижу новую функцию SlashIsDelimiter и место её использования (547-ая строка), пошагово отлаживаю это место.
Код: Выделить всё
Ready := (FDelimiterState = dsSet) or (Code = lcEnd) or GetReady(Code);
if not Ready and (Code <> lcString) then begin
Ready := CheckDelimeter and not IsSpecificSQL(StatementType);
if not Ready and (FCurrDelimiter = FOwner.FDelimiter{';'}) and (FSt = '/') then begin
if not SlashIsDelimiter then
BlankLine := FParser.PrevCol = 0;
if BlankLine then begin
TempCode := FParser.GetNext(TempSt);
if (TempCode = lcEnd) or
(TempCode = lcBlank) and ((Pos(#13, TempSt) > 0) or (Pos(#10, TempSt) > 0))
then
Ready := True
else
FParser.Back;
end;
end;
end;
Тестовый скрипт всё тот же:
Код: Выделить всё
MSScript.SQL.Text := 'SELECT (10'#10#13 +
'/'#10#13 +
'2) AS RES';
MSScript.Execute;
Из всего вышесказанного я всё-таки делаю вывод, что по одному вопросу исправлено что-то не до конца, а по другому исправлено что-то не то. Прошу проверить работоспособность на предоставленных мной тестовых примерах.
Спасибо за терпение.
- Пн 30 июн 2014 09:55
- Форум: SQL Server Data Access Components
- Тема: TMSQuery.Open портит память
- Ответы: 17
- Просмотры: 20758
Re: TMSQuery.Open портит память
Так, вернёмся к нашей проблеме (отвлёкся на переход с Delphi XE на XE6 и адаптацию под 64 бита).
Обновился на билд SDAC 6.10.20. По факту - проблема из первого поста и проблема с символом "/" (из другой ветки) остались на месте. Судя по "revision history" эти изменения должны были попасть в сборку. Почистил все dcu, проверил пути и настройки тестового проекта. Ничего не работает Пробовал на Delphi XE и XE6.
Прошу проверить, попали ли все необходимые изменения в сборку 6.10.20?
Обновился на билд SDAC 6.10.20. По факту - проблема из первого поста и проблема с символом "/" (из другой ветки) остались на месте. Судя по "revision history" эти изменения должны были попасть в сборку. Почистил все dcu, проверил пути и настройки тестового проекта. Ничего не работает Пробовал на Delphi XE и XE6.
Прошу проверить, попали ли все необходимые изменения в сборку 6.10.20?
- Чт 08 май 2014 08:38
- Форум: SQL Server Data Access Components
- Тема: TMSQuery.Open портит память
- Ответы: 17
- Просмотры: 20758
Re: TMSQuery.Open портит память
Да, что-то не везёт мне на примеры. Действительно, на 5-й версии пример из первого поста так же не работает, при этом свойство UniqueRecords на ситуацию никак не влияет.
Но, поверьте на слово, у меня реальные запросы в проекте, не работающие на 6-ой версии, прекрасно выполняются на 5-ой. Уж не знаю, в чём там отличие, но копать глубже нет времени.
Надесь, вы исправили именно эту ошибку
Кстати, на 5-ой версии при UniqueRecords := False не требуется обязательной подготовки запроса через вызов Prepare. Если вы говорите, что в 6-й версии так будет только при UniqueRecords := True, то мне обязательно нужен патч. Информация о лицензии приведена в первом посте. Пришлите исправление, пожалуйста.
Но, поверьте на слово, у меня реальные запросы в проекте, не работающие на 6-ой версии, прекрасно выполняются на 5-ой. Уж не знаю, в чём там отличие, но копать глубже нет времени.
Надесь, вы исправили именно эту ошибку
Кстати, на 5-ой версии при UniqueRecords := False не требуется обязательной подготовки запроса через вызов Prepare. Если вы говорите, что в 6-й версии так будет только при UniqueRecords := True, то мне обязательно нужен патч. Информация о лицензии приведена в первом посте. Пришлите исправление, пожалуйста.
- Чт 08 май 2014 08:19
- Форум: SQL Server Data Access Components
- Тема: TMSScript и знак деления
- Ответы: 3
- Просмотры: 5278
Re: TMSScript и знак деления
Да, действительно, мой пример универсален, и даёт ошибку на любой версии.
Странно, но все мои скрипты создания хранимых процедур с таким же отдельно стоящим знаком деления выполняются нормально на старой версии, а на новой дают такую вот ошибку.
Кстати, в некоторых скриптах встречается, что знак деления стоит первым символом в строке, а за ним располагается делитель. И в каких-то случаях возникает такая же ошибка. Какой-либо закономерности я не вижу.
И ещё одно наблюдение - если текст скрипта вставить в компонент MSScript на форме, то всё хорошо. При загрузке того же скрипта из файла (MSScript.SQL.LoadFromFile) - получаем ошибку.
Немного поколдовал со своими скриптами и получилось родить один пример.
Сохраните скрипт в файл:
Затем загружаем его в коде и пытаемся выполнить:
На 6-ой версии в таком виде - не работает. Если текст скрипта поместить в компонент в дизайне, то работает. На 5-ой версии проблем никаких нет.
Да и собственно, речь идёт не о том, что в какой-то версии работает, а в какой-то нет. Мой пример наглядно продемонстрировал проблему - абсолютно валидный с точки зрения синтаксиса T-SQL скрипт не выполняется через ваш компонент.
Исправьте, пожалуйста.
Странно, но все мои скрипты создания хранимых процедур с таким же отдельно стоящим знаком деления выполняются нормально на старой версии, а на новой дают такую вот ошибку.
Кстати, в некоторых скриптах встречается, что знак деления стоит первым символом в строке, а за ним располагается делитель. И в каких-то случаях возникает такая же ошибка. Какой-либо закономерности я не вижу.
И ещё одно наблюдение - если текст скрипта вставить в компонент MSScript на форме, то всё хорошо. При загрузке того же скрипта из файла (MSScript.SQL.LoadFromFile) - получаем ошибку.
Немного поколдовал со своими скриптами и получилось родить один пример.
Сохраните скрипт в файл:
Код: Выделить всё
IF(EXISTS(SELECT 1 FROM sys.objects WHERE object_id=OBJECT_ID('spTest','P')))
DROP PROCEDURE dbo.spTest
GO
CREATE PROCEDURE dbo.spTest
(
@ID smallint,
@ID_TEST smallint
)
AS
BEGIN
DECLARE @TEST SMALLINT
SET @TEST=10
;WITH M(CNT) AS
(
SELECT @TEST
UNION ALL
SELECT CAST(CNT + 1 AS SMALLINT)
FROM M
WHERE M.CNT < @TEST
)
SELECT
COUNT(ID) AS CNT
FROM M
CROSS APPLY
(
SELECT
(10
/
2) AS ID
) A
END
Код: Выделить всё
procedure TForm1.Button2Click(Sender: TObject);
var
MSConnection: TMSConnection;
MSScript: TMSScript;
begin
MSConnection := TMSConnection.Create(Self);
MSScript := TMSScript.Create(Self);
try
MSConnection.Authentication := auWindows;
MSConnection.Server := 'db01';
MSConnection.Database := 'master';
MSConnection.LoginPrompt := False;
MSScript.Connection := MSConnection;
MSScript.SQL.LoadFromFile('D:\test.sql');
MSScript.Execute;
finally
MSScript.Free;
MSConnection.Free;
end;
end;
Да и собственно, речь идёт не о том, что в какой-то версии работает, а в какой-то нет. Мой пример наглядно продемонстрировал проблему - абсолютно валидный с точки зрения синтаксиса T-SQL скрипт не выполняется через ваш компонент.
Исправьте, пожалуйста.
- Ср 07 май 2014 07:11
- Форум: SQL Server Data Access Components
- Тема: TMSQuery.Open портит память
- Ответы: 17
- Просмотры: 20758
Re: TMSQuery.Open портит память
Оказывается, если свойство UniqueRecords = False, то перед изменением данных в датасете надо обязательно вызывать метод Prepare (или устанавливать свойство Options.AutoPrepare := True, которое по-умолчанию = False). В документации про это ничего не сказано. Да и поведение какое-то нелогичное.
Пример кода для предыдущего проекта:
С закомментаренной строкой MSQuery1.Prepare получаю ошибку "Exception class EDatabaseError with message 'MSQuery1: Cannot modify a read-only dataset'.".
Пример кода для предыдущего проекта:
Код: Выделить всё
procedure TForm1.Button2Click(Sender: TObject);
const
qTest = 'SELECT * FROM SDAC_BUG';
begin
MSConnection1.Open;
MSQuery1.Options.UniqueRecords := False;
MSQuery1.SQL.Text := qTest;
// MSQuery1.Prepare;
MSQuery1.Open;
MSQuery1.Insert; // <--- Exception
MSConnection1.Close;
end;