← Back

Ошибка в клиринг

Во время клиринга вылетает огромное колличество ошибок "Ошибка проверки потока репликации. Код -2147184638", описание "P2ERR_SERV_NO_SERVICE", пока не переполнится стек. Источник ошибки:```csharp () => // pollAction { if (Streams.Count == 0 && _streamsToRemove.Count == 0) _sleepInterval.Sleep();

Streams.SyncDo(c =>
{
	foreach (var stream in Streams)
	{
		try
		{
			stream.CheckConnection(_connection);
		}
		catch (COMException e)
		{
			System.Diagnostics.Trace.WriteLine("stream.CheckConnection(_connection) - COMException " + e.ErrorCode.ToString());
			Error.SafeInvoke(new PlazaException("Ошибка проверки потока репликации.", e));
		}
	}
});
В методе stream.CheckConnection(_connection), вызывается DataStream.Open(connection);, что и дает ошибку.

Comments (37)

Login or Create account, Log in or register to leave a comment

Mikhail Sukhov
Mikhail Sukhov

FiNick: пока не переполнится стек.

Что за стек?

FiNick
FiNick Author

Mikhail Sukhov:

FiNick: пока не переполнится стек.

Что за стек?

Ну как, стек программы, который переполняется если, например, бесконечно рекурсивно вызывать какую-либо функцию. У меня на экране быстро появляются десятки окошек с ошибкой (см прикрепленную ошибку), все подвисает, пока не вылетит StackOverflow Exception. Попробуйте запустить SimpleGUI в промклиринг.

Mikhail Sukhov
Mikhail Sukhov

FiNick: Ну как, стек программы, который переполняется если, например, бесконечно рекурсивно вызывать какую-либо функцию.

Рекурсии не увидел.

FiNick: У меня на экране быстро появляются десятки окошек с ошибкой (см прикрепленную ошибку), все подвисает, пока не вылетит StackOverflow Exception. Попробуйте запустить SimpleGUI в промклиринг.

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

Alexander
Alexander

Mikhail Sukhov: Видимо окошки не нужно выбрасывать.

Я думаю данный exception вообще лишний для ProcessDataError - т.к. это стандартная ситуация. Потому предлагаю чтоб pollAction возвращал bool флаг - success или нет (чтоб не грузили ProcessMessage). Соответственно предлагаю изменить его на:

				if (Streams.Count == 0 && _streamsToRemove.Count == 0)
					_sleepInterval.Sleep();

                var checkSuccess = true;
				Streams.SyncDo(c =>
				{
					foreach (var stream in Streams)
					{
						try
						{
							stream.CheckConnection(_connection);
						}
						catch (COMException e)
						{
							System.Diagnostics.Trace.WriteLine("stream.CheckConnection(_connection) - COMException " + e.ErrorCode.ToString());
                            checkSuccess = false;
                            return;
						}
					}
				});

                if (!checkSuccess)
                {
                    _sleepInterval.Sleep();
                    return false;
                }

				_streamsToRemove.SyncDo(c =>
				{
					foreach (var stream in _streamsToRemove)
					{
						try
						{
							stream.Close();
						}
						catch (COMException e)
						{
							System.Diagnostics.Trace.WriteLine("stream.Close() - COMException " + e.ErrorCode.ToString());
							Error.SafeInvoke(new PlazaException("Ошибка закрытия потока репликации.", e));
						}
					}

					_streamsToRemove.Clear();
				});

                return true;

Ну и в PlazaConnection соответственно:

                            if (pollAction != null && !pollAction())
                                return;

Мысли \ возражения?

Alexander
Alexander

Форум ртс Насколько я понял - exception выкидывать не надо. просто делать Sleep если для всех стримов обломилась проверка. какие ещё идеи?

FiNick
FiNick Author

Мне кажется, или такой код должен грузить проц под 100%? Там же нигде Sleep нету. Надо как-то сделать, чтобы если !pollAction() то поспать:

if (pollAction != null && !pollAction())
{
    PollTimeOut.Sleep();
    return;
}
Alexander
Alexander

да, верно. подправил вариант ваше.

Alexander
Alexander

Положил. Хотя бы 1 поток должен быть открыт, так правильнее. В этом случае ProcessMessage имеет смысл делать.

FiNick
FiNick Author
var success = true;
if (Streams.Count == 0 && _streamsToRemove.Count == 0)
	success = false;

Streams.SyncDo(c =>
{
	var anySuccess = false;
	foreach (var stream in Streams)
	{
		try
		{
			stream.CheckConnection(_connection);
			anySuccess = true;
		}
		catch (COMException e)
		{
			System.Diagnostics.Trace.WriteLine("Ошибка проверки потока репликации - stream.CheckConnection(_connection) - COMException " + e.ErrorCode.ToString());
		}
	}

	success = anySuccess;
});

anySuccess лишняя переменная имхо, почему бы сразу везде не использовать success? Сегодня на клиринге протестирую, вроде должно работать.

Кстати, после этих изменений у меня <mark>не коннектится</mark>. И проблема именно в PlazaStreamManager, потому что со старым вариантом все норм

Alexander
Alexander

FiNick: ...

anySuccess лишняя переменная имхо, почему бы сразу везде не использовать success? Сегодня на клиринге протестирую, вроде должно работать.

Кстати, после этих изменений у меня <mark>не коннектится</mark>. И проблема именно в PlazaStreamManager, потому что со старым вариантом все норм

Исправил. По ночам лучше спать :) Мы должны дёргать ProcessMessage чтоб знать подключились или нет

FiNick
FiNick Author

Alexander Mukhanchikov: По ночам лучше спать :) Вот именно!=) Все равно не работает, верни return, либо поменяй Func на Action

Alexander
Alexander

FiNick:

Alexander Mukhanchikov: По ночам лучше спать :) Вот именно!=) Все равно не работает, верни return, либо поменяй Func на Action

недокоммитил. у себя проверял - работает.

FiNick
FiNick Author

Протестил. В клиринг приложение не падает, но вот после клиринга перестал обновляться стакан, пришлось переконнектиться

Alexander
Alexander

FiNick: Протестил. В клиринг приложение не падает, но вот после клиринга перестал обновляться стакан, пришлось переконнектиться

Тоже самое и после торгов. Пока хз в чём дело. Если будут идеи после анализа исходников PlazaTrader - пишите.

FiNick
FiNick Author

Похоже ошибку будет сложно отследить, т.к. клиринг просто так посреди дня несколько раз не воспроизвести.

Я смотрел логи, в начале клиринга по потоку FORTS_FUTAGGR5_REPL вылетает 'SERV:NO_SERVICE', затем через несколько секунд Stream opening started;stream 0x53183F0,type 1,name 'FORTS_FUTAGGR5_REPL'. То есть поток переоткрывается похоже, наверное в методе CheckConnection, если я ничего не путаю. Потом в логах он больше не фигурирует весь клиринг и после клиринга тоже

Кстати, замечание в РТС сделали, надо исправить: Закрывать потоки надо до закрытия соединения, а не пытаться сделать это после: 2011-10-05 19:03:13.921;p2repl-cli;;CLOSE message posted;stream 0x5415360 2011-10-05 19:03:13.921;p2repl-cli;error;p2err 24579=0x6003 - 'MQ:NOT_CONNECTED_YET';Couldn't post CLOSE message;stream 0x5415360

Alexander
Alexander

FiNick: Похоже ошибку будет сложно отследить, т.к. клиринг просто так посреди дня несколько раз не воспроизвести.

Я смотрел логи, в начале клиринга по потоку FORTS_FUTAGGR5_REPL вылетает 'SERV:NO_SERVICE', затем через несколько секунд Stream opening started;stream 0x53183F0,type 1,name 'FORTS_FUTAGGR5_REPL'. То есть поток переоткрывается похоже, наверное в методе CheckConnection, если я ничего не путаю. Потом в логах он больше не фигурирует весь клиринг и после клиринга тоже

Кстати, замечание в РТС сделали, надо исправить: Закрывать потоки надо до закрытия соединения, а не пытаться сделать это после: 2011-10-05 19:03:13.921;p2repl-cli;;CLOSE message posted;stream 0x5415360 2011-10-05 19:03:13.921;p2repl-cli;error;p2err 24579=0x6003 - 'MQ:NOT_CONNECTED_YET';Couldn't post CLOSE message;stream 0x5415360

Так и делается, разве нет?

		protected override void OnDisconnect()
		{
			// Иначе при выгрузке в StopStream будет срабатывать исключение.
			if (IsExportRunning)
				StopExport();

			_connectionPool.Disconnect();

			System.Diagnostics.Trace.WriteLine("OnDisconnect");
		}

По поводу стаканов - в клиринг они присылают StreamDatumDeleted, надо как-то его обработать правильно.

P.S. Я так пару багов с инициализацией инструмента подправил

FiNick
FiNick Author

Alexander Mukhanchikov: Так и делается, разве нет?

	protected override void OnDisconnect()
	{
		// Иначе при выгрузке в StopStream будет срабатывать исключение.
		if (IsExportRunning)
			StopExport();

		_connectionPool.Disconnect();

		System.Diagnostics.Trace.WriteLine("OnDisconnect");
	}

А StopExport() здесь останавливает выполенение и дожидается пока все потоки будут закрыты?
Я так понимаю закрытие потоков непосредственно выполняется в pollAction, может так получается, что дисконнект и закрытие потоков происходит параллельно.

На счет стаканов РТС написали:
"Как я понял, по вашему времени клиринг с 17-45 до 18-30 ? После него оба агреггированных потока приходили успешно вплоть до самого закрытия приложения."
что собственно я и видел в логах. Возможно это у нас косяк
Alexander
Alexander

FiNick:

Alexander Mukhanchikov: Так и делается, разве нет?

	protected override void OnDisconnect()
	{
		// Иначе при выгрузке в StopStream будет срабатывать исключение.
		if (IsExportRunning)
			StopExport();

		_connectionPool.Disconnect();

		System.Diagnostics.Trace.WriteLine("OnDisconnect");
	}
> 
> А StopExport() здесь останавливает выполенение и дожидается пока все потоки будут закрыты?
> Я так понимаю закрытие потоков непосредственно выполняется в pollAction, может так получается, что дисконнект и закрытие потоков происходит параллельно.
> 
> На счет стаканов РТС написали:
> "Как я понял, по вашему времени клиринг с 17-45 до 18-30 ? После него оба агреггированных потока приходили успешно вплоть до самого закрытия приложения."
> что собственно я и видел в логах. Возможно это у нас косяк


Это точно наш косяк. Надо удалять записи с ревизиями < пришедшей по событию StreamDatumDeleted. Мы этого не делаем.
FiNick
FiNick Author

Специальное уведомление StreamDatumDeleted присылается сервером по каждой таблице в начале синхронизации. Это уведомление означает «данных с ревиженами меньше указанного, на сервере нет». «Безбазовый» клиент должен удалить все данные с ревиженами, меньшими указанного в уведомлении из своего хранилища.

У нас же «базовый» клиент, там вроде само все делается, или я не прав? Плюс у нас в коде OnStreamDatumDeleted есть, там что-то делается

Alexander
Alexander

FiNick: Специальное уведомление StreamDatumDeleted присылается сервером по каждой таблице в начале синхронизации. Это уведомление означает «данных с ревиженами меньше указанного, на сервере нет». «Безбазовый» клиент должен удалить все данные с ревиженами, меньшими указанного в уведомлении из своего хранилища.

У нас же «базовый» клиент, там вроде само все делается, или я не прав? Плюс у нас в коде OnStreamDatumDeleted есть, там что-то делается

У нас безбазовый клиент. И это как раз не делается.

FiNick
FiNick Author

Alexander Mukhanchikov: У нас безбазовый клиент. И это как раз не делается.

А как дела с другими фичами, StreamLifeNumChanged например?

Alexander
Alexander

FiNick:

Alexander Mukhanchikov: У нас безбазовый клиент. И это как раз не делается.

А как дела с другими фичами, StreamLifeNumChanged например?

см. private void OnStreamLifeNumChanged(CP2DataStream stream, int lifeNum) в PlazaStream.cs

FiNick
FiNick Author

Протрассировал дисконнект:

protected override void OnDisconnect()
{
	// Иначе при выгрузке в StopStream будет срабатывать исключение.
	if (IsExportRunning)
		StopExport();

	_connectionPool.Disconnect();
	System.Diagnostics.Trace.WriteLine("OnDisconnect");
}

Там получается, что StopExport() никого не дожидается. _connectionPool.Disconnect() и Close всех потоков происходит параллельно, понятно, что Disconnect раньше происходит, и в лог ошибки сыплются. Поставил после StopExport() слип на пару секунд, все норм стало, но это грубо и некрасиво. Нужно AutoResetEvent какой-нибудь прикрутить или что-то подбное

FiNick
FiNick Author

Например сделать так: В PlazaTrader'e


public override void StopExport()
{
	lock (_stopExportLock)
	{
		_streamManager._stopStreamLock.Reset();
		if (!IsExportRunning)
			return;

		StopStream();
		base.StopExport();

		_streamManager._stopStreamLock.WaitOne();
		System.Diagnostics.Trace.WriteLine("Export stopped");
	}
}

В PlazaStreamManager'e

internal readonly AutoResetEvent _stopStreamLock = new AutoResetEvent(false);

_streamsToRemove.SyncDo(c =>
{
     foreach (var stream in _streamsToRemove)
     {
          try
          {
               stream.Close();
          }
          catch (COMException e)
          {
               System.Diagnostics.Trace.WriteLine("stream.Close() - COMException " + e.ErrorCode.ToString());
               Error.SafeInvoke(new PlazaException("Ошибка закрытия потока репликации.", e));
          }
     }

     _streamsToRemove.Clear();
     _stopStreamLock.Set();
});

Или еще избавиться от _stopExportLock и написать так:


public override void StopExport()
{
	_streamManager._stopStreamLock.WaitOne();	
	_streamManager._stopStreamLock.Reset();
	if (!IsExportRunning)
		return;

	StopStream();
	base.StopExport();

	_streamManager._stopStreamLock.WaitOne();
	System.Diagnostics.Trace.WriteLine("Export stopped");	
}
Alexander
Alexander
Alexander

FiNick: Например сделать так: В PlazaTrader'e

public override void StopExport() { lock (_stopExportLock) { _streamManager._stopStreamLock.Reset(); if (!IsExportRunning) return;

	StopStream();
	base.StopExport();

	_streamManager._stopStreamLock.WaitOne();
	System.Diagnostics.Trace.WriteLine("Export stopped");
}

}

> В PlazaStreamManager'e
> ```csharp
internal readonly AutoResetEvent _stopStreamLock = new AutoResetEvent(false);

