Форум программистов, компьютерный форум, киберфорум
Delphi для начинающих
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.75/4: Рейтинг темы: голосов - 4, средняя оценка - 4.75
12 / 12 / 2
Регистрация: 19.03.2012
Сообщений: 175
1
RAD XE3+

Не завершается работа приложения

27.05.2019, 17:39. Показов 698. Ответов 2

Всем привет!
Есть поток MyThread, который создает поток TThreadDB, в котором выполняется процедура, внутри которой вызывается процедура TForm1.UpdateNotes. Процедура создает компоненты FDConnection и FDQuery для работы с БД. В процессе ее выполнения происходит получение данных с сайта динамически созданным idHttp и запись в БД. Если после вызова процедуры TForm1.UpdateNotes больше одного раза и завершения ее работы закрыть главную форму, то в диспетчере задач остается висеть процесс. Замечено, что метод TThreadDB.Execute второго потока не отрабатывает полностью, то есть не доходит до Form1.LogAdd('I','Поток TThreadDB завершил работу');, хотя у первого потока MyThread.Execute отрабатывает полностью. Если не запускать процедуру TForm1.UpdateNotes, то второй TThreadDB нормально отрабатывает и процессы после закрытия не остаются висеть в диспетчере задач. Объясните, пожалуйста, что я делаю не так?
Код:
TForm1.UpdateNotes
Кликните здесь для просмотра всего текста
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
procedure TForm1.UpdateNotes(element_id:string;typeNotes:string);
var
  temp:string;
  sdvig,i:integer;
  FDQuery:TFDQuery;
  FDConnection:TFDConnection;
  IsDBConnected, IsEndUpdate, IsTableCreated:boolean;
