You are not logged in.
Zeos with mariadb
postgresql with mormot's direct
In an other thread, you propose to recreate the database connection. How can I do that?
I notice that I can "expire" the connections pool. What should I check before doing that?
The in-memory dictionary can not be used if I have an other app outside mormot that feeds too records.
I can use the in-memory dictionary for a number of tables, but not for all.
The problem with the TrestBatch, is that sometimes the next orm object needs first object's IDvalue in one of its properties.
How can I handle this?
So why not just this PtrInt field as the TID?
Because in the near future, the unique field can be a string too. In an other table, it is a GUID
Some comments:
1) don't use PtrInt for a field, it is not portable between 32-bit and 64-bit. Use explicit Int64 or integer.
2) what do you store into this field? Why just not use the TID?
3) look at TSynUniqueIdentifier if you really need a separated field, or at TOrmModel.SetIDGenerator() to have the ORM fill the TID directly.
The unique field TormTable.unif's content is predefined by other source. I can not change it. But I must have one record in the table per TormTable.unif content.
I thought about hash32 for defining idvalue but I want to avoid it, because in other tables I have multiple unique fields and it becomes more possible for duplicate hash result
Probably a scenario for a newbie but I am not still sure how to implemented correctly with mormot2:
Everything from the following is happening in the server which connects to an external database and I am using AcquireExecutionMode[execOrmWrite/Get]:=amBackgroundThread;
I have a table TormTable, that except the table ID, it has also an other unique field unif, covered with a unique database index.
TormTable=class(Torm)
published
property unif:ptrint read Funif write Funif;
end;
Before I add a new record in this table (as one job in a list of sql orm adds), I check if an existing record has the same content with the field TormTable.unif and use this record instead.
My problem is to add a new record in this table in a race condition:
Checking if a record with the same TormTable.unif exists and using a TRestBatch for all adds in my function is a solution.
But it can cause a error is a record with the same TormTable.unif contents was just inserted by an other web client request. (There is also a small possibility that such a record can be added by an other external software in the db-This table is defined to check maxID before each insert in mormot).
I was thinking that I can repeat the check and the Trestbatch. But sometimes I am getting out of sync errors from Zeos with indexes collisions and I have not find a solution to avoid them.
In such a case, what is the appropriate way to close and recreate the connection or refresh the db connection pool, in a running mormot server?
An other solution is to use db transaction locking for this table.
1. In such a case, should I use AcquireExecution[execOrmWrite].Safe^.Lock; before Begintransaction?
2. calling commit, if I get an exception should I issue a rollback?
Generally which is the safe way to handle a transaction?
Thank you in advance
Many many thanks @ab
I noticed that EnsureRawUtf8 fixes it. I will use it, not to cause trouble.
Today I update the mormot source for a project and I noticed that there is a character issue starting probably with commit 8338979 or one in the following 4-5 commits.
With the last changes I am getting the greek characters in form like ΑιτιολΟγιση Ξ³ΞΉΞ± ΞΌΞ·
The problem I noticed first has to do with Torm.GetJsonValues. Check the following source:
TOrmSoup=class(Torm)
private
Fplanttwo: rawutf8;
Fplantone: rawutf8;
published
property plantone:rawutf8 read Fplantone write Fplantone;
property planttwo:rawutf8 read Fplanttwo write Fplanttwo;
end;
procedure TForm3.Button1Click(Sender: TObject);
var o:tormsoup; s:rawutf8;
begin
o:=tormsoup.Create;
o.plantone:='Κρεμμύδι';
o.planttwo:='πατάτα';
s:=o.GetJsonValues(true,true,ALL_FIELDS);
end;
The result in s is now:
s='{"RowID":0,"plantone":"Ξ'#$9A'Ο'#$81'ΞµΞΌΞΌΟ'#$8D'δι","planttwo":"πατάτα"}'
Using JsontoObject instead of GetJsonValues does not produce this problem.
The reason I am using GetJsonValues (and not JsontoObject) is to have the possibility to select which fields I need to be exported to Json string.
On which compiler?
Can you describe the problem?
Can you state the error message displayed?I can't reproduce the problem here.
I tried with Delphi up to 12.2 with no compiler complain when building the mORMot2Tests project.
Delphi 12.2 and try the following:
procedure TForm3.Button1Click(Sender: TObject);
var a,b,c:array of integer;
begin
setlength(a,2);
setlength(b,3);
c:=concat(a,b);
end;
if mormot.core.base is uses list, it does not compile.
I had to change all to: c:=system.concat(a,b);
RTL concat for arrays has compilation problems with mormot's concat in mormot.core.base
Compile it with mormo1 and use it in mormot2
@ab really thank you....
From a small request, you did a lot of work during the weekend
Really thank you a lot!!!
But Values is read property that can not be assigned
I have a idmaper:Ikeyvalue<Ptrint,Ttreenode> to store Ttreenodes that are already managed for their memory in a Ttreeview.
How can I stop Ikeyvalue from freeing the Ttreenode for this specific idmaper:Ikeyvalue<Ptrint,Ttreenode> instance
trying to change idmaper.Data.Values.Info.info after creating idmaper does not work. And there is no option loNoFinalize as with Ilists
Thank you in advance
Finally with expandfilename I found that c:\windows\system32 is used as root path for services
For the logs, that where the initial problem, the log path provided was not relative, so it should not be caused by the path environment of the windows service. Anyway, I learn a lot for the services from this problem.
I found no solution for the log with Tsynlog.
Finally I used the EchoCustom and nofile=true and all logs are saved now ok in a file with a separate function.
Thank you for the response. My initial though was about that file permissions can produce the problem even with LocalSystem which is similar to administrator account.
But other files are created when running as a service in the same/different directories, the file permissions include account SYSTEM with full access. Even a mormot's function IsDirectoryWritable("directory",[idwTryWinExeFile,idwWriteSomeContent]); returns true.
My delay in response today, is because I found something interesting:
A mormot function like filefromstring('write this for testing',myfile) does not always produce a file when it runs from a service inside a directory named "c\work":
if myfile is 'c:\work\test\test.txt' the file is produced
if myfile is 'test\test.txt' the file is NOT produced, but it returns TRUE
all other functions for 'test\' like directoryexisting, etc, return true, and let you believe everything is ok
I believe windows write somewhere else the files but I can not find the path, c:\windows\system32, c:\windows\syswow64, and other I tested do not include the files
I did not also find a function to check this kind of path and reform it, in order to avoid such a problem
the same executable (tsynAngelize derived class object), when it runs as a windows services it does NOT log anything after service started. The same executable when it is started with -c parameter, it logs everything ok with Tsynlog
the service runs as LocalSystem "account".
it is created as
inherited create(tmyAngelconfig, nil, etcdirnam, config.workdir.ToString, settingspath+'services', config.LogPath, '.conf', 'agl', [fsoDisableSaveIfNeeded]);
with fsas.LogClass.Family do begin
NoFile:=false;
fsas.Log:=[sllWarning, sllError,sllLastError,sllMemory, sllFail, sllException, sllExceptionOS ];
RotateFileDailyAtHour:=0;
RotateFileCount:=10;
AutoFlushTimeOut:=3;
end;
WebSocketLog:=fsas.LogClass;
fsas.LogRotateFileCount:=10;
I expect the same executable to log the same either started as a windows service either as a console application.
Running as a service does not write any log entries to the file. Are they redirected somewhere else?
I have a windows service based on angel project and Tsynagelize
With the following code, after the windows service starts, I have no log entries in the log during the time that the services runs. Tested for hours.
function log2file(const s: rawutf8; const Args: array of const; const deb:boolean=false):boolean;
begin
result:=true;
if not deb then exit;
tsynlog.DoLog(sllCustom4,s,args); end;
With the following function, without any other change in code/configuration, I have log entries from this functions that they have the format of Tsynlog (the appendtofile returns false), even during the windows service runs, after starting/before stopping
function log2file(const s: rawutf8; const Args: array of const; const deb:boolean=false):boolean;
begin
result:=true;
if not deb then exit;
if not AppendToFile(formatutf8(s+#13,args),'agl.log') then tsynlog.DoLog(sllCustom4,s,args);
end;
In both cases the Tsynlog has to send the log entries to agl.log file.
In fact, Start calls SetLog() and therefore follow TSynAngelizeSettings.Log/LogPath/LogRotateFileCount parameters.
If you don't overwrite any settings in those fields, you won't have any logs once started.
With the same code from my part I see a difference between running alg with the -c parameter and /start parameter in windows (compiled with Delphi 12)
When running with the -c parameter as console application that waits the "Enter" to finish, everything is OK
When running with the /start parameter as a windows service then log entries come only from the starting process and stops to
20250113 10272931 ! debug mormot.core.os.TServiceController(02ea5658) Start(agl) Args=0 Handle=17568712
No more log entries from the running service can be found in the log, till I stop the service.
Running as a service does not write any log entries to the file. Are they redirected somewhere else?
Trying to use angelize I noticed that aLog in the constructor is not used anywhere. Do I miss something?
constructor TSynAngelize.Create(aServiceClass: TSynAngelizeServiceClass;
aLog: TSynLogClass; const aSectionName: RawUtf8;
const aWorkFolder, aSettingsFolder, aLogFolder, aSettingsExt, aSettingsName: TFileName;
aSettingsOptions: TSynJsonFileSettingsOptions);
Secondly, when in windows I start the agl with the -c parameter every log entry created with TSynlog.Add exists in the log file. When I started as a windows service with /start parameter, only log entries before starting the services are logged.
Where the logs entries go?
Thanks in advance
One major problem for this excellent work in mormot is that FPC is not so wide used for android and especially for iOS as Delphi does.
I was thinking that probably a .so library can be created in FPC with mormot functions that can be used by Delphi compiled programs or even other native languages. Or even a service that can server a UI program.
Does someone have already implemented something like that? Is there an open project for that available? or an example project?
Thank you in advance
Happy New year and my best wishes for you and your family
Just a question about that:
websocket's client can be used from other threads inside Synchronize/Queue ?
FastMM5 runs in full debug mode without reporting memory corruption or memory leaks
Usually this problem can happen when I am expecting to receive calls from server in the websockets and at the same time I am using the same http websocket client to do calls to the server.
Should I keep a websocket http client just to receive and do all client's calls to the server through an other usual http client?
Concerning compression, clients and server are enabled for compression
In a legacy application I have a mormot2 httpd server in a random port and the application user interface does calls to this server.
Sometimes after multiple requests to this server it happens the following:
When the interface function called in the server the response (before function ends) seems ok:
The client from the above request has the following after the call is finished:
I noticed that the json is somehow different.
After a while (after other calls to the server), everything seems ok.
@ab Any idea, how to check further this problem?
I am using last version from GitHub,
The following can exist also:
Exception: 20241108 20071551 ! EXC EInterfaceFactory {Message:"TInterfacedObjectFakeClient.FakeCall(ImwbService.GetDBormvers) failed: 'Invalid returned JSON content: expects {result:...}, got "} [Main] at 45df37 mormot.core.text.pas ESynException.RaiseUtf8 (9507) fresultcomp.pas Tresultcomp.FormCreate (150) Vcl.Forms.pas TCustomForm.DoCreate (5516) Vcl.Forms.pas TCustomForm.AfterConstruction (5384) System.pas @AfterConstruction (19735) Vcl.Forms.pas TCustomForm.Create (5373) feditdoc.pas Teditdocument.b_protoClick (713) Vcl.Controls.pas TControl.Click (8037) AdvGlowButton.pas TAdvCustomGlowButton.Click (3798) Vcl.Controls.pas TControl.WMLButtonUp (8177) AdvGlowButton.pas TAdvCustomGlowButton.WMLButtonUp (4342) Vcl.Controls.pas TControl.WndProc (7921) Vcl.Controls.pas TWinControl.IsControlMouseMsg (10886) Vcl.Controls.pas TWinControl.WndProc (11156) Vcl.Controls.pas TWinControl.MainWndProc (10823) System.Classes.pas StdWndProc (19092) Vcl.AppEvnts.pas TMultiCaster.GetAppEvents (687) Vcl.Forms.pas TApplication.ProcessMessage (13376) Vcl.Forms.pas TApplication.HandleMessage (13406) Vcl.Forms.pas TApplication.Run (13545)
GetDBormvers is declared as:
function GetDBormvers:rawjson;
An other error I usually find:
Exception: 20241112 17391118 # EXC ENetSock {LastError:"nrClosed",Message:"THttpClientSocket.SockRecv(283) read=0 [Closed - #5]"} [Main] at b2bf7e mormot.net.sock.pas TCrtSocket.SockRecv (5862) mormot.net.client.pas THttpClientSocket.RequestInternal (2408) fastmm5.pas FastMM_GetMem_GetSmallBlock (7186) System.pas @GetMem (4969) System.pas @NewAnsiString (26157) System.pas @LStrSetLength (30045) mormot.net.client.pas THttpClientSocket.Request (2516) mormot.rest.client.pas TRestClientUri.IsOpen (2155) mormot.rest.client.pas TRestClientUri.IsOpen (2227) mormot.rest.http.client.pas TRestHttpClientSocket.InternalRequest (780) mormot.rest.http.client.pas TRestHttpClientGeneric.InternalUri (580) mormot.rest.http.client.pas TRestHttpClientGeneric.InternalUri (582) rest.wsclient.pas TPCHRclient.setJWTheader (278) rest.wsclient.pas TPCHRclient.setJWTheader (279) rest.wsclient.pas TPCHRclient.setJWTheader (280) mormot.rest.client.pas TRestClientUri.OnBackgroundProcess (1980) mormot.rest.client.pas CallInternalUri (2524) mormot.rest.client.pas TRestClientUri.Uri (2556) System.pas TMonitor.TryEnter (20364) System.pas TMonitor.TryEnter (20364) System.Generics.Collections.pas TListHelper.InternalDeleteRange4 (3873) System.Generics.Collections.pas TListHelper.InternalDeleteRange4 (3879) fastmm5.pas FastMM_GetMem_GetSmallBlock (7186) System.pas @GetMem (4969) System.pas @NewAnsiString (26157) mormot.soa.client.pas DoClientCall (643) mormot.soa.client.pas TServiceFactoryClient.InternalInvoke (688) mormot.soa.client.pas TServiceFactoryClient.Invoke (583) mormot.core.interfaces.pas TInterfacedObjectFake.FakeCallGetJsonFromStack (3448) mormot.core.interfaces.pas TInterfacedObjectFake.FakeCallInternalProcess (3544) mormot.core.interfaces.pas TInterfacedObjectFakeRaw.FakeCall (3307)
Is this expected due to network conditions?
I was a bit late to answer because OnClientDisconnected caused the service to hang but with the https://github.com/synopse/mORMot2/issues/312 it works now a week without problems
In the client, I have assigned to TRestHttpClientWebsockets instance the OnWebSocketsUpgraded event before calling WebSocketsUpgrade
in the OnWebSocketsUpgraded event procedure I am getting the server's connection ID for that client: TRestHttpClientWebsockets(sender).WebSockets.WebSockets.ConnectionID and I pass with a call to the server at once together with a unique client ID that my client app has per client.
The server keeps a list of clients and connectionIDs in a IKeyValue directory that it gets from the above pathway and when OnClientDisconnected in the server is fired, it searchs the IKeyValue to find if this connection ID exists.
if so, it pushs a "request" in a TSynThreadPool instance (mormot.core.threads) and exits. I could just remove it from a list but just it takes some time to do some more cleaning work, I do not want the server to wait. I keep also a timestamp to check using the unique client ID, if my client has already reconnected in the meantime, in order not to clear it. Probably the tdatetime should be converted to TTimeLog also.
This thread pool is created for asynchronous task by inheriting from it:
TworkSoul=class
public
work:rawutf8; id:int64; dat:tdatetime;
end;
TmySlavePool=class(TSynThreadPool)
protected
procedure Task(aCaller: TSynThreadPoolWorkThread; aContext: Pointer); override;
procedure TaskAbort(aContext: Pointer); override;
end;
var soulsbox:TmySlavePool;
procedure Tmyserver.WSclientDisconnects(Protocol: TWebSocketProtocol);
var s:tworksoul;
begin
s:=tworksoul.Create;
s.work:='removeclient'; s.id:=protocol.ConnectionID; s.dat:=now;
soulsbox.push(s);
end;
Thank you @ab.
Is it possible to check if a string is utf8 or has invalid characters?
I am getting the following exception in the logs
31/10/2024 10:57:40.832 Exception 8 ESqlDBPostgres {Message:"TSqlDBPostgresLib Exec failed: 22021 [ERROR: invalid byte sequence for encoding \"UTF8\": 0xa2\nCONTEXT: unnamed portal parameter $14\n]",Statement:null} [R1:testdv1testdv0] at 8ccdc6 ../../../../../DG/mORMot2/src/db/mormot.db.raw.postgres.pas (437) ../../../../../DG/mORMot2/src/db/mormot.db.sql.postgres.pas (1015)
I think I managed to arrive to a working solution. Tcpview from microsoft was also real helpful to "close" connections
I have found also this thread: https://synopse.info/forum/viewtopic.php?id=5018
Useful will be to know how ClientRestoreCallbacks work and the automatic re-connection with full callbacks support mentioned here: https://synopse.info/forum/viewtopic.php?id=6066
Thanks you a lot, this really answers to my question.
So probably I should not try to deal with ClientRestoreCallbacks option
I have a lot of clients behind a firewall and I can see one IP for multiple clients. It does not helps
I was thinking to add a custom header for each client, to keep with the callback interface, but I was wondering if there is an other way through mormot framework
Yes, exactly, this the process for a client closing normaly. I am using it. I was wondering if there is a way to identify clients closed abormally
Documentation is more detailed than the example and I have followed the direction to keep an array of the callback interfaces.
Still the problem is how to be notified that a client has been disconnected and the callback interface is invalid without trying to send it a message.
I am not also sure of what to do to keep the connection, except for polling messages.
Thank you a lot for the response.
My main problem is to transform this "Protocol: TWebSocketProtocol" to the callback interface that it is created in the example.
I have found that the callbacks are of type TInterfacedObjectFakeServer are kept in TServiceContainerServer.fFakeCallbacks in the server, but it is much complicated for me with existing knowledge of mormot
And the ClientRestoreCallbacks above can update the connectionID (type TRestConnectionID or THttpServerConnectionID ?) and I am not sure if TOnWebSocketProtocolClosed event should be used
I need more documentation of the idea behind this process
when do we need ClientRestoreCallbacks to have a true value?
I am trying to tune a websocket server to be able to find when a websocket client has closed the connection.
IServiceWithCallbackReleased is ok for clients that close the connection as it should be closed
But when a client looses its connection (due to network or other reasons), the server can not be informed about it, or I am missing how to implemented.
Any ideas? thank you in advance
First time I checked mormot was 5 years ago. The Mormot v1 was a huge investment to start using it. I gave up.
Two years ago, with the 2nd version, I started to read the code and it was really helpful to have different units as it is now.
The documentation is probably the main problem for a new adopter now.
Dividing mormot to different repositories is not going to help more. The increased time it will need, it is better to be invested in more documentation with more examples.
mormot.core.os.security line 1947 and 2056
[dcc32 Error] mormot.core.os.security.pas(1947): E2010 Incompatible types: 'PAnsiChar' and 'PUtf8Char'
Lazarus does not have rtti for records, so you should inform mormot about typeinfo
Check the function: TRttiJson.RegisterFromText
But I am more worried about the fact that Pavel did not send some news from Ukraine since a lot of time.
I believe he is ok. Probably busy with UnityBase
mormot.net.client, line 2232
wraNegotiate:
fOnAuthorize := OnAuthorizeSspi; // as AuthorizeSspiUser()
Gives error in compiling if DOMAINRESTAUTH is not set
thank you a lot @ab
Win10 and I am receiving a RetrieveListJSON output with about 14000 records
How can I make mormot http server to compress the request response?
I am getting this exception but I have not managed to find any problem during runtime:
https://gist.github.com/dkounal/d1a0b1c … ad54746744
The only code that comes from TPCHRclient.setJWTheader is:
245: function TPCHRclient.setJWTheader(Sender: TRestClientUri): boolean; var b:Boolean; st:RawUtf8;
246: begin st:=''; repeat b:=jwl.TryReadLock; if b then try
247: if (Jexp>0) and (Jexp>{UnixTimeUtc}(DateTimeToUnixTime(Now)+jsdif)) then st:=jwth;
248: finally jwl.ReadUnLock; end else Sleep(20); until b;
249: result:=st<>''; if result then sender.SessionHttpHeader:=st; end;
Any contribution is welcome
in case I have a json rawutf8 string (e.g. from a recordsavejson ) when is better to use rawjson and when variant as a parameter type when calling an interface function in a mormot http server?
Thank you a lot @ab.