_streamsToRemove.SyncDo(c =>
{
     foreach (var stream in _streamsToRemove)
     {
          try
          {
               stream.Close();
          }
          catch (COMException e)
          {
               System.Diagnostics.Trace.WriteLine("stream.Close() - COMException " + e.ErrorCode.ToString());
               Error.SafeInvoke(new PlazaException("Ошибка закрытия потока репликации.", e));
          }
     }

     _streamsToRemove.Clear();
     _stopStreamLock.Set();
});

Спасибо. Залил это решение. В 4.0.2 не попало. Необходимо протестировать из исходников.

Alexander
Alexander

Стаканы после клиринга поправил вроде. Если есть возможность - протестируйте сегодня в клиринг, у меня не факт что удастся.

Alexander
Alexander

По коду выше немного не понял для чего нужен _streamManager._stopStreamLock.Reset();.

FiNick
FiNick Author

Alexander Mukhanchikov: По коду выше немного не понял для чего нужен _streamManager._stopStreamLock.Reset();. Чтобы быть уверенным, что перед началом остановки потоков _stopStreamLock находится в закрытом состоянии, т.е. что вызов WaitOne точно остановит выполнение.

я на самом деле никогда с такими штуками не работал, могу ошибаться.

Alexander
Alexander

Фикс с удалением, к сожалению, не помог. Чего-то не так с ревизиями всё равно.

