Skip to content

Commit c8690ba

Browse files
committed
Какие-то фиксы
1 parent 73f899c commit c8690ba

File tree

2 files changed

+64
-167
lines changed

2 files changed

+64
-167
lines changed

src/Классы/ПулСоединений.os

Lines changed: 34 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,11 @@
2828
Карта_КоннекторНаКонтекст = Новый Соответствие;
2929

3030
// Создаем начальный набор соединений
31-
Для Индекс = 1 По РазмерПула Цикл
31+
Счетчик = 0;
32+
Пока Счетчик < РазмерПула Цикл
3233
Соединение = СоздатьНовоеСоединение();
3334
ДоступныеСоединения.Добавить(Соединение);
35+
Счетчик = Счетчик + 1;
3436
КонецЦикла;
3537
КонецПроцедуры
3638

@@ -131,46 +133,16 @@
131133
Карта_КоннекторНаКонтекст.Очистить();
132134
КонецПроцедуры
133135

134-
// Очистить завершенные контексты
135-
// Проверяет статус фоновых заданий и освобождает соединения завершенных контекстов
136-
// При недоступности API фоновых заданий использует эвристическую очистку
137-
//
138136
Процедура ОчиститьЗавершенныеКонтексты()
139-
Попытка
140-
// Пытаемся использовать API фоновых заданий для точной очистки
141-
Если ТипЗнч(ФоновыеЗадания) = Тип("МенеджерФоновыхЗаданий") Тогда
142-
ОчиститьЗавершенныеКонтексты_ЧерезAPI();
137+
КонтекстыДляПроверки = Новый Массив;
138+
Для Каждого Элемент Из Карта_КонтекстНаКоннектор Цикл
139+
КонтекстыДляПроверки.Добавить(Элемент.Ключ);
140+
КонецЦикла;
141+
Для Каждого КонтекстID Из КонтекстыДляПроверки Цикл
142+
Если ПроверитьЗавершениеКонтекста(КонтекстID) Тогда
143+
ОсвободитьКонтекст(КонтекстID);
143144
КонецЕсли;
144-
Исключение
145-
// Если API недоступен или возникла ошибка, используем эвристическую очистку
146-
КонецПопытки;
147-
148-
// Эвристическая очистка как запасной вариант
149-
ОчиститьЗавершенныеКонтексты_Эвристически();
150-
КонецПроцедуры
151-
152-
// Очистка завершенных контекстов через API фоновых заданий
153-
//
154-
Процедура ОчиститьЗавершенныеКонтексты_ЧерезAPI()
155-
Попытка
156-
// Получаем список всех контекстов, привязанных к соединениям
157-
КонтекстыДляПроверки = Новый Массив;
158-
Для Каждого Элемент Из Карта_КонтекстНаКоннектор Цикл
159-
КонтекстыДляПроверки.Добавить(Элемент.Ключ);
160-
КонецЦикла;
161-
162-
// Проверяем каждый контекст
163-
Для Каждого КонтекстID Из КонтекстыДляПроверки Цикл
164-
КонтекстЗавершен = ПроверитьЗавершениеКонтекста(КонтекстID);
165-
Если КонтекстЗавершен Тогда
166-
ОсвободитьКонтекст(КонтекстID);
167-
КонецЕсли;
168-
КонецЦикла;
169-
170-
Исключение
171-
// Если произошла ошибка при работе с API, просто игнорируем
172-
// Эвристическая очистка сработает как запасной вариант
173-
КонецПопытки;
145+
КонецЦикла;
174146
КонецПроцедуры
175147

