-
Добрый день. Есть программа работы с кассовым аппаратом. В отдельном модуле реализовано хранение чеков в БД, в отдельном работа с web-сервисом (обмен json-данных) с 1С.
Необходимо написать отправку данных в 1С в отдельном потоке. Программа должна делать выборку из БД данных, которые не отправлены и отправлять в 1С. В случае успешной отправки помечать запись как отправленную. К сожалению, у меня совсем не получается постичь работу в Delphi с потоками, поэтому пишу в эту конференцию.
Вопросы по теме: 1. Как лучше делать выборку неотправленных данных? По одной записи или все неотправленные и все отправлять? Чтобы фризов в основной программе не было. 2. Как правильно описать Объект потока? В основном потоке уже есть открытое соединение с БД. Надо будет создавать новое соединение? 3. Как правильно вызвать этот поток? При запуске программы (открытии основной формы) или по таймеру запускать (например каждую минуту)?
Delphi 7. БД: Firebird 2.5.7 embed. WS: Synapse и lkJSON.
-
> Чтобы фризов в основной программе не было.
вроде как, эту проблем уже решает отдельный поток 1. да как угодно. если объем данных небольшой, соединение устойчивое - все сразу. 2. если отправлять по одной записи, то к бд вообще нет смысла обращаться, данные уже есть (внесение в бд же ими делается) 3. если отправлять по одной записи, то сразу при появлении данных. если все сразу - то по завершении кассовой смены.
-
а еще это может регламентироваться законодательством, сразу или не сразу отправлять.
-
Не, данные по законодательству отправляются самим аппаратом. А вот в 1С, по-хорошему, надо сразу видеть что оплатили, а что еще нет. А так как есть точки удаленные с нестабильным интернетом, надо предусмотреть что когда чек был пробит инета не было, а потом пытаться, пытаться, пытаться отправить.
-
Можно простенький примерчик, в какой момент получать данные, в какой отправлять данные, получать ответ от веб-сервиса, записывать флаг об успешной отправке и, главное, в какой момент вызывать синхронизации с основным потоком, чтобы зависаний не было.
-
Synapse разве не умеет асинхронно работать?
-
Нет. ICS асинхронно работает. Помимо этого хочу разобраться на небольшом но осязаемом примере как правильно использовать потоки.
-
> Можно простенький примерчик, в какой момент получать данные, > в какой отправлять данные, получать ответ от веб-сервиса, > записывать флаг об успешной отправке и, главное, в какой > момент вызывать синхронизации с основным потоком, чтобы > зависаний не было.
Это не простенький примерчик. И все эти моменты определяет программист. Про зависания вообще непонятно. Имеет смысл сначала всё-таки прочитать книжки по делфи, коих множество, и в коих есть простенькие примерчики отдельных задач. И тогда вопрос либо отпадет, либо трансформируется в что-то более конкретное. А вот если бы я писал эту программу, то делал бы ее по ТЗ заказчика.
-
procedure SendLocalDataToServer; var sthr : TSendThread; begin // sthr := TSendThread.Create(True); sthr.fhttp := http; sthr.Priority := tpLower; sthr.FreeOnTerminate := True; end;
{ TSendThread }
procedure TSendThread.Execute; var s : string; begin inherited; while True do begin if Terminated then Break; if not DM.SelectDataForSend then begin Terminate; Break; end; DM.ibqryThread.First; if fhttp.PostPayData( DM.ibqryThread.FieldByName('chid').AsInteger, DM.ibqryThread.FieldByName('cheque_type').AsInteger, DM.ibqryThread.FieldByName('cheque_time').AsDateTime, DM.ibqryThread.FieldByName('aw_date').AsDateTime, DM.ibqryThread.FieldByName('client').AsString, DM.ibqryThread.FieldByName('aw_code').AsString, DM.ibqryThread.FieldByName('department').AsInteger, DM.ibqryThread.FieldByName('vat_type').AsInteger, DM.ibqryThread.FieldByName('quantity').AsFloat, DM.ibqryThread.FieldByName('price').AsFloat, DM.ibqryThread.FieldByName('summ').AsFloat, DM.ibqryThread.FieldByName('vatsumm').AsFloat, DM.ibqryThread.FieldByName('summ1').AsFloat, DM.ibqryThread.FieldByName('summ2').AsFloat, DM.ibqryThread.FieldByName('summ3').AsFloat, DM.ibqryThread.FieldByName('summ4').AsFloat, DM.ibqryThread.FieldByName('vat18').AsFloat, DM.ibqryThread.FieldByName('vat10').AsFloat, DM.ibqryThread.FieldByName('vat0').AsFloat, s) then begin // TODO // write code for mark this cheque as posted on server end; end; end;
Может подскажете на таком примере правильное направление мысли?
-
здесь нет мысли ))) лишь небезопасная отправка кучки полей через http-post, и без примера обработки ошибок.
-
Т.е. простенького примера (можно из комментариев) какой структуры вы бы написали объект потока, в каких процедурах и в какой момент делать выборку данных, отправку в 1с, запись в бд и вызов встроенных процедур самого потока в конференции новичков не дождешься? Н-да... страшно представить чтобы в остальных конференциях сказали и куда послали... Спасибо, что не отказали.
-
по коду: непонятно используется ли отдельная сессия для запроса из потока.
по дизайну: эй, поток, я вон там оставил для тебя какие-то штуки. у тебя в юзез мой дм, плюс ты умный, так что сходи туда возьми все что надо (ты знаешь) и сделай что мне надо.
-
Зря вы так... Спасибо брату, что нашел время и помог мне. Я, конечно, до сих пор не понял как с ним работать, но с его помощью и методом тыка написал такой код, который работает. constructor TSendThread.Create; begin fhttp := THttpService.Create; fTimeout := 1000; inherited Create(False); end;
procedure TSendThread.SendData; var s : string; begin if not DM.SelectDataForSend then begin fTimeout := 5000; end else begin fTimeout:= 1000; with DM.ibqryThread do begin First;
if fhttp.PostPayData( FieldByName('chid').AsInteger, FieldByName('cheque_type').AsInteger, FieldByName('cheque_time').AsDateTime, FieldByName('awbdate').AsDateTime, FieldByName('client').AsString, FieldByName('awbcode').AsString, FieldByName('department').AsInteger, FieldByName('vat_type').AsInteger, FieldByName('quantity').AsFloat, FieldByName('price').AsFloat, FieldByName('summ').AsFloat, FieldByName('vatsumm').AsFloat, FieldByName('summ1').AsFloat, FieldByName('summ2').AsFloat, FieldByName('summ3').AsFloat, FieldByName('summ4').AsFloat, FieldByName('vat18').AsFloat, FieldByName('vat10').AsFloat, FieldByName('vat0').AsFloat, s) then begin DM.SetChequePosted(FieldByName('chid').AsInteger); end; end; end; end;
procedure TSendThread.Execute; begin while not Terminated do begin Synchronize(SendData); Sleep(fTimeout); end; end;
Я не просил за меня написать код. Я просил помочь разобраться со структурой вызовов: где что и когда вызывать... В этом без брата я бы не разобрался. Я от сообщества ожидал, что-то типа такого:
procedure TThread.SendData;
begin
end;
procedure TThread.Execute;
begin
while not Terminated do begin
Syncronize(SendData);
Sleep(1000);
end;
end;
Что сложного написать тому, кто это знает и главное понимает, эти 10 строк. Я тоже это знаю, и программировать на каких-то языках могу очень сложные приложения, а на каких-то только понять, что писал автор, но вот никак не могу усвоить в какой последовательности надо программировать работу с потоками в Delphi. И пример про сортировку разобрал из поставки, но как применить его конкретно на моем примере так и не понял. Спасибо. Вопрос закрыт
-
> Kirill © (22.08.17 16:34) [6] > > Нет. ICS асинхронно работает.
Хм. ICS действительно работает как правило асинхронно. В это одна из главных её особенностей (но и синхронно тоже умеет). Но при чем тут ICS?
-
-
> Kirill © (24.08.17 00:57) [12]
> Вопрос закрыт
Вряд ли вопрос закрыт. Дело в том, что в такой редакции второй поток не имеет никакого смысла. Смотрим метод Execute:
procedure TSendThread.Execute; begin while not Terminated do begin Synchronize(SendData); Sleep(fTimeout); end; end;
Видим, что:
1. Метод SendData вызывается через метод Synchronize - то есть, метод SendData все равно будет выполнен в главном (а не во втором) потоке.
2. Sleep - в данном случае не дает ничего, кроме тормозов (ну разве что разгружает процессор, больше никакого прока от него здесь нет).
3. Больше ничего второй поток не делает. Какой же тогда в нем смысл? Без него все будет работать точно так же.
-
плюс снова непонятно есть ли у брата отдельная от основной сессия с бд.
-
> они есть практически в любой книжке. что сложного в чтении > книжки?
А это из разряда смотрим в книгу, видим фигу. Это проблема моего мышления. Пока я не могу представить в голове, я этого не понимаю и не запоминаю. Я так с фуаном мучался в универе. Я ж говорю, и примеров полно и код рабочий был по потокам, ну не могу понять как он работает. Ответы Юрия тому пример.
> Метод SendData вызывается через метод Synchronize - то есть, > метод SendData все равно будет выполнен в главном (а не > во втором) потоке.
Т.е. вызывать надо без него?
> Sleep - в данном случае не дает ничего, кроме тормозов (ну > разве что разгружает процессор, больше никакого прока от > него здесь нет)
Sleep не делает DDOS атаку на web-сервис 1С. Т.е. он отправляет неотправленные чеки с периодичностью каждую секунду, а если в последний раз не было ничего на отправку, то ждет уже 5 сек.
> Больше ничего второй поток не делает. Какой же тогда в нем > смысл? Без него все будет работать точно так же.
Смысл в том, чтобы пользователь продолжал работать с кассой, а сама программа отправляла подтверждения оплат не блокируя интерфейс.
> плюс снова непонятно есть ли у брата отдельная от основной > сессия с бд.
На счет его я не знаю, какая у него структура БД, а у меня нет. Надо новую? А если FB Embeded?
-
Sleep не делает DDOS
вотэтоповорот. кто бы мог подумать.
На счет его я не знаю, какая у него структура БД, а у меня нет. Надо новую? А если FB Embeded?
уже пофик.
-
Смысл в том, чтобы пользователь продолжал работать с кассой, а сама программа отправляла подтверждения оплат не блокируя интерфейс.
без этого потока все будет точно так же. тютя в тютю. даже немного более быстрее и менее тормознуто.
|