FiNick
FiNick Author

Alexander Mukhanchikov: Фикс с удалением, к сожалению, не помог. Чего-то не так с ревизиями всё равно. Да, действительно. Тут еще такая проблемка: до клиринга выставил заявку, ушел с ней на клиринг. Теперь она висит активной, не могу снять, перезапускал и робота и раутер все равно висит. Запускаю SimpleGUI, там нет этой заявки.

И еще вот что мне РТС написал: По приложенному логу видно, что накапливается очередь сообщений в первые секунды работы. 2011-10-06 16:45:47.234;p2mq-cli;;New message added to recvList. Size: 38 Это приводит к задержкам в получении данных, поэтому предлагается побороться с очередями. Для этого предлагается разбить получение реплики на несколько соединений, работающих в отдельных thread'ах, каждое со своим циклом выборки.

Вот еще странная фраза РТС, которая может помочь=) Используется базовый или безбазовый вариант клиента репликации? В случае безбазового клиента, какова политика обработки ошибок в потоке данных - используется ли накопленная информация для запроса данных?

Alexander
Alexander

Безбазовый у нас клиент, бд не использует.

Alexander
Alexander

Стаканы поправил, в клиринг с 14 до 14:03 проблема со стаканами прошла - пошли дальше как ни в чём не бывало. Посмотрим что будет в вечерний клиринг.