begin
  Form1.logadd('I','Начинаем обновление задач и примечаний по сущности '+typeNotes);
  IsDBConnected:=false;
  //Создаем подключение к БД
  if FileExists(ExtractFilePath(paramstr(0))+'base.mdb') then
  begin
      FDConnection:=TFDconnection.Create(nil);
      FDConnection.DriverName:='MSAcc';
      FDConnection.Params.DriverID:='MSAcc';
      FDConnection.Params.Database:=ExtractFilePath(paramstr(0))+'base.mdb';
      FDConnection.LoginPrompt:=false;
      try
        FDConnection.Connected:=true;
        if FDConnection.Connected then
        begin
          FDQuery:=TFDQuery.Create(nil);
          FDQuery.Connection:=FDConnection;
          FDQuery.SQL.Text:='SELECT * FROM notes';
          try
            FDQuery.Active:=true;
            IsDBConnected:=true;
          except
            Form1.LogAdd('E','Не удалось активировать FDQuery при создании подключения к БД');
            Form1.LogAdd('E',FDQuery.SQL.Text);
            FDquery.Free;
            IsDBConnected:=false;
          end;
        end else
        begin
          Form1.LogAdd('E','Не удалось подключиться к БД');
          FDConnection.Free;
          IsDBConnected:=false;
        end;
 
      except
        Form1.LogAdd('E','Не удалось подключиться к БД (Исключение)');
        FDConnection.Free;
        IsDBConnected:=false;
      end;
  end else
  begin
    Form1.LogAdd('E','Файл базы данных не найден');
    FDConnection.Free;
    IsDBConnected:=false;
  end;
    {
      Конец блока подключения к БД
    }
    if IsDBConnected then //Если есть подключение к БД
    begin
      IsEndUpdate:=false;
      sdvig:=0;
      while not IsEndUpdate do
      begin
        //Ждем полсекунды, что бы не спамить к амо
        sleep(500);
        //Запрашиваем данные с амо
 
        temp:=Form1.GetJson('https://***.amocrm.ru/api/v2/notes?type='+typeNotes+'&element_id='+element_id+'&limit_rows=500&limit_offset='+inttostr(sdvig*500));
        //Если массив item не пустой
        if (pos('items":[{',temp)>0) AND (pos('items":[{}]',temp) = 0) then
        begin
          //Поток не создаем, т.к. выгрузка notes получает по одной сущности и эта операция не долгая
          //Создаем временную таблицу
          if IsDBConnected then //Если подключение успешно создано
          begin
            //Создаем временную таблицу
            FDQuery.SQL.Text:='SELECT * INTO notes'+IntToStr(sdvig)+' FROM (SELECT * FROM notes WHERE 1<>1) AS T';
            try
              FDQuery.ExecSQL;
              isTableCreated:=true;
              except
                Form1.LogAdd('E','Не удалось создать временную таблицу notes'+IntToStr(sdvig));
              end;
              //Временная таблица создана. Открываем ее
            try
              FDQuery.Open('Select * from notes'+IntToStr(sdvig));
            except
              Form1.LogAdd('E','Нe удалось выполнить запрос: '+Fdquery.SQL.Text);
            end;
            if isTableCreated then
            begin
              //LogAdd('I','Всего: '+IntToStr(SO(temp).O['_embedded'].A['items'].Length));
              //Запускаем цикл обработки и внесения данных в БД
              for I := 0 to SO(temp).O['_embedded'].A['items'].Length-1 do
              begin
                //Добавляем в лог инфу, что бы не уснуть, пока идет выгрузка
                form1.LogAdd('I','Таблица notes'+IntToStr(sdvig)+': Запись №'+IntToStr(i+1));
                //Начинаем запись в БД
                FDQuery.Insert;
                FDQuery.FieldByName('notes_id').Value:=SO(temp).O['_embedded'].A['items'].o[i].i['id']; //ID события
                FDQuery.FieldByName('created_by').Value:=SO(temp).O['_embedded'].A['items'].o[i].i['created_by']; //ID создашего событие
                FDQuery.FieldByName('account_id').Value:=SO(temp).O['_embedded'].A['items'].o[i].i['account_id']; //ID аккаунта, на котором содано событие
                FDQuery.FieldByName('group_id').Value:=SO(temp).O['_embedded'].A['items'].o[i].i['group_id']; //ID группы в которой состоит пользователь, имеющий отношение к событию
                case SO(temp).O['_embedded'].A['items'].o[i].i['element_type'] of //Тип сущности элемента, в карточку которого будет добавлено событие
                  1: FDQuery.FieldByName('element_type').Value:='Контакт';
                  2: FDQuery.FieldByName('element_type').Value:='Сделка';
                  3: FDQuery.FieldByName('element_type').Value:='Компания';
                  4: FDQuery.FieldByName('element_type').Value:='Задача';
                  12:FDQuery.FieldByName('element_type').Value:='Покупатель';
                end;
                FDQuery.FieldByName('element_id').Value:=SO(temp).O['_embedded'].A['items'].o[i].i['element_id']; //id элемента, в карточку которого будет добавлено событие
                FDQuery.FieldByName('notes_text').Value:=SO(temp).O['_embedded'].A['items'].o[i].S['text']; //Текст события
                case SO(temp).O['_embedded'].A['items'].o[i].i['note_type'] of   //Тип события
                  1: FDQuery.FieldByName('note_type').Value:='Сделка создана';
                  2: FDQuery.FieldByName('note_type').Value:='Контакт создан';
                  3: FDQuery.FieldByName('note_type').Value:='Статус сделки изменен';
                  4: FDQuery.FieldByName('note_type').Value:='Обычное примечание';
                  12: FDQuery.FieldByName('note_type').Value:='Компания создана';
                  13: FDQuery.FieldByName('note_type').Value:='Результат по задаче';
                  25: FDQuery.FieldByName('note_type').Value:='Системное сообщение';
                  102: FDQuery.FieldByName('note_type').Value:='Входящее смс';
                  103: FDQuery.FieldByName('note_type').Value:='Исходящее смс';
                end;
                FDQuery.FieldByName('created_at').Value:=Form1.UnixToDateTime(SO(temp).O['_embedded'].A['items'].o[i].i['created_at']); //Время создания события
                FDQuery.FieldByName('updated_at').Value:=Form1.UnixToDateTime(SO(temp).O['_embedded'].A['items'].o[i].i['updated_at']); //Время последнего обновления
                FDQuery.FieldByName('responsible_user_id').Value:=SO(temp).O['_embedded'].A['items'].o[i].i['responsible_user_id']; //id пользователя ответственного за событие
                FDQuery.Post;
              end;
              //Объединяем временную таблицу с основной
              FDQuery.SQL.Text:='INSERT INTO notes SELECT notes'+IntToStr(Sdvig)+'.* FROM notes'+IntToStr(Sdvig)
                +' LEFT JOIN notes ON notes'+IntToStr(Sdvig)+'.notes_id=notes.notes_id WHERE notes.notes_id IS NULL';
              try
                FDQuery.ExecSQL;
              except
                Form1.LogAdd('E','Не удалось выполнить запрос: '+FDQuery.SQL.Text);
              end;
              //Удаляем временную таблицу
              FDQuery.SQL.Text:='DROP TABLE notes'+IntToStr(Sdvig);
              try
                FDQuery.ExecSQL;
              except
                Form1.LogAdd('E','Не удалось выполнить запрос: '+FDQuery.SQL.Text);
              end;
            end;
          end;
        end else //Если массив items пустой
          IsEndUpdate:=true;
        Inc(sdvig);
      end;
      //Освобождаем память
    FDQuery.Active:=false;
    FDQuery.Free;
    FDConnection.Close;
    FDConnection.Free;
  end;