176148
// Проверить, завершен ли контекст (фоновое задание или основной поток)
@@ -207,49 +179,32 @@
207179
//
208180
Функция ПроверитьСтатусФоновогоЗадания(ЗаданиеID)
209181
Попытка
210-
// В OneScript может быть доступен метод для получения задания по ID
211-
// Пока используем заглушку, так как точный API неизвестен
212-
213-
// Предполагаемый код (когда API будет доступен):
214-
// Задание = ФоновыеЗадания.НайтиПоИдентификатору(ЗаданиеID);
215-
// Если Задание <> Неопределено Тогда
216-
// Возврат Задание.Состояние = СостояниеФоновогоЗадания.Завершено
217-
// ИЛИ Задание.Состояние = СостояниеФоновогоЗадания.ЗавершеноАварийно;
218-
// КонецЕсли;
219-
220-
Возврат Ложь; // Консервативный подход - не освобождаем, пока не уверены
221-
222-
Исключение
223-
Возврат Ложь; // При ошибке считаем задание активным
224-
КонецПопытки;
225-
КонецФункции
226-
227-
// Эвристическая очистка контекстов для предотвращения утечек памяти
228-
//
229-
Процедура ОчиститьЗавершенныеКонтексты_Эвристически()
230-
МаксимальноеКоличествоКонтекстов = 100;
231-
232-
Если Карта_КонтекстНаКоннектор.Количество() > МаксимальноеКоличествоКонтекстов Тогда
233-
// Создаем список контекстов для удаления (самые старые)
234-
КонтекстыДляУдаления = Новый Массив;
235-
Счетчик = 0;
236-
КоличествоДляУдаления = Карта_КонтекстНаКоннектор.Количество() - МаксимальноеКоличествоКонтекстов;
237-
238-
Для Каждого Элемент Из Карта_КонтекстНаКоннектор Цикл
239-
Если Счетчик < КоличествоДляУдаления Тогда
240-
КонтекстыДляУдаления.Добавить(Элемент.Ключ);
241-
Счетчик = Счетчик + 1;
182+
// Получаем актуальный список заданий. Если задание отсутствует - считаем завершенным.
183+
МассивЗаданий = ФоновыеЗадания.ПолучитьФоновыеЗадания();
184+
Для Каждого Задание Из МассивЗаданий Цикл
185+
Если Задание.УникальныйИдентификатор <> ЗаданиеID Тогда
186+
Продолжить;
187+
КонецЕсли;
188+
Попытка
189+
Сост = Задание.Состояние;
190+
Исключение
191+
// Не удалось получить состояние - считаем активным
192+
Возврат Ложь;
193+
КонецПопытки;
194+
Если Сост = СостояниеФоновогоЗадания.Активно Тогда
195+
Возврат Ложь;
242196
Иначе
243-
Прервать;
197+
Возврат Истина;
244198
КонецЕсли;
245199
КонецЦикла;
246-
247-
// Освобождаем старые контексты
248-
Для Каждого КонтекстID Из КонтекстыДляУдаления Цикл
249-
ОсвободитьКонтекст(КонтекстID);
250-
КонецЦикла;
251-
КонецЕсли;
252-
КонецПроцедуры
200+
201+
// Не нашли задание - вероятно завершено и очищено менеджером
202+
Возврат Истина;
203+
Исключение
204+
// При любой ошибке (например, свойство недоступно) возвращаем Ложь - не освобождаем раньше времени
205+
Возврат Ложь;
206+
КонецПопытки;
207+
КонецФункции
253208

254209
// Создать новое соединение
255210
//

tests/МногопоточностьФоновыеЗадания.os

Lines changed: 30 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -248,22 +248,6 @@
248248
// Проверяет многопоточную работу менеджера сущностей в режиме фоновых заданий
249249
&Тест
250250
Процедура МногопоточнаяРаботаСФоновымиЗаданиями() Экспорт
251-
// Проверяем доступность API фоновых заданий
252-
253-
ДоступныФоновыеЗадания = Ложь;
254-
Попытка
255-
Если ТипЗнч(ФоновыеЗадания) = Тип("МенеджерФоновыхЗаданий") Тогда
256-
ДоступныФоновыеЗадания = Истина;
257-
КонецЕсли;
258-
Исключение
259-
// API фоновых заданий недоступен
260-
КонецПопытки;
261-
262-
Если НЕ ДоступныФоновыеЗадания Тогда
263-
Сообщить("API фоновых заданий недоступен. Выполняем симуляцию многопоточности.");
264-
ВыполнитьСимуляциюМногопоточности();
265-
Возврат;
266-
КонецЕсли;
267251

268252
// Создаем менеджер с пулом соединений для тестирования
269253
ТипКоннекторы = ТипЗнч(МенеджерСущностей.ПолучитьКоннектор());
@@ -297,23 +281,7 @@
297281
КонецЦикла;
298282

299283
// Ждем завершения всех фоновых заданий (максимум 10 секунд)
300-
СчетчикОжидания = 0;
301-
Пока СчетчикОжидания < 100 Цикл
302-
ВсеЗавершены = Истина;
303-
Для Каждого Задание Из МассивЗаданий Цикл
304-
Если Задание.Состояние = СостояниеФоновогоЗадания.Активно Тогда
305-
ВсеЗавершены = Ложь;
306-
Прервать;
307-
КонецЕсли;
308-
КонецЦикла;
309-
310-
Если ВсеЗавершены Тогда
311-
Прервать;
312-
КонецЕсли;
313-
314-
Приостановить(100); // 100 мс
315-
СчетчикОжидания = СчетчикОжидания + 1;
316-
КонецЦикла;
284+
ОжидатьЗавершенияВсехЗаданий(МассивЗаданий, 100, 100);
317285

318286
// Фиксируем транзакцию основного потока
319287
МенеджерСПулом.ЗафиксироватьТранзакцию(ОсновнойКонтекстID);
@@ -345,64 +313,35 @@
345313
МенеджерСПулом.Закрыть();
346314
КонецПроцедуры
347315