FiNick
FiNick Author

Alexander Mukhanchikov: Стаканы поправил, в клиринг с 14 до 14:03 проблема со стаканами прошла - пошли дальше как ни в чём не бывало. Посмотрим что будет в вечерний клиринг. А вы на каком сервере смотрите, на игровом? Малый клиринг стаканы нормально проходят, проблема была с клирингом 14.45-15.30 Мск. В понедельник протестирую

Alexander
Alexander

FiNick:

Alexander Mukhanchikov: Стаканы поправил, в клиринг с 14 до 14:03 проблема со стаканами прошла - пошли дальше как ни в чём не бывало. Посмотрим что будет в вечерний клиринг. А вы на каком сервере смотрите, на игровом? Малый клиринг стаканы нормально проходят, проблема была с клирингом 14.45-15.30 Мск. В понедельник протестирую

На боевом, да. Тестовый сегодня не работает в связи с обновлением на 3.8.2. Жду 18:45 :)

FiNick
FiNick Author

Alexander Mukhanchikov: На боевом, да. Тестовый сегодня не работает в связи с обновлением на 3.8.2. Жду 18:45 :)

На боевом или на игровом всетаки? ведь чтобы открыть счет на боевом сервере надо робота засертифицировать

Alexander
Alexander

FiNick:

Alexander Mukhanchikov: На боевом, да. Тестовый сегодня не работает в связи с обновлением на 3.8.2. Жду 18:45 :)

На боевом или на игровом всетаки? ведь чтобы открыть счет на боевом сервере надо робота засертифицировать

На полноценном боевом сервере.

Alexander
Alexander

Проверил - фикс работает. Стакан обновляется, после клиринга не останавливается. 👍

Но также надо и остальные таблицы обновлять, удаляя ненужные записи. Чтоб потом не поиметь проблем. Как минимум - если в клиринг приходит StreamDatumDeleted для стрима сделок своих - то все активные сделки с ревизиями меньшей пришедшей - снимаются.