end;

TForm1.GetJson
Кликните здесь для просмотра всего текста
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
function TForm1.GetJson(url: string): string;
var
  Http:TIdHttp;
  login, api : string;
  params:TStringList;
begin
  if IsInternet then
  begin
    Http:=TIdHttp.Create(self);
    login:='***';
    api:='***';
    params:=TstringList.Create;
    params.Add('USER_LOGIN='+login);
    params.Add('USER_HASH='+api);
    try
      //Авторизуемся
      Http.Post('https://***.amocrm.ru/private/api/auth.php',params);
    except
      LogAdd('E','Не удалось выполнить запрос на авторизацию в amoCRM');
      result:='';
    end;
    params.Clear;
    if Http.ResponseCode = 200 then
    begin
      //Получаем данные
      try
        result:=JsonDecode(Http.Get(url));
      except
        LogAdd('E','Не удалось получить данные из amoCRM');
        result:='';
      end;
    end else
    begin
      result :='';
    end;
 
    params.Free;
    Http.Free;
 
  end else
  begin
    LogAdd('E','Нет подключения к интернету');
    result:='';
  end;
 
 
end;

P.S.: Надеюсь Вы не запутались что чего вызывает...
0

Помощь в написании контрольных, курсовых и дипломных работ здесь.

Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
27.05.2019, 17:39
Ответы с готовыми решениями:

Как программно произвести перезапуск приложения, если оно завершается из диспетчера задач (вкладка процессы) методом убийства процесса?
Это возможно вообще?

После закрытия приложения процесс не завершается
Сделал приложение для работы с HID устройствами. Всё что мне необходимо она выполняет, НО когда...

Не завершается процесс Excel после закрытия приложения
Часто встречался с подобным вопросом, и сам попадал на эти грабли. После завершения приложения...

Завершается работа проводника
Здравствуйте. У меня такая проблема.. В компьютерах и их &quot;внутренних&quot; устройствах я мало что...

2
5026 / 3919 / 1296
Регистрация: 14.04.2014
Сообщений: 18,027
Записей в блоге: 18
28.05.2019, 09:50 2
без анализа логики пока
1. использование переменной Form1 в методе класса TForm1 это безусловно баг
2. если вы из потока вызываете форму без синхронизации - это баг
3. а если с синхронизацией - это логический баг. нафига поток, если все все равно в главном происходит????
4. создание подключения - это довольно затратная операция, а вы его создаете каждый раз заново. зачем?
5. вообще не понял для чего кусок "SELECT * FROM NOTES" --- "Не удалось активировать FDQuery при создании подключения к БД". Подключение либо есть либо нет. Что его проверять. все уже проверено...
6. просто от души рекомендую писать ровно так как вы проговариваете сценарий
Цитата Сообщение от Vyazan Посмотреть сообщение
В процессе ее выполнения происходит получение данных с сайта динамически созданным idHttp и запись в БД.
переводим
Delphi
1
2
GetDataFromWeb(Data);
SaveDataToDb(Data);
и далее каждую процедуру дорабатываем по нисходящей.
потому что вот эти простыни, где каждое крыло IF по 200 строк, абсолютно неремонтопригодны...
7. TForm1.GetJson несмотря на то, что внутри все правильно, но какое отношение она имеет к Form1 ???
Это скорее метод класса, который у вас работает с данными. Или к-нить класса TMyAPI, но не TForm1

а для ответа на основной вопрос данных все равно не хватает, потому что неясно именно кто кого когда и главное по каким ссылкам вызывает.
попробуйте убрать минорные ошибки и структурировать программу. ошибка или уйдет сама, или ее станет легче отыскать
1
12 / 12 / 2
Регистрация: 19.03.2012
Сообщений: 175
28.05.2019, 12:23  [ТС] 3
Принял, сделаю. Отпишусь. Спасибо
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
28.05.2019, 12:23

Работа компьютера очень долго завершается
ОС: Windows 7 x64 Максимальная Компьютер - член домена. Проблема в том, что работа компьютера...

Работа с матрицами (программа завершается аварийно)
Помогите, на Си, не С++. Выдает другие значения, к тому же аварийно завершает программу Для...

Не завершается работа пока не включатся HDD
Windows 7x64 В системе несколько жестких дисков и после простоя отключается их питание. После...

При вводе полей структуры завершается работа программы
Решаю задачи по Прата. При вводе полей структуры резко завершает программу. #include&lt;iostream&gt;...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
3
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.