← Zurück

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

Во время клиринга вылетает огромное колличество ошибок "Ошибка проверки потока репликации. Код -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);, что и дает ошибку.

War dieses Thema hilfreich?

Thema teilen

Kommentare (37)

Anmelden oder Konto erstellen, Melden Sie sich an oder registrieren Sie sich, um einen Kommentar zu hinterlassen

Mikhail Sukhov
Mikhail Sukhov

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

Что за стек?

FiNick
FiNick Autor

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 Autor

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

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

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

Alexander
Alexander

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

FiNick
FiNick Autor
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 Autor

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

Alexander
Alexander

FiNick:

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

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

FiNick
FiNick Autor

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

Alexander
Alexander

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

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

FiNick
FiNick Autor

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

Я смотрел логи, в начале клиринга по потоку 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 Autor

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 Autor

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

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

Alexander
Alexander

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

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

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

FiNick
FiNick Autor

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

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

Alexander
Alexander

FiNick:

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

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

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

FiNick
FiNick Autor

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

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

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

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

FiNick
FiNick Autor

Например сделать так: В 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 Autor

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

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

Alexander
Alexander

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

FiNick
FiNick Autor

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 Autor

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 Autor

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

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

Alexander
Alexander

FiNick:

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

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

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

Alexander
Alexander

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

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