348-
// Симуляция многопоточности когда API фоновых заданий недоступен
349-
Процедура ВыполнитьСимуляциюМногопоточности()
350-
// Создаем несколько независимых контекстов для имитации многопоточности
351-
ТипКоннекторы = ТипЗнч(МенеджерСущностей.ПолучитьКоннектор());
352-
МенеджерСПулом = Новый МенеджерСущностей(
353-
ТипКоннекторы,
354-
СтрокаСоединенияКоннектора,
355-
Неопределено,
356-
3
357-
);
358-
МенеджерСПулом.ДобавитьКлассВМодель(Тип("Автор"));
359-
МенеджерСПулом.Инициализировать();
360-
361-
// Имитируем параллельную работу нескольких "потоков"
362-
МассивКонтекстов = Новый Массив;
363-
364-
// "Поток" 1
365-
КонтекстID1 = МенеджерСПулом.НачатьТранзакцию();
366-
МассивКонтекстов.Добавить(КонтекстID1);
367-
368-
Автор1 = Новый Автор;
369-
Автор1.Имя = "Поток1";
370-
Автор1.ВтороеИмя = "Симуляция";
371-
МенеджерСПулом.Сохранить(Автор1, КонтекстID1);
372-
373-
// "Поток" 2
374-
КонтекстID2 = МенеджерСПулом.НачатьТранзакцию();
375-
МассивКонтекстов.Добавить(КонтекстID2);
376-
377-
Автор2 = Новый Автор;
378-
Автор2.Имя = "Поток2";
379-
Автор2.ВтороеИмя = "Симуляция";
380-
МенеджерСПулом.Сохранить(Автор2, КонтекстID2);
381-
382-
// "Поток" 3 с ошибкой
383-
КонтекстID3 = МенеджерСПулом.НачатьТранзакцию();
384-
МассивКонтекстов.Добавить(КонтекстID3);
385-
386-
Автор3 = Новый Автор;
387-
Автор3.Имя = "Поток3";
388-
Автор3.ВтороеИмя = "СОшибкой";
389-
МенеджерСПулом.Сохранить(Автор3, КонтекстID3);
390-
391-
// Фиксируем первые два, третий откатываем
392-
МенеджерСПулом.ЗафиксироватьТранзакцию(КонтекстID1);
393-
МенеджерСПулом.ЗафиксироватьТранзакцию(КонтекстID2);
394-
МенеджерСПулом.ОтменитьТранзакцию(КонтекстID3); // Имитируем ошибку
395-
396-
// Проверяем результат
397-
Результат = МенеджерСПулом.ПолучитьКоннектор().ВыполнитьЗапрос("SELECT * FROM Авторы ORDER BY Имя");
398-
Ожидаем.Что(Результат, "Должны сохраниться только успешные операции").ИмеетДлину(2);
399-
Ожидаем.Что(Результат[0].Имя, "Первый автор").Равно("Поток1");
400-
Ожидаем.Что(Результат[1].Имя, "Второй автор").Равно("Поток2");
401-
402-
МенеджерСПулом.Закрыть();
316+
// Ожидать завершения всех переданных фоновых заданий
317+
//
318+
// Параметры:
319+
// Задания - Массив - Массив фоновых заданий (объекты типа ФоновоеЗадание)
320+
// МаксИтераций - Число - Максимальное количество итераций ожидания
321+
// ИнтервалМС - Число - Пауза между итерациями в миллисекундах
322+
Процедура ОжидатьЗавершенияВсехЗаданий(Задания, МаксИтераций, ИнтервалМС)
323+
СчетчикОжидания = 0;
324+
Пока СчетчикОжидания < МаксИтераций Цикл
325+
ВсеЗавершены = Истина;
326+
Для Каждого Задание Из Задания Цикл
327+
Если Задание.Состояние = СостояниеФоновогоЗадания.Активно Тогда
328+
ВсеЗавершены = Ложь;
329+
Прервать;
330+
КонецЕсли;
331+
КонецЦикла;
332+
Если ВсеЗавершены Тогда
333+
Прервать;
334+
КонецЕсли;
335+
Приостановить(ИнтервалМС);
336+
СчетчикОжидания = СчетчикОжидания + 1;
337+
КонецЦикла;
403338
КонецПроцедуры
404339

340+
405341
// Процедура для выполнения в фоновом задании
342+
// Создание автора в отдельной транзакции (используется в тестах фоновых заданий)
343+
// Параметры:
344+
// ПараметрыЗадания - Структура - Данные для выполнения (МенеджерСущностей, НомерЗадания)
406345
Процедура ФоновоеЗаданиеСозданияАвтора(ПараметрыЗадания) Экспорт
407346
МенеджерСущностей = ПараметрыЗадания.МенеджерСущностей;
408347

@@ -425,6 +364,9 @@
425364
КонецПроцедуры
426365

427366
// Процедура для выполнения в фоновом задании с пулом соединений
367+
// Создание автора при активном пуле соединений (используется в тестах)
368+
// Параметры:
369+
// ПараметрыЗадания - Структура - Данные для выполнения (МенеджерСущностей, НомерЗадания)
428370
Процедура ФоновоеЗаданиеСозданияАвтораСПулом(ПараметрыЗадания) Экспорт
429371
МенеджерСущностей = ПараметрыЗадания.МенеджерСущностей;
430372
НомерЗадания = ПараметрыЗадания.НомерЗадания;

0 commit comments

Comments
 (0)